KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jvyamlb > EmitterImpl


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2007 Ola Bini <ola@ologix.com>
15  *
16  * Alternatively, the contents of this file may be used under the terms of
17  * either of the GNU General Public License Version 2 or later (the "GPL"),
18  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19  * in which case the provisions of the GPL or the LGPL are applicable instead
20  * of those above. If you wish to allow use of your version of this file only
21  * under the terms of either the GPL or the LGPL, and not to allow others to
22  * use your version of this file under the terms of the CPL, indicate your
23  * decision by deleting the provisions above and replace them with the notice
24  * and other provisions required by the GPL or the LGPL. If you do not delete
25  * the provisions above, a recipient may use your version of this file under
26  * the terms of any one of the CPL, the GPL or the LGPL.
27  ***** END LICENSE BLOCK *****/

28 package org.jvyamlb;
29
30 import java.io.IOException JavaDoc;
31 import java.io.OutputStream JavaDoc;
32 import java.io.BufferedInputStream JavaDoc;
33 import java.io.FileInputStream JavaDoc;
34
35 import java.util.HashMap JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.Iterator JavaDoc;
40 import java.util.Set JavaDoc;
41 import java.util.TreeSet JavaDoc;
42
43 import java.util.regex.Pattern JavaDoc;
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 /**
63  * @author <a HREF="mailto:ola.bini@ki.se">Ola Bini</a>
64  */

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 JavaDoc;
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 JavaDoc {
119                     env.expectDocumentStart(true);
120                 }
121             };
122         STATES[DOCUMENT_ROOT] = new EmitterState() {
123                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
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 JavaDoc {
134                     env.expectDocumentStart(false);
135                 }
136             };
137         STATES[DOCUMENT_END] = new EmitterState() {
138                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
139                     env.expectDocumentEnd();
140                 }
141             };
142         STATES[FIRST_FLOW_SEQUENCE_ITEM] = new EmitterState() {
143                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
144                     env.expectFirstFlowSequenceItem();
145                 }
146             };
147         STATES[FLOW_SEQUENCE_ITEM] = new EmitterState() {
148                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
149                     env.expectFlowSequenceItem();
150                 }
151             };
152         STATES[FIRST_FLOW_MAPPING_KEY] = new EmitterState() {
153                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
154                     env.expectFirstFlowMappingKey();
155                 }
156             };
157         STATES[FLOW_MAPPING_SIMPLE_VALUE] = new EmitterState() {
158                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
159                     env.expectFlowMappingSimpleValue();
160                 }
161             };
162         STATES[FLOW_MAPPING_VALUE] = new EmitterState() {
163                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
164                     env.expectFlowMappingValue();
165                 }
166             };
167         STATES[FLOW_MAPPING_KEY] = new EmitterState() {
168                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
169                     env.expectFlowMappingKey();
170                 }
171             };
172         STATES[BLOCK_SEQUENCE_ITEM] = new EmitterState() {
173                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
174                     env.expectBlockSequenceItem(false);
175                 }
176             };
177         STATES[FIRST_BLOCK_MAPPING_KEY] = new EmitterState() {
178                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
179                     env.expectFirstBlockMappingKey();
180                 }
181             };
182         STATES[BLOCK_MAPPING_SIMPLE_VALUE] = new EmitterState() {
183                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
184                     env.expectBlockMappingSimpleValue();
185                 }
186             };
187         STATES[BLOCK_MAPPING_VALUE] = new EmitterState() {
188                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
189                     env.expectBlockMappingValue();
190                 }
191             };
192         STATES[BLOCK_MAPPING_KEY] = new EmitterState() {
193                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
194                     env.expectBlockMappingKey(false);
195                 }
196             };
197         STATES[FIRST_BLOCK_SEQUENCE_ITEM] = new EmitterState() {
198                 public void expect(final EmitterEnvironment env) throws IOException JavaDoc {
199                     env.expectBlockSequenceItem(true);
200                 }
201             };
202     }
203
204     private final static Map JavaDoc DEFAULT_TAG_PREFIXES_1_0;
205     private final static Map JavaDoc DEFAULT_TAG_PREFIXES_1_1;
206     static {
207         final Map JavaDoc defInit0 = new HashMap JavaDoc();
208         defInit0.put("tag:yaml.org,2002:","!");
209         DEFAULT_TAG_PREFIXES_1_0 = java.util.Collections.unmodifiableMap(defInit0);
210         final Map JavaDoc defInit = new HashMap JavaDoc();
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 JavaDoc stream;
218     private YAMLConfig options;
219     private EmitterEnvironment env;
220
221     public EmitterImpl(final OutputStream JavaDoc 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 JavaDoc {
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 JavaDoc states = new ArrayList JavaDoc();
252         public int state = STREAM_START;
253         public List JavaDoc events = new ArrayList JavaDoc();
254         public Event event;
255         public int flowLevel = 0;
256         public List JavaDoc indents = new ArrayList JavaDoc();
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 JavaDoc tagPrefixes;
275
276         public String JavaDoc preparedAnchor;
277         public String JavaDoc 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 JavaDoc iter = events.iterator();
305             iter.next();
306             for(;iter.hasNext();) {
307                 final Object JavaDoc 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 JavaDoc(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 JavaDoc {
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 JavaDoc(DEFAULT_TAG_PREFIXES_1_0);
359                     } else {
360                         tagPrefixes = new HashMap JavaDoc(DEFAULT_TAG_PREFIXES_1_1);
361                     }
362
363                     if(null != ev.getTags()) {
364                         final Set JavaDoc handles = new TreeSet JavaDoc();
365                         handles.addAll(ev.getTags().keySet());
366                         for(final Iterator JavaDoc iter = handles.iterator();iter.hasNext();) {
367                             final String JavaDoc handle = (String JavaDoc)iter.next();
368                             final String JavaDoc prefix = (String JavaDoc)ev.getTags().get(handle);
369                             tagPrefixes.put(prefix,handle);
370                             final String JavaDoc handleText = prepareTagHandle(handle);
371                             final String JavaDoc 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 JavaDoc {
395             states.add(0,new Integer JavaDoc(DOCUMENT_END));
396             expectNode(true,false,false,false);
397         }
398
399         public void expectDocumentEnd() throws IOException JavaDoc {
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 JavaDoc {
414             if(event instanceof SequenceEndEvent) {
415                 indent = ((Integer JavaDoc)indents.remove(0)).intValue();
416                 flowLevel--;
417                 emitter.writeIndicator(ByteList.create("]"),false,false,false);
418                 state = ((Integer JavaDoc)states.remove(0)).intValue();
419             } else {
420                 if(canonical || column > bestWidth) {
421                     emitter.writeIndent();
422                 }
423                 states.add(0,new Integer JavaDoc(FLOW_SEQUENCE_ITEM));
424                 expectNode(false,true,false,false);
425             }
426         }
427
428         public void expectFlowSequenceItem() throws IOException JavaDoc {
429             if(event instanceof SequenceEndEvent) {
430                 indent = ((Integer JavaDoc)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 JavaDoc)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 JavaDoc(FLOW_SEQUENCE_ITEM));
444                 expectNode(false,true,false,false);
445             }
446         }
447
448         public void expectFirstFlowMappingKey() throws IOException JavaDoc {
449             if(event instanceof MappingEndEvent) {
450                 indent = ((Integer JavaDoc)indents.remove(0)).intValue();
451                 flowLevel--;
452                 emitter.writeIndicator(ByteList.create("}"),false,false,false);
453                 state = ((Integer JavaDoc)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 JavaDoc(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 JavaDoc(FLOW_MAPPING_VALUE));
464                     expectNode(false,false,true,false);
465                 }
466             }
467         }
468
469         public void expectFlowMappingSimpleValue() throws IOException JavaDoc {
470             emitter.writeIndicator(ByteList.create(": "),false,true,false);
471             states.add(0,new Integer JavaDoc(FLOW_MAPPING_KEY));
472             expectNode(false,false,true,false);
473         }
474
475         public void expectFlowMappingValue() throws IOException JavaDoc {
476             if(canonical || column > bestWidth) {
477                 emitter.writeIndent();
478             }
479             emitter.writeIndicator(ByteList.create(": "),false,true,false);
480             states.add(0,new Integer JavaDoc(FLOW_MAPPING_KEY));
481             expectNode(false,false,true,false);
482         }
483
484         public void expectFlowMappingKey() throws IOException JavaDoc {
485             if(event instanceof MappingEndEvent) {
486                 indent = ((Integer JavaDoc)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 JavaDoc)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 JavaDoc(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 JavaDoc(FLOW_MAPPING_VALUE));
505                     expectNode(false,false,true,false);
506                 }
507             }
508         }
509
510         public void expectBlockSequenceItem(final boolean first) throws IOException JavaDoc {
511             if(!first && event instanceof SequenceEndEvent) {
512                 indent = ((Integer JavaDoc)indents.remove(0)).intValue();
513                 state = ((Integer JavaDoc)states.remove(0)).intValue();
514             } else {
515                 emitter.writeIndent();
516                 emitter.writeIndicator(ByteList.create("-"),true,false,true);
517                 states.add(0,new Integer JavaDoc(BLOCK_SEQUENCE_ITEM));
518                 expectNode(false,true,false,false);
519             }
520         }
521
522         public void expectFirstBlockMappingKey() throws IOException JavaDoc {
523             expectBlockMappingKey(true);
524         }
525
526         public void expectBlockMappingSimpleValue() throws IOException JavaDoc {
527             emitter.writeIndicator(ByteList.create(": "),false,true,false);
528             states.add(0,new Integer JavaDoc(BLOCK_MAPPING_KEY));
529             expectNode(false,false,true,false);
530         }
531
532         public void expectBlockMappingValue() throws IOException JavaDoc {
533             emitter.writeIndent();
534             emitter.writeIndicator(ByteList.create(": "),true,true,true);
535             states.add(0,new Integer JavaDoc(BLOCK_MAPPING_KEY));
536             expectNode(false,false,true,false);
537         }
538
539         public void expectBlockMappingKey(final boolean first) throws IOException JavaDoc {
540             if(!first && event instanceof MappingEndEvent) {
541                 indent = ((Integer JavaDoc)indents.remove(0)).intValue();
542                 state = ((Integer JavaDoc)states.remove(0)).intValue();
543             } else {
544                 emitter.writeIndent();
545                 if(checkSimpleKey()) {
546                     states.add(0,new Integer JavaDoc(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 JavaDoc(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 JavaDoc {
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 JavaDoc {
587             if(((NodeEvent)event).getAnchor() == null) {
588                 throw new EmitterException("anchor is not specified for alias");
589             }
590             processAnchor(ByteList.create("*"));
591             state = ((Integer JavaDoc)states.remove(0)).intValue();
592         }
593
594         private void expectScalar() throws IOException JavaDoc {
595             increaseIndent(true,false);
596             processScalar();
597             indent = ((Integer JavaDoc)indents.remove(0)).intValue();
598             state = ((Integer JavaDoc)states.remove(0)).intValue();
599         }
600
601         private void expectFlowSequence() throws IOException JavaDoc {
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 JavaDoc {
609             increaseIndent(false, mappingContext && !indentation);
610             state = FIRST_BLOCK_SEQUENCE_ITEM;
611         }
612
613         private void expectFlowMapping() throws IOException JavaDoc {
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 JavaDoc {
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 JavaDoc 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 JavaDoc {
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 JavaDoc {
688             String JavaDoc 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 && ev.getImplicit()[0]) {
736
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 JavaDoc {
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 JavaDoc {
783         flushStream();
784     }
785     
786     void writeIndicator(final ByteList indicator, final boolean needWhitespace, final boolean whitespace, final boolean indentation) throws IOException JavaDoc {
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 JavaDoc {
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 JavaDoc version_text) throws IOException JavaDoc {
819         stream.write(("%YAML " + version_text).getBytes());
820         writeLineBreak(null);
821     }
822     
823     void writeTagDirective(final String JavaDoc handle, final String JavaDoc prefix) throws IOException JavaDoc {
824         stream.write(("%TAG " + handle + " " + prefix).getBytes());
825         writeLineBreak(null);
826     }
827
828     void writeDoubleQuoted(final ByteList text, final boolean split) throws IOException JavaDoc {
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 JavaDoc(ch))) {
847                         data = ByteList.create("\\" + YAML.ESCAPE_REPLACEMENTS.get(new Character JavaDoc(ch)));
848                     } else if(ch <= '\u00FF') {
849                         String JavaDoc 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 JavaDoc {
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 JavaDoc {
951         String JavaDoc 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 JavaDoc {
1014        String JavaDoc 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 JavaDoc {
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); // space
1066
}
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 JavaDoc {
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 JavaDoc {
1137        stream.flush();
1138    }
1139
1140    static String JavaDoc 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 JavaDoc HANDLE_FORMAT = Pattern.compile("^![-\\w]*!$");
1147    static String JavaDoc prepareTagHandle(final String JavaDoc 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 JavaDoc prepareTagPrefix(final String JavaDoc prefix) {
1159        if(prefix == null || "".equals(prefix)) {
1160            throw new EmitterException("tag prefix must not be empty");
1161        }
1162        final StringBuffer JavaDoc chunks = new StringBuffer JavaDoc();
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 JavaDoc ANCHOR_FORMAT = Pattern.compile("^[-\\w]*$");
1177    static String JavaDoc prepareAnchor(final String JavaDoc 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 JavaDoc prepareTag(final String JavaDoc 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 JavaDoc handle = null;
1195        String JavaDoc suffix = tag;
1196        for(final Iterator JavaDoc iter = env.tagPrefixes.keySet().iterator();iter.hasNext();) {
1197            String JavaDoc prefix = (String JavaDoc)iter.next();
1198            if(Pattern.matches("^" + prefix + ".+$", tag) && (prefix.equals("!") || prefix.length() < tag.length())) {
1199                handle = (String JavaDoc)env.tagPrefixes.get(prefix);
1200                suffix = tag.substring(prefix.length());
1201            }
1202        }
1203        final StringBuffer JavaDoc chunks = new StringBuffer JavaDoc();
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 JavaDoc 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 JavaDoc DOC_INDIC = Pattern.compile("^(---|\\.\\.\\.)");
1223    private final static String JavaDoc NULL_BL_T_LINEBR = "\0 \t\r\n\u0085";
1224    private final static String JavaDoc SPECIAL_INDIC = "#,[]{}#&*!|>'\"%@`";
1225    private final static String JavaDoc 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        // Whitespaces.
1236
boolean inlineSpaces = false; // non-space space+ non-space
1237
boolean inlineBreaks = false; // non-space break+ non-space
1238
boolean leadingSpaces = false; // ^ space+ (non-space | $)
1239
boolean leadingBreaks = false; // ^ break+ (non-space | $)
1240
boolean trailingSpaces = false; // (^ | non-space) space+ $
1241
boolean trailingBreaks = false; // (^ | non-space) break+ $
1242
boolean inlineBreaksSpaces = false; // non-space break+ space+ non-space
1243
boolean mixedBreaksSpaces = false; // anything else
1244

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 JavaDoc 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 JavaDoc[] args) throws IOException JavaDoc {
1422        final String JavaDoc filename = args[0]; // filename to test against
1423
System.out.println("File contents:");
1424        final BufferedInputStream JavaDoc read = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(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 JavaDoc(filename)));
1433        for(final Iterator JavaDoc iter = pars.eachEvent();iter.hasNext();) {
1434            emitter.emit((Event)iter.next());
1435        }
1436    }
1437}// EmitterImpl
1438
Popular Tags