1 28 package org.jvyamlb; 29 30 import java.io.IOException ; 31 import java.io.OutputStream ; 32 import java.io.BufferedInputStream ; 33 import java.io.FileInputStream ; 34 35 import java.util.HashMap ; 36 import java.util.List ; 37 import java.util.Map ; 38 import java.util.ArrayList ; 39 import java.util.Iterator ; 40 import java.util.Set ; 41 import java.util.TreeSet ; 42 43 import java.util.regex.Pattern ; 44 45 import org.jvyamlb.events.Event; 46 import org.jvyamlb.events.StreamStartEvent; 47 import org.jvyamlb.events.StreamEndEvent; 48 import org.jvyamlb.events.DocumentStartEvent; 49 import org.jvyamlb.events.DocumentEndEvent; 50 import org.jvyamlb.events.CollectionStartEvent; 51 import org.jvyamlb.events.CollectionEndEvent; 52 import org.jvyamlb.events.MappingStartEvent; 53 import org.jvyamlb.events.SequenceStartEvent; 54 import org.jvyamlb.events.MappingEndEvent; 55 import org.jvyamlb.events.SequenceEndEvent; 56 import org.jvyamlb.events.AliasEvent; 57 import org.jvyamlb.events.ScalarEvent; 58 import org.jvyamlb.events.NodeEvent; 59 60 import org.jruby.util.ByteList; 61 62 65 public class EmitterImpl implements Emitter { 66 private static class ScalarAnalysis { 67 public ByteList scalar; 68 public boolean empty; 69 public boolean multiline; 70 public boolean allowFlowPlain; 71 public boolean allowBlockPlain; 72 public boolean allowSingleQuoted; 73 public boolean allowDoubleQuoted; 74 public boolean allowBlock; 75 public ScalarAnalysis(final ByteList scalar, final boolean empty, final boolean multiline, final boolean allowFlowPlain, final boolean allowBlockPlain, final boolean allowSingleQuoted, final boolean allowDoubleQuoted, final boolean allowBlock) { 76 this.scalar = scalar; 77 this.empty = empty; 78 this.multiline = multiline; 79 this.allowFlowPlain = allowFlowPlain; 80 this.allowBlockPlain = allowBlockPlain; 81 this.allowSingleQuoted = allowSingleQuoted; 82 this.allowDoubleQuoted = allowDoubleQuoted; 83 this.allowBlock = allowBlock; 84 } 85 } 86 87 private static interface EmitterState { 88 void expect(final EmitterEnvironment env) throws IOException ; 89 } 90 91 private static final int STREAM_START = 0; 92 private static final int FIRST_DOCUMENT_START = 1; 93 private static final int DOCUMENT_ROOT = 2; 94 private static final int NOTHING = 3; 95 private static final int DOCUMENT_START = 4; 96 private static final int DOCUMENT_END = 5; 97 private static final int FIRST_FLOW_SEQUENCE_ITEM = 6; 98 private static final int FLOW_SEQUENCE_ITEM = 7; 99 private static final int FIRST_FLOW_MAPPING_KEY = 8; 100 private static final int FLOW_MAPPING_SIMPLE_VALUE = 9; 101 private static final int FLOW_MAPPING_VALUE = 10; 102 private static final int FLOW_MAPPING_KEY = 11; 103 private static final int BLOCK_SEQUENCE_ITEM = 12; 104 private static final int FIRST_BLOCK_MAPPING_KEY = 13; 105 private static final int BLOCK_MAPPING_SIMPLE_VALUE = 14; 106 private static final int BLOCK_MAPPING_VALUE = 15; 107 private static final int BLOCK_MAPPING_KEY = 16; 108 private static final int FIRST_BLOCK_SEQUENCE_ITEM = 17; 109 110 private static final EmitterState[] STATES = new EmitterState[18]; 111 static { 112 STATES[STREAM_START] = new EmitterState() { 113 public void expect(final EmitterEnvironment env) { 114 env.expectStreamStart(); 115 } 116 }; 117 STATES[FIRST_DOCUMENT_START] = new EmitterState() { 118 public void expect(final EmitterEnvironment env) throws IOException { 119 env.expectDocumentStart(true); 120 } 121 }; 122 STATES[DOCUMENT_ROOT] = new EmitterState() { 123 public void expect(final EmitterEnvironment env) throws IOException { 124 env.expectDocumentRoot(); 125 } 126 }; 127 STATES[NOTHING] = new EmitterState() { 128 public void expect(final EmitterEnvironment env) { 129 env.expectNothing(); 130 } 131 }; 132 STATES[DOCUMENT_START] = new EmitterState() { 133 public void expect(final EmitterEnvironment env) throws IOException { 134 env.expectDocumentStart(false); 135 } 136 }; 137 STATES[DOCUMENT_END] = new EmitterState() { 138 public void expect(final EmitterEnvironment env) throws IOException { 139 env.expectDocumentEnd(); 140 } 141 }; 142 STATES[FIRST_FLOW_SEQUENCE_ITEM] = new EmitterState() { 143 public void expect(final EmitterEnvironment env) throws IOException { 144 env.expectFirstFlowSequenceItem(); 145 } 146 }; 147 STATES[FLOW_SEQUENCE_ITEM] = new EmitterState() { 148 public void expect(final EmitterEnvironment env) throws IOException { 149 env.expectFlowSequenceItem(); 150 } 151 }; 152 STATES[FIRST_FLOW_MAPPING_KEY] = new EmitterState() { 153 public void expect(final EmitterEnvironment env) throws IOException { 154 env.expectFirstFlowMappingKey(); 155 } 156 }; 157 STATES[FLOW_MAPPING_SIMPLE_VALUE] = new EmitterState() { 158 public void expect(final EmitterEnvironment env) throws IOException { 159 env.expectFlowMappingSimpleValue(); 160 } 161 }; 162 STATES[FLOW_MAPPING_VALUE] = new EmitterState() { 163 public void expect(final EmitterEnvironment env) throws IOException { 164 env.expectFlowMappingValue(); 165 } 166 }; 167 STATES[FLOW_MAPPING_KEY] = new EmitterState() { 168 public void expect(final EmitterEnvironment env) throws IOException { 169 env.expectFlowMappingKey(); 170 } 171 }; 172 STATES[BLOCK_SEQUENCE_ITEM] = new EmitterState() { 173 public void expect(final EmitterEnvironment env) throws IOException { 174 env.expectBlockSequenceItem(false); 175 } 176 }; 177 STATES[FIRST_BLOCK_MAPPING_KEY] = new EmitterState() { 178 public void expect(final EmitterEnvironment env) throws IOException { 179 env.expectFirstBlockMappingKey(); 180 } 181 }; 182 STATES[BLOCK_MAPPING_SIMPLE_VALUE] = new EmitterState() { 183 public void expect(final EmitterEnvironment env) throws IOException { 184 env.expectBlockMappingSimpleValue(); 185 } 186 }; 187 STATES[BLOCK_MAPPING_VALUE] = new EmitterState() { 188 public void expect(final EmitterEnvironment env) throws IOException { 189 env.expectBlockMappingValue(); 190 } 191 }; 192 STATES[BLOCK_MAPPING_KEY] = new EmitterState() { 193 public void expect(final EmitterEnvironment env) throws IOException { 194 env.expectBlockMappingKey(false); 195 } 196 }; 197 STATES[FIRST_BLOCK_SEQUENCE_ITEM] = new EmitterState() { 198 public void expect(final EmitterEnvironment env) throws IOException { 199 env.expectBlockSequenceItem(true); 200 } 201 }; 202 } 203 204 private final static Map DEFAULT_TAG_PREFIXES_1_0; 205 private final static Map DEFAULT_TAG_PREFIXES_1_1; 206 static { 207 final Map defInit0 = new HashMap (); 208 defInit0.put("tag:yaml.org,2002:","!"); 209 DEFAULT_TAG_PREFIXES_1_0 = java.util.Collections.unmodifiableMap(defInit0); 210 final Map defInit = new HashMap (); 211 defInit.put("!","!"); 212 defInit.put("tag:yaml.org,2002:","!!"); 213 DEFAULT_TAG_PREFIXES_1_1 = java.util.Collections.unmodifiableMap(defInit); 214 } 215 216 217 private OutputStream stream; 218 private YAMLConfig options; 219 private EmitterEnvironment env; 220 221 public EmitterImpl(final OutputStream stream, final YAMLConfig opts) { 222 this.stream = stream; 223 this.options = opts; 224 this.env = new EmitterEnvironment(); 225 this.env.emitter = this; 226 this.env.canonical = this.options.canonical(); 227 final int propIndent = this.options.indent(); 228 if(propIndent>=2 && propIndent<10) { 229 this.env.bestIndent = propIndent; 230 } 231 final int propWidth = this.options.bestWidth(); 232 if(propWidth != 0 && propWidth > (this.env.bestIndent*2)) { 233 this.env.bestWidth = propWidth; 234 } 235 } 236 237 public YAMLConfig getOptions() { 238 return options; 239 } 240 241 public void emit(final Event event) throws IOException { 242 this.env.events.add(event); 243 while(!this.env.needMoreEvents()) { 244 this.env.event = (Event)this.env.events.remove(0); 245 STATES[this.env.state].expect(env); 246 this.env.event = null; 247 } 248 } 249 250 private static class EmitterEnvironment { 251 public List states = new ArrayList (); 252 public int state = STREAM_START; 253 public List events = new ArrayList (); 254 public Event event; 255 public int flowLevel = 0; 256 public List indents = new ArrayList (); 257 public int indent = -1; 258 public boolean rootContext = false; 259 public boolean sequenceContext = false; 260 public boolean mappingContext = false; 261 public boolean simpleKeyContext = false; 262 263 public int line = 0; 264 public int column = 0; 265 public boolean whitespace = true; 266 public boolean indentation = true; 267 268 public boolean canonical = false; 269 public int bestIndent = 2; 270 public int bestWidth = 80; 271 272 public ByteList bestLinebreak = ByteList.create("\n"); 273 274 public Map tagPrefixes; 275 276 public String preparedAnchor; 277 public String preparedTag; 278 279 public ScalarAnalysis analysis; 280 public char style = 0; 281 282 public EmitterImpl emitter; 283 284 public boolean isVersion10 = false; 285 286 public boolean needMoreEvents() { 287 if(events.isEmpty()) { 288 return true; 289 } 290 event = (Event)events.get(0); 291 if(event instanceof DocumentStartEvent) { 292 return needEvents(1); 293 } else if(event instanceof SequenceStartEvent) { 294 return needEvents(2); 295 } else if(event instanceof MappingStartEvent) { 296 return needEvents(3); 297 } else { 298 return false; 299 } 300 } 301 302 private boolean needEvents(final int count) { 303 int level = 0; 304 final Iterator iter = events.iterator(); 305 iter.next(); 306 for(;iter.hasNext();) { 307 final Object curr = iter.next(); 308 if(curr instanceof DocumentStartEvent || curr instanceof CollectionStartEvent) { 309 level++; 310 } else if(curr instanceof DocumentEndEvent || curr instanceof CollectionEndEvent) { 311 level--; 312 } else if(curr instanceof StreamEndEvent) { 313 level = -1; 314 } 315 if(level<0) { 316 return false; 317 } 318 } 319 return events.size() < count+1; 320 } 321 322 private void increaseIndent(final boolean flow, final boolean indentless) { 323 indents.add(0,new Integer (indent)); 324 if(indent == -1) { 325 if(flow) { 326 indent = bestIndent; 327 } else { 328 indent = 0; 329 } 330 } else if(!indentless) { 331 indent += bestIndent; 332 } 333 } 334 335 public void expectStreamStart() { 336 if(this.event instanceof StreamStartEvent) { 337 emitter.writeStreamStart(); 338 this.state = FIRST_DOCUMENT_START; 339 } else { 340 throw new EmitterException("expected StreamStartEvent, but got " + this.event); 341 } 342 } 343 344 public void expectNothing() { 345 throw new EmitterException("expecting nothing, but got " + this.event); 346 } 347 348 public void expectDocumentStart(final boolean first) throws IOException { 349 if(event instanceof DocumentStartEvent) { 350 final DocumentStartEvent ev = (DocumentStartEvent)event; 351 if(first) { 352 if(null != ev.getVersion()) { 353 emitter.writeVersionDirective(prepareVersion(ev.getVersion())); 354 } 355 356 if((null != ev.getVersion() && ev.getVersion()[1] == 0) || emitter.getOptions().version().equals("1.0")) { 357 isVersion10 = true; 358 tagPrefixes = new HashMap (DEFAULT_TAG_PREFIXES_1_0); 359 } else { 360 tagPrefixes = new HashMap (DEFAULT_TAG_PREFIXES_1_1); 361 } 362 363 if(null != ev.getTags()) { 364 final Set handles = new TreeSet (); 365 handles.addAll(ev.getTags().keySet()); 366 for(final Iterator iter = handles.iterator();iter.hasNext();) { 367 final String handle = (String )iter.next(); 368 final String prefix = (String )ev.getTags().get(handle); 369 tagPrefixes.put(prefix,handle); 370 final String handleText = prepareTagHandle(handle); 371 final String prefixText = prepareTagPrefix(prefix); 372 emitter.writeTagDirective(handleText,prefixText); 373 } 374 } 375 } 376 377 final boolean implicit = first && !ev.getExplicit() && !canonical && ev.getVersion() == null && ev.getTags() == null && !checkEmptyDocument(); 378 if(!implicit) { 379 emitter.writeIndent(); 380 emitter.writeIndicator(ByteList.create("--- "),true,true,false); 381 if(canonical) { 382 emitter.writeIndent(); 383 } 384 } 385 state = DOCUMENT_ROOT; 386 } else if(event instanceof StreamEndEvent) { 387 emitter.writeStreamEnd(); 388 state = NOTHING; 389 } else { 390 throw new EmitterException("expected DocumentStartEvent, but got " + event); 391 } 392 } 393 394 public void expectDocumentRoot() throws IOException { 395 states.add(0,new Integer (DOCUMENT_END)); 396 expectNode(true,false,false,false); 397 } 398 399 public void expectDocumentEnd() throws IOException { 400 if(event instanceof DocumentEndEvent) { 401 emitter.writeIndent(); 402 if(((DocumentEndEvent)event).getExplicit()) { 403 emitter.writeIndicator(ByteList.create("..."),true,false,false); 404 emitter.writeIndent(); 405 } 406 emitter.flushStream(); 407 state = DOCUMENT_START; 408 } else { 409 throw new EmitterException("expected DocumentEndEvent, but got " + event); 410 } 411 } 412 413 public void expectFirstFlowSequenceItem() throws IOException { 414 if(event instanceof SequenceEndEvent) { 415 indent = ((Integer )indents.remove(0)).intValue(); 416 flowLevel--; 417 emitter.writeIndicator(ByteList.create("]"),false,false,false); 418 state = ((Integer )states.remove(0)).intValue(); 419 } else { 420 if(canonical || column > bestWidth) { 421 emitter.writeIndent(); 422 } 423 states.add(0,new Integer (FLOW_SEQUENCE_ITEM)); 424 expectNode(false,true,false,false); 425 } 426 } 427 428 public void expectFlowSequenceItem() throws IOException { 429 if(event instanceof SequenceEndEvent) { 430 indent = ((Integer )indents.remove(0)).intValue(); 431 flowLevel--; 432 if(canonical) { 433 emitter.writeIndicator(ByteList.create(","),false,false,false); 434 emitter.writeIndent(); 435 } 436 emitter.writeIndicator(ByteList.create("]"),false,false,false); 437 state = ((Integer )states.remove(0)).intValue(); 438 } else { 439 emitter.writeIndicator(ByteList.create(","),false,false,false); 440 if(canonical || column > bestWidth) { 441 emitter.writeIndent(); 442 } 443 states.add(0,new Integer (FLOW_SEQUENCE_ITEM)); 444 expectNode(false,true,false,false); 445 } 446 } 447 448 public void expectFirstFlowMappingKey() throws IOException { 449 if(event instanceof MappingEndEvent) { 450 indent = ((Integer )indents.remove(0)).intValue(); 451 flowLevel--; 452 emitter.writeIndicator(ByteList.create("}"),false,false,false); 453 state = ((Integer )states.remove(0)).intValue(); 454 } else { 455 if(canonical || column > bestWidth) { 456 emitter.writeIndent(); 457 } 458 if(!canonical && checkSimpleKey()) { 459 states.add(0,new Integer (FLOW_MAPPING_SIMPLE_VALUE)); 460 expectNode(false,false,true,true); 461 } else { 462 emitter.writeIndicator(ByteList.create("?"),true,false,false); 463 states.add(0,new Integer (FLOW_MAPPING_VALUE)); 464 expectNode(false,false,true,false); 465 } 466 } 467 } 468 469 public void expectFlowMappingSimpleValue() throws IOException { 470 emitter.writeIndicator(ByteList.create(": "),false,true,false); 471 states.add(0,new Integer (FLOW_MAPPING_KEY)); 472 expectNode(false,false,true,false); 473 } 474 475 public void expectFlowMappingValue() throws IOException { 476 if(canonical || column > bestWidth) { 477 emitter.writeIndent(); 478 } 479 emitter.writeIndicator(ByteList.create(": "),false,true,false); 480 states.add(0,new Integer (FLOW_MAPPING_KEY)); 481 expectNode(false,false,true,false); 482 } 483 484 public void expectFlowMappingKey() throws IOException { 485 if(event instanceof MappingEndEvent) { 486 indent = ((Integer )indents.remove(0)).intValue(); 487 flowLevel--; 488 if(canonical) { 489 emitter.writeIndicator(ByteList.create(","),false,false,false); 490 emitter.writeIndent(); 491 } 492 emitter.writeIndicator(ByteList.create("}"),false,false,false); 493 state = ((Integer )states.remove(0)).intValue(); 494 } else { 495 emitter.writeIndicator(ByteList.create(","),false,false,false); 496 if(canonical || column > bestWidth) { 497 emitter.writeIndent(); 498 } 499 if(!canonical && checkSimpleKey()) { 500 states.add(0,new Integer (FLOW_MAPPING_SIMPLE_VALUE)); 501 expectNode(false,false,true,true); 502 } else { 503 emitter.writeIndicator(ByteList.create("?"),true,false,false); 504 states.add(0,new Integer (FLOW_MAPPING_VALUE)); 505 expectNode(false,false,true,false); 506 } 507 } 508 } 509 510 public void expectBlockSequenceItem(final boolean first) throws IOException { 511 if(!first && event instanceof SequenceEndEvent) { 512 indent = ((Integer )indents.remove(0)).intValue(); 513 state = ((Integer )states.remove(0)).intValue(); 514 } else { 515 emitter.writeIndent(); 516 emitter.writeIndicator(ByteList.create("-"),true,false,true); 517 states.add(0,new Integer (BLOCK_SEQUENCE_ITEM)); 518 expectNode(false,true,false,false); 519 } 520 } 521 522 public void expectFirstBlockMappingKey() throws IOException { 523 expectBlockMappingKey(true); 524 } 525 526 public void expectBlockMappingSimpleValue() throws IOException { 527 emitter.writeIndicator(ByteList.create(": "),false,true,false); 528 states.add(0,new Integer (BLOCK_MAPPING_KEY)); 529 expectNode(false,false,true,false); 530 } 531 532 public void expectBlockMappingValue() throws IOException { 533 emitter.writeIndent(); 534 emitter.writeIndicator(ByteList.create(": "),true,true,true); 535 states.add(0,new Integer (BLOCK_MAPPING_KEY)); 536 expectNode(false,false,true,false); 537 } 538 539 public void expectBlockMappingKey(final boolean first) throws IOException { 540 if(!first && event instanceof MappingEndEvent) { 541 indent = ((Integer )indents.remove(0)).intValue(); 542 state = ((Integer )states.remove(0)).intValue(); 543 } else { 544 emitter.writeIndent(); 545 if(checkSimpleKey()) { 546 states.add(0,new Integer (BLOCK_MAPPING_SIMPLE_VALUE)); 547 expectNode(false,false,true,true); 548 } else { 549 emitter.writeIndicator(ByteList.create("?"),true,false,true); 550 states.add(0,new Integer (BLOCK_MAPPING_VALUE)); 551 expectNode(false,false,true,false); 552 } 553 } 554 } 555 556 private void expectNode(final boolean root, final boolean sequence, final boolean mapping, final boolean simpleKey) throws IOException { 557 rootContext = root; 558 sequenceContext = sequence; 559 mappingContext = mapping; 560 simpleKeyContext = simpleKey; 561 if(event instanceof AliasEvent) { 562 expectAlias(); 563 } else if(event instanceof ScalarEvent || event instanceof CollectionStartEvent) { 564 processAnchor(ByteList.create("&")); 565 processTag(); 566 if(event instanceof ScalarEvent) { 567 expectScalar(); 568 } else if(event instanceof SequenceStartEvent) { 569 if(flowLevel != 0 || canonical || ((SequenceStartEvent)event).getFlowStyle() || checkEmptySequence()) { 570 expectFlowSequence(); 571 } else { 572 expectBlockSequence(); 573 } 574 } else if(event instanceof MappingStartEvent) { 575 if(flowLevel != 0 || canonical || ((MappingStartEvent)event).getFlowStyle() || checkEmptyMapping()) { 576 expectFlowMapping(); 577 } else { 578 expectBlockMapping(); 579 } 580 } 581 } else { 582 throw new EmitterException("expected NodeEvent, but got " + event); 583 } 584 } 585 586 private void expectAlias() throws IOException { 587 if(((NodeEvent)event).getAnchor() == null) { 588 throw new EmitterException("anchor is not specified for alias"); 589 } 590 processAnchor(ByteList.create("*")); 591 state = ((Integer )states.remove(0)).intValue(); 592 } 593 594 private void expectScalar() throws IOException { 595 increaseIndent(true,false); 596 processScalar(); 597 indent = ((Integer )indents.remove(0)).intValue(); 598 state = ((Integer )states.remove(0)).intValue(); 599 } 600 601 private void expectFlowSequence() throws IOException { 602 emitter.writeIndicator(ByteList.create("["),true,true,false); 603 flowLevel++; 604 increaseIndent(true,false); 605 state = FIRST_FLOW_SEQUENCE_ITEM; 606 } 607 608 private void expectBlockSequence() throws IOException { 609 increaseIndent(false, mappingContext && !indentation); 610 state = FIRST_BLOCK_SEQUENCE_ITEM; 611 } 612 613 private void expectFlowMapping() throws IOException { 614 emitter.writeIndicator(ByteList.create("{"),true,true,false); 615 flowLevel++; 616 increaseIndent(true,false); 617 state = FIRST_FLOW_MAPPING_KEY; 618 } 619 620 private void expectBlockMapping() throws IOException { 621 increaseIndent(false,false); 622 state = FIRST_BLOCK_MAPPING_KEY; 623 } 624 625 private boolean checkEmptySequence() { 626 return event instanceof SequenceStartEvent && !events.isEmpty() && events.get(0) instanceof SequenceEndEvent; 627 } 628 629 private boolean checkEmptyMapping() { 630 return event instanceof MappingStartEvent && !events.isEmpty() && events.get(0) instanceof MappingEndEvent; 631 } 632 633 private boolean checkEmptyDocument() { 634 if(!(event instanceof DocumentStartEvent) || events.isEmpty()) { 635 return false; 636 } 637 final Event ev = (Event)events.get(0); 638 return ev instanceof ScalarEvent && ((ScalarEvent)ev).getAnchor() == null && ((ScalarEvent)ev).getTag() == null && ((ScalarEvent)ev).getImplicit() != null && ((ScalarEvent)ev).getValue().realSize == 0; 639 } 640 641 private boolean checkSimpleKey() { 642 int length = 0; 643 if(event instanceof NodeEvent && null != ((NodeEvent)event).getAnchor()) { 644 if(null == preparedAnchor) { 645 preparedAnchor = prepareAnchor(((NodeEvent)event).getAnchor()); 646 } 647 length += preparedAnchor.length(); 648 } 649 String tag = null; 650 if(event instanceof ScalarEvent) { 651 tag = ((ScalarEvent)event).getTag(); 652 } else if(event instanceof CollectionStartEvent) { 653 tag = ((CollectionStartEvent)event).getTag(); 654 } 655 if(tag != null) { 656 if(null == preparedTag) { 657 preparedTag = emitter.prepareTag(tag); 658 } 659 length += preparedTag.length(); 660 } 661 if(event instanceof ScalarEvent) { 662 if(null == analysis) { 663 analysis = analyzeScalar(((ScalarEvent)event).getValue()); 664 length += analysis.scalar.length(); 665 } 666 } 667 668 return (length < 128 && (event instanceof AliasEvent || (event instanceof ScalarEvent && !analysis.empty && !analysis.multiline) || checkEmptySequence() || checkEmptyMapping())); 669 } 670 671 private void processAnchor(final ByteList indicator) throws IOException { 672 final NodeEvent ev = (NodeEvent)event; 673 if(null == ev.getAnchor()) { 674 preparedAnchor = null; 675 return; 676 } 677 if(null == preparedAnchor) { 678 preparedAnchor = prepareAnchor(ev.getAnchor()); 679 } 680 if(preparedAnchor != null && !"".equals(preparedAnchor)) { 681 indicator.append(preparedAnchor.getBytes()); 682 emitter.writeIndicator(indicator,true,false,false); 683 } 684 preparedAnchor = null; 685 } 686 687 private void processTag() throws IOException { 688 String tag = null; 689 if(event instanceof ScalarEvent) { 690 final ScalarEvent ev = (ScalarEvent)event; 691 tag = ev.getTag(); 692 if(style == 0) { 693 style = chooseScalarStyle(); 694 } 695 if(((!canonical || tag == null) && ((0 == style && ev.getImplicit()[0]) || (0 != style && ev.getImplicit()[1])))) { 696 preparedTag = null; 697 return; 698 } 699 if(ev.getImplicit()[0] && null == tag) { 700 tag = "!"; 701 preparedTag = null; 702 } 703 } else { 704 final CollectionStartEvent ev = (CollectionStartEvent)event; 705 tag = ev.getTag(); 706 if((!canonical || tag == null) && ev.getImplicit()) { 707 preparedTag = null; 708 return; 709 } 710 indentation = true; 711 } 712 if(tag == null) { 713 throw new EmitterException("tag is not specified"); 714 } 715 if(null == preparedTag) { 716 preparedTag = emitter.prepareTag(tag); 717 } 718 if(preparedTag != null && !"".equals(preparedTag)) { 719 emitter.writeIndicator(ByteList.create(preparedTag),true,false,true); 720 } 721 preparedTag = null; 722 } 723 724 private char chooseScalarStyle() { 725 final ScalarEvent ev = (ScalarEvent)event; 726 727 if(null == analysis) { 728 analysis = analyzeScalar(ev.getValue()); 729 } 730 731 if(ev.getStyle() == '"' || this.canonical) { 732 return '"'; 733 } 734 735 if(ev.getStyle() == 0) { 737 if(!(simpleKeyContext && (analysis.empty || analysis.multiline)) && ((flowLevel != 0 && analysis.allowFlowPlain) || (flowLevel == 0 && analysis.allowBlockPlain))) { 738 return 0; 739 } 740 } 741 if(ev.getStyle() == 0 && ev.getImplicit()[0] && (!(simpleKeyContext && (analysis.empty || analysis.multiline)) && (flowLevel!=0 && analysis.allowFlowPlain || (flowLevel == 0 && analysis.allowBlockPlain)))) { 742 return 0; 743 } 744 if((ev.getStyle() == '|' || ev.getStyle() == '>') && flowLevel == 0 && analysis.allowBlock) { 745 return '\''; 746 } 747 if((ev.getStyle() == 0 || ev.getStyle() == '\'') && (analysis.allowSingleQuoted && !(simpleKeyContext && analysis.multiline))) { 748 return '\''; 749 } 750 return '"'; 751 } 752 753 private void processScalar() throws IOException { 754 final ScalarEvent ev = (ScalarEvent)event; 755 756 if(null == analysis) { 757 analysis = analyzeScalar(ev.getValue()); 758 } 759 if(0 == style) { 760 style = chooseScalarStyle(); 761 } 762 final boolean split = !simpleKeyContext; 763 if(style == '"') { 764 emitter.writeDoubleQuoted(analysis.scalar,split); 765 } else if(style == '\'') { 766 emitter.writeSingleQuoted(analysis.scalar,split); 767 } else if(style == '>') { 768 emitter.writeFolded(analysis.scalar); 769 } else if(style == '|') { 770 emitter.writeLiteral(analysis.scalar); 771 } else { 772 emitter.writePlain(analysis.scalar,split); 773 } 774 analysis = null; 775 style = 0; 776 } 777 } 778 779 void writeStreamStart() { 780 } 781 782 void writeStreamEnd() throws IOException { 783 flushStream(); 784 } 785 786 void writeIndicator(final ByteList indicator, final boolean needWhitespace, final boolean whitespace, final boolean indentation) throws IOException { 787 ByteList data = indicator; 788 if(!(env.whitespace || !needWhitespace)) { 789 data.prepend((byte)' '); 790 } 791 env.whitespace = whitespace; 792 env.indentation = env.indentation && indentation; 793 env.column += data.length(); 794 stream.write(data.bytes,0,data.realSize); 795 } 796 797 void writeIndent() throws IOException { 798 int indent = 0; 799 if(env.indent != -1) { 800 indent = env.indent; 801 } 802 803 if(!env.indentation || env.column > indent || (env.column == indent && !env.whitespace)) { 804 writeLineBreak(null); 805 } 806 807 if(env.column < indent) { 808 env.whitespace = true; 809 final ByteList data = new ByteList(); 810 for(int i=0,j=(indent-env.column);i<j;i++) { 811 data.append((byte)' '); 812 } 813 env.column = indent; 814 stream.write(data.bytes,0,data.realSize); 815 } 816 } 817 818 void writeVersionDirective(final String version_text) throws IOException { 819 stream.write(("%YAML " + version_text).getBytes()); 820 writeLineBreak(null); 821 } 822 823 void writeTagDirective(final String handle, final String prefix) throws IOException { 824 stream.write(("%TAG " + handle + " " + prefix).getBytes()); 825 writeLineBreak(null); 826 } 827 828 void writeDoubleQuoted(final ByteList text, final boolean split) throws IOException { 829 writeIndicator(ByteList.create("\""),true,false,false); 830 int start = 0; 831 int ending = 0; 832 ByteList data = null; 833 while(ending <= text.length()) { 834 char ch = 0; 835 if(ending < text.length()) { 836 ch = text.charAt(ending); 837 } 838 if(ch==0 || "\"\\\u0085".indexOf(ch) != -1 || !('\u0020' <= ch && ch <= '\u007E')) { 839 if(start < ending) { 840 data = (ByteList)text.subSequence(start,ending); 841 env.column+=data.length(); 842 stream.write(data.bytes,0,data.realSize); 843 start = ending; 844 } 845 if(ch != 0) { 846 if(YAML.ESCAPE_REPLACEMENTS.containsKey(new Character (ch))) { 847 data = ByteList.create("\\" + YAML.ESCAPE_REPLACEMENTS.get(new Character (ch))); 848 } else if(ch <= '\u00FF') { 849 String str = Integer.toString(ch,16); 850 if(str.length() == 1) { 851 str = "0" + str; 852 } 853 data = ByteList.create("\\x" + str); 854 } 855 env.column += data.length(); 856 stream.write(data.bytes,0,data.realSize); 857 start = ending+1; 858 } 859 } 860 if((0 < ending && ending < (text.length()-1)) && (ch == ' ' || start >= ending) && (env.column+(ending-start)) > env.bestWidth && split) { 861 if(start < ending) { 862 data = (ByteList)text.subSequence(start,ending); 863 data.append('\\'); 864 } else { 865 data = ByteList.create("\\"); 866 } 867 868 if(start < ending) { 869 start = ending; 870 } 871 env.column += data.length(); 872 stream.write(data.bytes,0,data.realSize); 873 writeIndent(); 874 env.whitespace = false; 875 env.indentation = false; 876 if(text.charAt(start) == ' ') { 877 data = ByteList.create("\\"); 878 env.column += data.length(); 879 stream.write(data.bytes,0,data.realSize); 880 } 881 } 882 ending += 1; 883 } 884 885 writeIndicator(ByteList.create("\""),false,false,false); 886 } 887 888 void writeSingleQuoted(final ByteList text, final boolean split) throws IOException { 889 writeIndicator(ByteList.create("'"),true,false,false); 890 boolean spaces = false; 891 boolean breaks = false; 892 int start=0,ending=0; 893 char ceh = 0; 894 ByteList data = null; 895 while(ending <= text.length()) { 896 ceh = 0; 897 if(ending < text.length()) { 898 ceh = text.charAt(ending); 899 } 900 if(spaces) { 901 if(ceh == 0 || ceh != 32) { 902 if(start+1 == ending && env.column > env.bestWidth && split && start != 0 && ending != text.length()) { 903 writeIndent(); 904 } else { 905 data = (ByteList)text.subSequence(start,ending); 906 env.column += data.length(); 907 stream.write(data.bytes,0,data.realSize); 908 } 909 start = ending; 910 } 911 } else if(breaks) { 912 if(ceh == 0 || !('\n' == ceh || '\u0085' == ceh)) { 913 data = (ByteList)text.subSequence(start,ending); 914 for(int i=0,j=data.length();i<j;i++) { 915 char cha = data.charAt(i); 916 if('\n' == cha) { 917 writeLineBreak(null); 918 } else { 919 writeLineBreak(ByteList.create(""+cha)); 920 } 921 } 922 writeIndent(); 923 start = ending; 924 } 925 } else { 926 if(ceh == 0 || !('\n' == ceh || '\u0085' == ceh)) { 927 if(start < ending) { 928 data = (ByteList)text.subSequence(start,ending); 929 env.column += data.length(); 930 stream.write(data.bytes,0,data.realSize); 931 start = ending; 932 } 933 if(ceh == '\'') { 934 data = ByteList.create("''"); 935 env.column += 2; 936 stream.write(data.bytes,0,data.realSize); 937 start = ending + 1; 938 } 939 } 940 } 941 if(ceh != 0) { 942 spaces = ceh == ' '; 943 breaks = ceh == '\n' || ceh == '\u0085'; 944 } 945 ending++; 946 } 947 writeIndicator(ByteList.create("'"),false,false,false); 948 } 949 950 void writeFolded(final ByteList text) throws IOException { 951 String chomp = determineChomp(text); 952 writeIndicator(ByteList.create(">" + chomp), true, false, false); 953 writeIndent(); 954 boolean leadingSpace = false; 955 boolean spaces = false; 956 boolean breaks = false; 957 int start=0,ending=0; 958 ByteList data = null; 959 while(ending <= text.length()) { 960 char ceh = 0; 961 if(ending < text.length()) { 962 ceh = text.charAt(ending); 963 } 964 if(breaks) { 965 if(ceh == 0 || !('\n' == ceh || '\u0085' == ceh)) { 966 if(!leadingSpace && ceh != 0 && ceh != ' ' && text.charAt(start) == '\n') { 967 writeLineBreak(null); 968 } 969 leadingSpace = ceh == ' '; 970 data = (ByteList)text.subSequence(start,ending); 971 for(int i=0,j=data.length();i<j;i++) { 972 char cha = data.charAt(i); 973 if('\n' == cha) { 974 writeLineBreak(null); 975 } else { 976 writeLineBreak(ByteList.create(""+cha)); 977 } 978 } 979 if(ceh != 0) { 980 writeIndent(); 981 } 982 start = ending; 983 } 984 } else if(spaces) { 985 if(ceh != ' ') { 986 if(start+1 == ending && env.column > env.bestWidth) { 987 writeIndent(); 988 } else { 989 data = (ByteList)text.subSequence(start,ending); 990 env.column += data.length(); 991 stream.write(data.bytes,0,data.realSize); 992 } 993 start = ending; 994 } 995 } else { 996 if(ceh == 0 || ' ' == ceh || '\n' == ceh || '\u0085' == ceh) { 997 data = (ByteList)text.subSequence(start,ending); 998 stream.write(data.bytes,0,data.realSize); 999 if(ceh == 0) { 1000 writeLineBreak(null); 1001 } 1002 start = ending; 1003 } 1004 } 1005 if(ceh != 0) { 1006 breaks = '\n' == ceh || '\u0085' == ceh; 1007 spaces = ceh == ' '; 1008 } 1009 ending++; 1010 } 1011 } 1012 1013 void writeLiteral(final ByteList text) throws IOException { 1014 String chomp = determineChomp(text); 1015 writeIndicator(ByteList.create("|" + chomp), true, false, false); 1016 writeIndent(); 1017 boolean breaks = false; 1018 int start=0,ending=0; 1019 ByteList data = null; 1020 while(ending <= text.length()) { 1021 char ceh = 0; 1022 if(ending < text.length()) { 1023 ceh = text.charAt(ending); 1024 } 1025 if(breaks) { 1026 if(ceh == 0 || !('\n' == ceh || '\u0085' == ceh)) { 1027 data = (ByteList)text.subSequence(start,ending); 1028 for(int i=0,j=data.length();i<j;i++) { 1029 char cha = data.charAt(i); 1030 if('\n' == cha) { 1031 writeLineBreak(null); 1032 } else { 1033 writeLineBreak(ByteList.create(""+cha)); 1034 } 1035 } 1036 if(ceh != 0) { 1037 writeIndent(); 1038 } 1039 start = ending; 1040 } 1041 } else { 1042 if(ceh == 0 || '\n' == ceh || '\u0085' == ceh) { 1043 data = (ByteList)text.subSequence(start,ending); 1044 stream.write(data.bytes,0,data.realSize); 1045 if(ceh == 0) { 1046 writeLineBreak(null); 1047 } 1048 start = ending; 1049 } 1050 } 1051 if(ceh != 0) { 1052 breaks = '\n' == ceh || '\u0085' == ceh; 1053 } 1054 ending++; 1055 } 1056 } 1057 1058 void writePlain(final ByteList text, final boolean split) throws IOException { 1059 if(text == null || text.realSize == 0) { 1060 return; 1061 } 1062 ByteList data = null; 1063 if(!env.whitespace) { 1064 env.column += 1; 1065 stream.write(32); } 1067 env.whitespace = false; 1068 env.indentation = false; 1069 boolean spaces=false, breaks = false; 1070 int start=0,ending=0; 1071 while(ending <= text.length()) { 1072 char ceh = 0; 1073 if(ending < text.length()) { 1074 ceh = (char)(text.bytes[ending] & 0xFF); 1075 } 1076 if(spaces) { 1077 if(ceh != ' ') { 1078 if(start+1 == ending && env.column > env.bestWidth && split) { 1079 writeIndent(); 1080 env.whitespace = false; 1081 env.indentation = false; 1082 } else { 1083 data = new ByteList(text, start, ending-start); 1084 env.column += data.length(); 1085 stream.write(data.bytes,0,data.realSize); 1086 } 1087 start = ending; 1088 } 1089 } else if(breaks) { 1090 if(ceh != '\n' && ceh != '\u0085') { 1091 if((text.bytes[start] & 0xFF) == '\n') { 1092 writeLineBreak(null); 1093 } 1094 data = new ByteList(text, start, ending-start); 1095 for(int i=0,j=data.length();i<j;i++) { 1096 char cha = (char)(data.bytes[i]&0xFF); 1097 if('\n' == cha) { 1098 writeLineBreak(null); 1099 } else { 1100 writeLineBreak(ByteList.create(""+cha)); 1101 } 1102 } 1103 writeIndent(); 1104 env.whitespace = false; 1105 env.indentation = false; 1106 start = ending; 1107 } 1108 } else { 1109 if(ceh == 0 || ' ' == ceh || '\n' == ceh || '\u0085' == ceh) { 1110 data = new ByteList(text, start, ending-start); 1111 env.column += data.length(); 1112 stream.write(data.bytes,0,data.realSize); 1113 start = ending; 1114 } 1115 } 1116 if(ceh != 0) { 1117 spaces = ceh == ' '; 1118 breaks = ceh == '\n' || ceh == '\u0085'; 1119 } 1120 ending++; 1121 } 1122 } 1123 1124 void writeLineBreak(final ByteList data) throws IOException { 1125 ByteList xdata = data; 1126 if(xdata == null) { 1127 xdata = env.bestLinebreak; 1128 } 1129 env.whitespace = true; 1130 env.indentation = true; 1131 env.line++; 1132 env.column = 0; 1133 stream.write(xdata.bytes,0,xdata.realSize); 1134 } 1135 1136 void flushStream() throws IOException { 1137 stream.flush(); 1138 } 1139 1140 static String prepareVersion(final int[] version) { 1141 if(version[0] != 1) { 1142 throw new EmitterException("unsupported YAML version: " + version[0] + "." + version[1]); 1143 } 1144 return ""+version[0] + "." + version[1]; 1145 } 1146 private final static Pattern HANDLE_FORMAT = Pattern.compile("^![-\\w]*!$"); 1147 static String prepareTagHandle(final String handle) { 1148 if(handle == null || "".equals(handle)) { 1149 throw new EmitterException("tag handle must not be empty"); 1150 } else if(handle.charAt(0) != '!' || handle.charAt(handle.length()-1) != '!') { 1151 throw new EmitterException("tag handle must start and end with '!': " + handle); 1152 } else if(!"!".equals(handle) && !HANDLE_FORMAT.matcher(handle).matches()) { 1153 throw new EmitterException("invalid syntax for tag handle: " + handle); 1154 } 1155 return handle; 1156 } 1157 1158 static String prepareTagPrefix(final String prefix) { 1159 if(prefix == null || "".equals(prefix)) { 1160 throw new EmitterException("tag prefix must not be empty"); 1161 } 1162 final StringBuffer chunks = new StringBuffer (); 1163 int start=0,ending=0; 1164 if(prefix.charAt(0) == '!') { 1165 ending = 1; 1166 } 1167 while(ending < prefix.length()) { 1168 ending++; 1169 } 1170 if(start < ending) { 1171 chunks.append(prefix.substring(start,ending)); 1172 } 1173 return chunks.toString(); 1174 } 1175 1176 private final static Pattern ANCHOR_FORMAT = Pattern.compile("^[-\\w]*$"); 1177 static String prepareAnchor(final String anchor) { 1178 if(anchor == null || "".equals(anchor)) { 1179 throw new EmitterException("anchor must not be empty"); 1180 } 1181 if(!ANCHOR_FORMAT.matcher(anchor).matches()) { 1182 throw new EmitterException("invalid syntax for anchor: " + anchor); 1183 } 1184 return anchor; 1185 } 1186 1187 String prepareTag(final String tag) { 1188 if(tag == null || "".equals(tag)) { 1189 throw new EmitterException("tag must not be empty"); 1190 } 1191 if(tag.equals("!")) { 1192 return tag; 1193 } 1194 String handle = null; 1195 String suffix = tag; 1196 for(final Iterator iter = env.tagPrefixes.keySet().iterator();iter.hasNext();) { 1197 String prefix = (String )iter.next(); 1198 if(Pattern.matches("^" + prefix + ".+$", tag) && (prefix.equals("!") || prefix.length() < tag.length())) { 1199 handle = (String )env.tagPrefixes.get(prefix); 1200 suffix = tag.substring(prefix.length()); 1201 } 1202 } 1203 final StringBuffer chunks = new StringBuffer (); 1204 int start=0,ending=0; 1205 while(ending < suffix.length()) { 1206 ending++; 1207 } 1208 if(start < ending) { 1209 chunks.append(suffix.substring(start,ending)); 1210 } 1211 String suffixText = chunks.toString(); 1212 if(tag.charAt(0) == '!' && env.isVersion10) { 1213 return tag; 1214 } 1215 if(handle != null) { 1216 return handle + suffixText; 1217 } else { 1218 return "!<" + suffixText + ">"; 1219 } 1220 } 1221 1222 private final static Pattern DOC_INDIC = Pattern.compile("^(---|\\.\\.\\.)"); 1223 private final static String NULL_BL_T_LINEBR = "\0 \t\r\n\u0085"; 1224 private final static String SPECIAL_INDIC = "#,[]{}#&*!|>'\"%@`"; 1225 private final static String FLOW_INDIC = ",?[]{}"; 1226 static ScalarAnalysis analyzeScalar(final ByteList scalar) { 1227 if(scalar == null || scalar.realSize == 0) { 1228 return new ScalarAnalysis(scalar,true,false,false,true,true,true,false); 1229 } 1230 boolean blockIndicators = false; 1231 boolean flowIndicators = false; 1232 boolean lineBreaks = false; 1233 boolean specialCharacters = false; 1234 1235 boolean inlineSpaces = false; boolean inlineBreaks = false; boolean leadingSpaces = false; boolean leadingBreaks = false; boolean trailingSpaces = false; boolean trailingBreaks = false; boolean inlineBreaksSpaces = false; boolean mixedBreaksSpaces = false; 1245 if(DOC_INDIC.matcher(scalar).matches()) { 1246 blockIndicators = true; 1247 flowIndicators = true; 1248 } 1249 1250 boolean preceededBySpace = true; 1251 boolean followedBySpace = scalar.length() == 1 || NULL_BL_T_LINEBR.indexOf(scalar.charAt(1)) != -1; 1252 1253 boolean spaces = false; 1254 boolean breaks = false; 1255 boolean mixed = false; 1256 boolean leading = false; 1257 1258 int index = 0; 1259 1260 while(index < scalar.length()) { 1261 char ceh = scalar.charAt(index); 1262 if(index == 0) { 1263 if(SPECIAL_INDIC.indexOf(ceh) != -1) { 1264 flowIndicators = true; 1265 blockIndicators = true; 1266 } 1267 if(ceh == '?' || ceh == ':') { 1268 flowIndicators = true; 1269 if(followedBySpace) { 1270 blockIndicators = true; 1271 } 1272 } 1273 if(ceh == '-' && followedBySpace) { 1274 flowIndicators = true; 1275 blockIndicators = true; 1276 } 1277 } else { 1278 if(FLOW_INDIC.indexOf(ceh) != -1) { 1279 flowIndicators = true; 1280 } 1281 if(ceh == ':') { 1282 flowIndicators = true; 1283 if(followedBySpace) { 1284 blockIndicators = true; 1285 } 1286 } 1287 if(ceh == '#' && preceededBySpace) { 1288 flowIndicators = true; 1289 blockIndicators = true; 1290 } 1291 } 1292 if(ceh == '\n' || '\u0085' == ceh) { 1293 lineBreaks = true; 1294 } 1295 if(!(ceh == '\n' || ('\u0020' <= ceh && ceh <= '\u007E'))) { 1296 specialCharacters = true; 1297 1298 } 1299 if(' ' == ceh || '\n' == ceh || '\u0085' == ceh) { 1300 if(spaces && breaks) { 1301 if(ceh != ' ') { 1302 mixed = true; 1303 } 1304 } else if(spaces) { 1305 if(ceh != ' ') { 1306 breaks = true; 1307 mixed = true; 1308 } 1309 } else if(breaks) { 1310 if(ceh == ' ') { 1311 spaces = true; 1312 } 1313 } else { 1314 leading = (index == 0); 1315 if(ceh == ' ') { 1316 spaces = true; 1317 } else { 1318 breaks = true; 1319 } 1320 } 1321 } else if(spaces || breaks) { 1322 if(leading) { 1323 if(spaces && breaks) { 1324 mixedBreaksSpaces = true; 1325 } else if(spaces) { 1326 leadingSpaces = true; 1327 } else if(breaks) { 1328 leadingBreaks = true; 1329 } 1330 } else { 1331 if(mixed) { 1332 mixedBreaksSpaces = true; 1333 } else if(spaces && breaks) { 1334 inlineBreaksSpaces = true; 1335 } else if(spaces) { 1336 inlineSpaces = true; 1337 } else if(breaks) { 1338 inlineBreaks = true; 1339 } 1340 } 1341 spaces = breaks = mixed = leading = false; 1342 } 1343 1344 if((spaces || breaks) && (index == scalar.length()-1)) { 1345 if(spaces && breaks) { 1346 mixedBreaksSpaces = true; 1347 } else if(spaces) { 1348 trailingSpaces = true; 1349 if(leading) { 1350 leadingSpaces = true; 1351 } 1352 } else if(breaks) { 1353 trailingBreaks = true; 1354 if(leading) { 1355 leadingBreaks = true; 1356 } 1357 } 1358 spaces = breaks = mixed = leading = false; 1359 } 1360 index++; 1361 preceededBySpace = NULL_BL_T_LINEBR.indexOf(ceh) != -1; 1362 followedBySpace = index+1 >= scalar.length() || NULL_BL_T_LINEBR.indexOf(scalar.charAt(index+1)) != -1; 1363 } 1364 boolean allowFlowPlain = true; 1365 boolean allowBlockPlain = true; 1366 boolean allowSingleQuoted = true; 1367 boolean allowDoubleQuoted = true; 1368 boolean allowBlock = true; 1369 1370 if(leadingSpaces || leadingBreaks || trailingSpaces) { 1371 allowFlowPlain = allowBlockPlain = allowBlock = false; 1372 } 1373 1374 if(trailingBreaks) { 1375 allowFlowPlain = allowBlockPlain = false; 1376 } 1377 1378 if(inlineBreaksSpaces) { 1379 allowFlowPlain = allowBlockPlain = allowSingleQuoted = false; 1380 } 1381 1382 if(mixedBreaksSpaces || specialCharacters) { 1383 allowFlowPlain = allowBlockPlain = allowSingleQuoted = allowBlock = false; 1384 } 1385 1386 if(inlineBreaks) { 1387 allowFlowPlain = allowBlockPlain = allowSingleQuoted = false; 1388 } 1389 1390 if(trailingBreaks) { 1391 allowSingleQuoted = false; 1392 } 1393 1394 if(lineBreaks) { 1395 allowFlowPlain = allowBlockPlain = false; 1396 } 1397 1398 if(flowIndicators) { 1399 allowFlowPlain = false; 1400 } 1401 1402 if(blockIndicators) { 1403 allowBlockPlain = false; 1404 } 1405 1406 return new ScalarAnalysis(scalar,false,lineBreaks,allowFlowPlain,allowBlockPlain,allowSingleQuoted,allowDoubleQuoted,allowBlock); 1407 } 1408 1409 static String determineChomp(final ByteList text) { 1410 char ceh = ' '; 1411 char ceh2 = ' '; 1412 if(text.realSize > 0) { 1413 ceh = (char)(text.bytes[text.realSize-1] & 0xFF); 1414 if(text.realSize > 1) { 1415 ceh2 = (char)(text.bytes[text.realSize-2] & 0xFF); 1416 } 1417 } 1418 return (ceh == '\n' || ceh == '\u0085') ? ((ceh2 == '\n' || ceh2 == '\u0085') ? "+" : "") : "-"; 1419 } 1420 1421 public static void main(final String [] args) throws IOException { 1422 final String filename = args[0]; System.out.println("File contents:"); 1424 final BufferedInputStream read = new BufferedInputStream (new FileInputStream (filename)); 1425 int last = -1; 1426 while((last = read.read()) != -1) { 1427 System.out.print((char)last); 1428 } 1429 read.close(); 1430 System.out.println("--------------------------------"); 1431 final Emitter emitter = new EmitterImpl(System.out,YAML.config()); 1432 final Parser pars = new ParserImpl(new ScannerImpl(new FileInputStream (filename))); 1433 for(final Iterator iter = pars.eachEvent();iter.hasNext();) { 1434 emitter.emit((Event)iter.next()); 1435 } 1436 } 1437} | Popular Tags |