1 package com.ctc.wstx.api;
2
3 import java.lang.ref.SoftReference;
4 import java.util.HashMap;
5
6 import javax.xml.stream.XMLOutputFactory;
7 import javax.xml.stream.XMLReporter;
8
9 import org.codehaus.stax2.XMLOutputFactory2;
10 import org.codehaus.stax2.XMLStreamProperties;
11 import org.codehaus.stax2.io.EscapingWriterFactory;
12
13 import com.ctc.wstx.cfg.OutputConfigFlags;
14 import com.ctc.wstx.io.BufferRecycler;
15 import com.ctc.wstx.util.ArgUtil;
16 import com.ctc.wstx.util.DataUtil;
17 // for property consts
18
19 /**
20  * Simple configuration container class; passed by writer factory to writer
21  * instance created.
22  */

23 public final class WriterConfig
24     extends CommonConfig
25     implements OutputConfigFlags
26 {
27     // // // Constants for standard Stax properties:
28
29     protected final static String DEFAULT_AUTOMATIC_NS_PREFIX = "wstxns";
30
31     // // // First, standard Stax writer properties
32
33     final static int PROP_AUTOMATIC_NS = 1; // standard property ("repairing")
34
35     // // // And then additional Stax2 properties:
36
37     // General output settings
38     final static int PROP_AUTOMATIC_EMPTY_ELEMENTS = 2;
39     final static int PROP_AUTO_CLOSE_OUTPUT = 3;
40     // Namespace settings:
41     final static int PROP_ENABLE_NS = 4;
42     final static int PROP_AUTOMATIC_NS_PREFIX = 5;
43     // Escaping text content/attr values:
44     final static int PROP_TEXT_ESCAPER = 6;
45     final static int PROP_ATTR_VALUE_ESCAPER = 7;
46     // Problem checking/reporting options
47     final static int PROP_PROBLEM_REPORTER = 8;
48
49     // // // And then custom Wstx properties:
50
51     // Output settings:
52     final static int PROP_USE_DOUBLE_QUOTES_IN_XML_DECL = 10;
53
54     final static int PROP_OUTPUT_CDATA_AS_TEXT = 11;
55
56     final static int PROP_COPY_DEFAULT_ATTRS = 12;
57
58     final static int PROP_ESCAPE_CR = 13;
59
60     final static int PROP_ADD_SPACE_AFTER_EMPTY_ELEM = 14;
61
62     final static int PROP_AUTOMATIC_END_ELEMENTS = 15;
63
64     // Validation flags:
65
66     final static int PROP_VALIDATE_STRUCTURE = 16;
67     final static int PROP_VALIDATE_CONTENT = 17;
68     final static int PROP_VALIDATE_ATTR = 18;
69     final static int PROP_VALIDATE_NAMES = 19;
70     final static int PROP_FIX_CONTENT = 20;
71
72     // Other:
73
74     final static int PROP_OUTPUT_INVALID_CHAR_HANDLER = 21;
75     final static int PROP_OUTPUT_EMPTY_ELEMENT_HANDLER = 22;
76
77     // Per-writer instance information
78
79     final static int PROP_UNDERLYING_STREAM = 30;
80     final static int PROP_UNDERLYING_WRITER = 31;
81
82     // // // Default settings for additional properties:
83
84     /* 18-May-2013, feature request WSTX-291
85      */

86     final static boolean DEFAULT_USE_DOUBLE_QUOTES_IN_XML_DECL = false;
87
88     final static boolean DEFAULT_OUTPUT_CDATA_AS_TEXT = false;
89     final static boolean DEFAULT_COPY_DEFAULT_ATTRS = false;
90
91     /* 26-Dec-2006, TSa: Since CRs have been auto-escaped so far, let's
92      *   retain the defaults when adding new properties/features.
93      */

94     final static boolean DEFAULT_ESCAPE_CR = true;
95
96     /**
97      * 09-Aug-2007, TSa: Space has always been added after empty
98      *   element (before closing "/>"), but now it is configurable.
99      * 31-Dec-2009, TSa: Intention was to leave it enabled for backwards
100      *   compatibility: but due to a bug this was NOT the case... ugh.
101      */

102     final static boolean DEFAULT_ADD_SPACE_AFTER_EMPTY_ELEM = false;
103
104     /* How about validation? Let's turn them mostly off by default, since
105      * there are some performance hits when enabling them.
106      */

107
108     // Structural checks are easy, cheap and useful...
109     final static boolean DEFAULT_VALIDATE_STRUCTURE = true;
110
111     /* 17-May-2006, TSa: Since content validation is now much cheaper
112      *   (due to integrated transcoders) than it used to be, let's
113      *   just enable content validation too.
114      */

115     final static boolean DEFAULT_VALIDATE_CONTENT = true;
116     final static boolean DEFAULT_VALIDATE_ATTR = false;
117     final static boolean DEFAULT_VALIDATE_NAMES = false;
118
119     // This only matters if content validation is enabled...
120     /**
121      * As per [WSTX-120], default was changed to false,
122      * from true (default prior to wstx 4.0)
123      */

124     //final static boolean DEFAULT_FIX_CONTENT = true;
125     final static boolean DEFAULT_FIX_CONTENT = false;
126
127     /**
128      * Default config flags are converted from individual settings,
129      * to conform to Stax 1.0 specifications.
130      */

131     final static int DEFAULT_FLAGS_J2ME =
132         0
133
134         // Stax 1.0 mandated:
135
136         // namespace-awareness assumed; repairing disabled by default:
137         // | CFG_AUTOMATIC_NS
138         | CFG_ENABLE_NS
139
140         // Usually it's good to allow writer to produce empty elems
141         // (note: default for woodstox 1.x was false)
142         | CFG_AUTOMATIC_EMPTY_ELEMENTS
143
144         | (DEFAULT_USE_DOUBLE_QUOTES_IN_XML_DECL ? CFG_USE_DOUBLE_QUOTES_IN_XML_DECL : 0)
145         | (DEFAULT_OUTPUT_CDATA_AS_TEXT ? CFG_OUTPUT_CDATA_AS_TEXT : 0)
146         | (DEFAULT_COPY_DEFAULT_ATTRS ? CFG_COPY_DEFAULT_ATTRS : 0)
147         | (DEFAULT_ESCAPE_CR ? CFG_ESCAPE_CR : 0)
148         | (DEFAULT_ADD_SPACE_AFTER_EMPTY_ELEM ? CFG_ADD_SPACE_AFTER_EMPTY_ELEM : 0)
149         | CFG_AUTOMATIC_END_ELEMENTS
150
151         | (DEFAULT_VALIDATE_STRUCTURE ? CFG_VALIDATE_STRUCTURE : 0)
152         | (DEFAULT_VALIDATE_CONTENT ? CFG_VALIDATE_CONTENT : 0)
153         | (DEFAULT_VALIDATE_ATTR ? CFG_VALIDATE_ATTR : 0)
154         | (DEFAULT_VALIDATE_NAMES ? CFG_VALIDATE_NAMES : 0)
155         | (DEFAULT_FIX_CONTENT ? CFG_FIX_CONTENT : 0)
156
157         // As per Stax 1.0 specs, we can not enable this by default:
158         //| CFG_AUTO_CLOSE_INPUT);
159         ;
160
161     /**
162      * For now, full instances start with same settings as J2ME subset
163      */

164     final static int DEFAULT_FLAGS_FULL = DEFAULT_FLAGS_J2ME;
165
166     // // //
167
168     /**
169      * Map to use for converting from String property ids to ints
170      * described above; useful to allow use of switch later on.
171      */

172     final static HashMap<String,Integer> sProperties = new HashMap<String,Integer>(8);
173     static {
174         // // Stax (1.0) standard ones:
175         sProperties.put(XMLOutputFactory.IS_REPAIRING_NAMESPACES,
176                         DataUtil.Integer(PROP_AUTOMATIC_NS));
177
178         // // Stax2 standard ones:
179
180         // Namespace support
181         sProperties.put(XMLStreamProperties.XSP_NAMESPACE_AWARE,
182                         DataUtil.Integer(PROP_ENABLE_NS));
183
184         // Generic output
185         sProperties.put(XMLOutputFactory2.P_AUTOMATIC_EMPTY_ELEMENTS,
186                         DataUtil.Integer(PROP_AUTOMATIC_EMPTY_ELEMENTS));
187         sProperties.put(XMLOutputFactory2.P_AUTO_CLOSE_OUTPUT,
188                         DataUtil.Integer(PROP_AUTO_CLOSE_OUTPUT));
189         // Namespace support
190         sProperties.put(XMLOutputFactory2.P_AUTOMATIC_NS_PREFIX,
191                         DataUtil.Integer(PROP_AUTOMATIC_NS_PREFIX));
192         // Text/attr value escaping (customized escapers)
193         sProperties.put(XMLOutputFactory2.P_TEXT_ESCAPER,
194                         DataUtil.Integer(PROP_TEXT_ESCAPER));
195         sProperties.put(XMLOutputFactory2.P_ATTR_VALUE_ESCAPER,
196                         DataUtil.Integer(PROP_ATTR_VALUE_ESCAPER));
197         // Problem checking/reporting options
198         sProperties.put(XMLStreamProperties.XSP_PROBLEM_REPORTER,
199                         DataUtil.Integer(PROP_PROBLEM_REPORTER));
200
201         // // Woodstox-specifics:
202
203         // Output conversions
204         sProperties.put(WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL,
205                         DataUtil.Integer(PROP_USE_DOUBLE_QUOTES_IN_XML_DECL));
206         sProperties.put(WstxOutputProperties.P_OUTPUT_CDATA_AS_TEXT,
207                         DataUtil.Integer(PROP_OUTPUT_CDATA_AS_TEXT));
208         sProperties.put(WstxOutputProperties.P_COPY_DEFAULT_ATTRS,
209                         DataUtil.Integer(PROP_COPY_DEFAULT_ATTRS));
210         sProperties.put(WstxOutputProperties.P_OUTPUT_ESCAPE_CR,
211                         DataUtil.Integer(PROP_ESCAPE_CR));
212         sProperties.put(WstxOutputProperties.P_ADD_SPACE_AFTER_EMPTY_ELEM,
213                         DataUtil.Integer(PROP_ADD_SPACE_AFTER_EMPTY_ELEM));
214         sProperties.put(WstxOutputProperties.P_AUTOMATIC_END_ELEMENTS,
215                         DataUtil.Integer(PROP_AUTOMATIC_END_ELEMENTS));
216         sProperties.put(WstxOutputProperties.P_OUTPUT_INVALID_CHAR_HANDLER,
217                         DataUtil.Integer(PROP_OUTPUT_INVALID_CHAR_HANDLER));
218         sProperties.put(WstxOutputProperties.P_OUTPUT_EMPTY_ELEMENT_HANDLER,
219                         DataUtil.Integer(PROP_OUTPUT_EMPTY_ELEMENT_HANDLER));
220
221         // Validation settings:
222         sProperties.put(WstxOutputProperties.P_OUTPUT_VALIDATE_STRUCTURE,
223                         DataUtil.Integer(PROP_VALIDATE_STRUCTURE));
224         sProperties.put(WstxOutputProperties.P_OUTPUT_VALIDATE_CONTENT,
225                         DataUtil.Integer(PROP_VALIDATE_CONTENT));
226         sProperties.put(WstxOutputProperties.P_OUTPUT_VALIDATE_ATTR,
227                         DataUtil.Integer(PROP_VALIDATE_ATTR));
228         sProperties.put(WstxOutputProperties.P_OUTPUT_VALIDATE_NAMES,
229                         DataUtil.Integer(PROP_VALIDATE_NAMES));
230         sProperties.put(WstxOutputProperties.P_OUTPUT_FIX_CONTENT,
231                         DataUtil.Integer(PROP_FIX_CONTENT));
232
233         // Underlying stream/writer access
234         sProperties.put(WstxOutputProperties.P_OUTPUT_UNDERLYING_STREAM,
235                         DataUtil.Integer(PROP_UNDERLYING_STREAM));
236         sProperties.put(WstxOutputProperties.P_OUTPUT_UNDERLYING_STREAM,
237                         DataUtil.Integer(PROP_UNDERLYING_STREAM));
238     }
239
240     /*
241     //////////////////////////////////////////////////////////
242     // Current config state:
243     //////////////////////////////////////////////////////////
244      */

245
246     final boolean mIsJ2MESubset;
247
248     protected int mConfigFlags;
249
250     /*
251     //////////////////////////////////////////////////////////
252     // More special(ized) configuration objects
253     //////////////////////////////////////////////////////////
254      */

255
256     //protected String mAutoNsPrefix;
257     //protected EscapingWriterFactory mTextEscaperFactory = null;
258     //protected EscapingWriterFactory mAttrValueEscaperFactory = null;
259     //protected XMLReporter mProblemReporter = null;
260     //protected InvalidCharHandler mInvalidCharHandler = null;
261
262     Object[] mSpecialProperties = null;
263
264     private final static int SPEC_PROC_COUNT = 6;
265
266     private final static int SP_IX_AUTO_NS_PREFIX = 0;
267     private final static int SP_IX_TEXT_ESCAPER_FACTORY = 1;
268     private final static int SP_IX_ATTR_VALUE_ESCAPER_FACTORY = 2;
269     private final static int SP_IX_PROBLEM_REPORTER = 3;
270     private final static int SP_IX_INVALID_CHAR_HANDLER = 4;
271     private final static int SP_IX_EMPTY_ELEMENT_HANDLER = 5;
272
273     /*
274     //////////////////////////////////////////////////////////
275     // Buffer recycling:
276     //////////////////////////////////////////////////////////
277      */

278
279     /**
280      * This <code>ThreadLocal</code> contains a {@link SoftRerefence}
281      * to a {@link BufferRecycler} used to provide a low-cost
282      * buffer recycling between Reader instances.
283      */

284     final static ThreadLocal<SoftReference<BufferRecycler>> mRecyclerRef = new ThreadLocal<SoftReference<BufferRecycler>>();
285
286     /**
287      * This is the actually container of the recyclable buffers. It
288      * is obtained via ThreadLocal/SoftReference combination, if one
289      * exists, when Config instance is created. If one does not
290      * exists, it will created first time a buffer is returned.
291      */

292     BufferRecycler mCurrRecycler = null;
293
294     /*
295     //////////////////////////////////////////////////////////
296     // Life-cycle:
297     //////////////////////////////////////////////////////////
298      */

299
300     private WriterConfig(WriterConfig base,
301             boolean j2meSubset, int flags, Object[] specProps)
302     {
303         super(base);
304         mIsJ2MESubset = j2meSubset;
305         mConfigFlags = flags;
306         mSpecialProperties = specProps;
307
308         /* Ok, let's then see if we can find a buffer recycler. Since they
309          * are lazily constructed, and since GC may just flush them out
310          * on its whims, it's possible we might not find one. That's ok;
311          * we can reconstruct one if and when we are to return one or more
312          * buffers.
313          */

314         SoftReference<BufferRecycler> ref = mRecyclerRef.get();
315         if (ref != null) {
316             mCurrRecycler = ref.get();
317         }
318     }
319
320     public static WriterConfig createJ2MEDefaults()
321     {
322         return new WriterConfig(nulltrue, DEFAULT_FLAGS_J2ME, null);
323     }
324
325     public static WriterConfig createFullDefaults()
326     {
327         return new WriterConfig(nullfalse, DEFAULT_FLAGS_FULL, null);
328     }
329
330     public WriterConfig createNonShared()
331     {
332         Object[] specProps;
333
334         if (mSpecialProperties != null) {
335             int len = mSpecialProperties.length;
336             specProps = new Object[len];
337             System.arraycopy(mSpecialProperties, 0, specProps, 0, len);
338         } else {
339             specProps = null;
340         }
341         return new WriterConfig(this, mIsJ2MESubset, mConfigFlags, specProps);
342     }
343
344     /*
345     //////////////////////////////////////////////////////////
346     // Implementation of abstract methods
347     //////////////////////////////////////////////////////////
348      */

349
350     @Override
351     protected int findPropertyId(String propName)
352     {
353         Integer I = sProperties.get(propName);
354         return (I == null) ? -1 : I.intValue();
355     }
356
357     /*
358     //////////////////////////////////////////////////////////
359     // Public API
360     //////////////////////////////////////////////////////////
361      */

362
363     @Override
364     public Object getProperty(int id)
365     {
366         switch (id) {
367
368         // First, Stax 1.0 properties:
369
370         case PROP_AUTOMATIC_NS:
371             return automaticNamespacesEnabled() ? Boolean.TRUE : Boolean.FALSE;
372
373         // Then Stax2 properties:
374
375             // First, properties common to input/output factories:
376
377         case PROP_ENABLE_NS:
378             return willSupportNamespaces() ? Boolean.TRUE : Boolean.FALSE;
379         case PROP_PROBLEM_REPORTER:
380             return getProblemReporter();
381
382             // Then output-specific properties:
383         case PROP_AUTOMATIC_EMPTY_ELEMENTS:
384             return automaticEmptyElementsEnabled() ? Boolean.TRUE : Boolean.FALSE;
385         case PROP_AUTO_CLOSE_OUTPUT:
386             return willAutoCloseOutput() ? Boolean.TRUE : Boolean.FALSE;
387         case PROP_AUTOMATIC_NS_PREFIX:
388             return getAutomaticNsPrefix();
389         case PROP_TEXT_ESCAPER:
390             return getTextEscaperFactory();
391         case PROP_ATTR_VALUE_ESCAPER:
392             return getAttrValueEscaperFactory();
393
394         // // // Then Woodstox-specific properties:
395
396         case PROP_USE_DOUBLE_QUOTES_IN_XML_DECL:
397             return willUseDoubleQuotesInXmlDecl() ? Boolean.TRUE : Boolean.FALSE;
398         case PROP_OUTPUT_CDATA_AS_TEXT:
399             return willOutputCDataAsText() ? Boolean.TRUE : Boolean.FALSE;
400         case PROP_COPY_DEFAULT_ATTRS:
401             return willCopyDefaultAttrs() ? Boolean.TRUE : Boolean.FALSE;
402         case PROP_ESCAPE_CR:
403             return willEscapeCr() ? Boolean.TRUE : Boolean.FALSE;
404         case PROP_ADD_SPACE_AFTER_EMPTY_ELEM:
405             return willAddSpaceAfterEmptyElem() ? Boolean.TRUE : Boolean.FALSE;
406         case PROP_AUTOMATIC_END_ELEMENTS:
407             return automaticEndElementsEnabled() ? Boolean.TRUE : Boolean.FALSE;
408
409         case PROP_VALIDATE_STRUCTURE:
410             return willValidateStructure() ? Boolean.TRUE : Boolean.FALSE;
411         case PROP_VALIDATE_CONTENT:
412             return willValidateContent() ? Boolean.TRUE : Boolean.FALSE;
413         case PROP_VALIDATE_ATTR:
414             return willValidateAttributes() ? Boolean.TRUE : Boolean.FALSE;
415         case PROP_VALIDATE_NAMES:
416             return willValidateNames() ? Boolean.TRUE : Boolean.FALSE;
417         case PROP_FIX_CONTENT:
418             return willFixContent() ? Boolean.TRUE : Boolean.FALSE;
419         case PROP_OUTPUT_INVALID_CHAR_HANDLER:
420             return getInvalidCharHandler();
421         case PROP_OUTPUT_EMPTY_ELEMENT_HANDLER:
422             return getEmptyElementHandler();
423
424             // And then per-instance properties: not valid via config object
425         case PROP_UNDERLYING_STREAM:
426         case PROP_UNDERLYING_WRITER:
427             throw new IllegalStateException("Can not access per-stream-writer properties via factory");
428         }
429
430         throw new IllegalStateException("Internal error: no handler for property with internal id "+id+".");
431     }
432
433     /**
434      * @return True, if the specified property was <b>succesfully</b>
435      *    set to specified value; false if its value was not changed
436      */

437     @Override
438     public boolean setProperty(String name, int id, Object value)
439     {
440         switch (id) {
441         // First, Stax 1.0 properties:
442
443         case PROP_AUTOMATIC_NS:
444             enableAutomaticNamespaces(ArgUtil.convertToBoolean(name, value));
445             break;
446
447        // // // Then Stax2 ones:
448
449         case PROP_ENABLE_NS:
450             doSupportNamespaces(ArgUtil.convertToBoolean(name, value));
451             break;
452         case PROP_PROBLEM_REPORTER:
453             setProblemReporter((XMLReporter) value);
454             break;
455
456         case PROP_AUTOMATIC_EMPTY_ELEMENTS:
457             enableAutomaticEmptyElements(ArgUtil.convertToBoolean(name, value));
458             break;
459
460         case PROP_AUTO_CLOSE_OUTPUT:
461             doAutoCloseOutput(ArgUtil.convertToBoolean(name, value));
462             break;
463
464         case PROP_AUTOMATIC_NS_PREFIX:
465             // value should be a String, but let's verify that:
466             setAutomaticNsPrefix(value.toString());
467             break;
468
469         case PROP_TEXT_ESCAPER:
470             setTextEscaperFactory((EscapingWriterFactory) value);
471             break;
472
473         case PROP_ATTR_VALUE_ESCAPER:
474             setAttrValueEscaperFactory((EscapingWriterFactory) value);
475             break;
476
477             // // // Then Woodstox-specific ones:
478
479         case PROP_USE_DOUBLE_QUOTES_IN_XML_DECL:
480             doUseDoubleQuotesInXmlDecl(ArgUtil.convertToBoolean(name, value));
481             break;
482         case PROP_OUTPUT_CDATA_AS_TEXT:
483             doOutputCDataAsText(ArgUtil.convertToBoolean(name, value));
484             break;
485         case PROP_COPY_DEFAULT_ATTRS:
486             doCopyDefaultAttrs(ArgUtil.convertToBoolean(name, value));
487             break;
488         case PROP_ESCAPE_CR:
489             doEscapeCr(ArgUtil.convertToBoolean(name, value));
490             break;
491         case PROP_ADD_SPACE_AFTER_EMPTY_ELEM:
492             doAddSpaceAfterEmptyElem(ArgUtil.convertToBoolean(name, value));
493             break;
494         case PROP_AUTOMATIC_END_ELEMENTS:
495             enableAutomaticEndElements(ArgUtil.convertToBoolean(name, value));
496             break;
497         case PROP_VALIDATE_STRUCTURE:
498             doValidateStructure(ArgUtil.convertToBoolean(name, value));
499             break;
500         case PROP_VALIDATE_CONTENT:
501             doValidateContent(ArgUtil.convertToBoolean(name, value));
502             break;
503         case PROP_VALIDATE_ATTR:
504             doValidateAttributes(ArgUtil.convertToBoolean(name, value));
505             break;
506         case PROP_VALIDATE_NAMES:
507             doValidateNames(ArgUtil.convertToBoolean(name, value));
508             break;
509         case PROP_FIX_CONTENT:
510             doFixContent(ArgUtil.convertToBoolean(name, value));
511             break;
512         case PROP_OUTPUT_INVALID_CHAR_HANDLER:
513             setInvalidCharHandler((InvalidCharHandler) value);
514             break;
515         case PROP_OUTPUT_EMPTY_ELEMENT_HANDLER:
516             setEmptyElementHandler((EmptyElementHandler) value);
517             break;
518
519         case PROP_UNDERLYING_STREAM:
520         case PROP_UNDERLYING_WRITER:
521             throw new IllegalStateException("Can not modify per-stream-writer properties via factory");
522
523         default:
524             throw new IllegalStateException("Internal error: no handler for property with internal id "+id+".");
525         }
526
527         return true;
528     }
529
530     /*
531     //////////////////////////////////////////////////////////
532     // Extended Woodstox API, accessors/modifiers
533     //////////////////////////////////////////////////////////
534      */

535
536     // // // "Raw" accessors for on/off properties:
537
538     public int getConfigFlags() { return mConfigFlags; }
539
540
541     // // // Accessors, standard properties:
542
543     public boolean automaticNamespacesEnabled() {
544         return hasConfigFlag(CFG_AUTOMATIC_NS);
545     }
546
547     // // // Accessors, Woodstox properties:
548
549     public boolean automaticEmptyElementsEnabled() {
550         return hasConfigFlag(CFG_AUTOMATIC_EMPTY_ELEMENTS);
551     }
552
553     public boolean willAutoCloseOutput() {
554         return hasConfigFlag(CFG_AUTO_CLOSE_OUTPUT);
555     }
556
557     public boolean willSupportNamespaces() {
558         return hasConfigFlag(CFG_ENABLE_NS);
559     }
560
561     /**
562      * @since 4.2.2
563      */

564     public boolean willUseDoubleQuotesInXmlDecl() {
565         return hasConfigFlag(CFG_USE_DOUBLE_QUOTES_IN_XML_DECL);
566     }
567
568     public boolean willOutputCDataAsText() {
569         return hasConfigFlag(CFG_OUTPUT_CDATA_AS_TEXT);
570     }
571
572     public boolean willCopyDefaultAttrs() {
573         return hasConfigFlag(CFG_COPY_DEFAULT_ATTRS);
574     }
575
576     public boolean willEscapeCr() {
577         return hasConfigFlag(CFG_ESCAPE_CR);
578     }
579
580     public boolean willAddSpaceAfterEmptyElem() {
581         return hasConfigFlag(CFG_ADD_SPACE_AFTER_EMPTY_ELEM);
582     }
583
584     public boolean automaticEndElementsEnabled() {
585         return hasConfigFlag(CFG_AUTOMATIC_END_ELEMENTS);
586     }
587
588     public boolean willValidateStructure() {
589         return hasConfigFlag(CFG_VALIDATE_STRUCTURE);
590     }
591
592     public boolean willValidateContent() {
593         return hasConfigFlag(CFG_VALIDATE_CONTENT);
594     }
595
596     public boolean willValidateAttributes() {
597         return hasConfigFlag(CFG_VALIDATE_ATTR);
598     }
599
600     public boolean willValidateNames() {
601         return hasConfigFlag(CFG_VALIDATE_NAMES);
602     }
603
604     public boolean willFixContent() {
605         return hasConfigFlag(CFG_FIX_CONTENT);
606     }
607
608     /**
609      * @return Prefix to use as the base for automatically generated
610      *   namespace prefixes ("namespace prefix prefix", so to speak).
611      *   Defaults to "wstxns".
612      */

613     public String getAutomaticNsPrefix() {
614         String prefix = (String) getSpecialProperty(SP_IX_AUTO_NS_PREFIX);
615         if (prefix == null) {
616             prefix = DEFAULT_AUTOMATIC_NS_PREFIX;
617         }
618         return prefix;
619     }
620
621     public EscapingWriterFactory getTextEscaperFactory() {
622         return (EscapingWriterFactory) getSpecialProperty(SP_IX_TEXT_ESCAPER_FACTORY);
623     }
624
625     public EscapingWriterFactory getAttrValueEscaperFactory() {
626         return (EscapingWriterFactory) getSpecialProperty(SP_IX_ATTR_VALUE_ESCAPER_FACTORY);
627     }
628
629     public XMLReporter getProblemReporter() {
630         return (XMLReporter) getSpecialProperty(SP_IX_PROBLEM_REPORTER);
631     }
632
633     public InvalidCharHandler getInvalidCharHandler() {
634         return (InvalidCharHandler) getSpecialProperty(SP_IX_INVALID_CHAR_HANDLER);
635     }
636
637     public EmptyElementHandler getEmptyElementHandler() {
638         return (EmptyElementHandler) getSpecialProperty(SP_IX_EMPTY_ELEMENT_HANDLER);
639     }
640
641     // // // Mutators:
642
643     // Standard properies:
644
645     public void enableAutomaticNamespaces(boolean state) {
646         setConfigFlag(CFG_AUTOMATIC_NS, state);
647     }
648
649     // Wstx properies:
650
651     public void enableAutomaticEmptyElements(boolean state) {
652         setConfigFlag(CFG_AUTOMATIC_EMPTY_ELEMENTS, state);
653     }
654
655     public void doAutoCloseOutput(boolean state) {
656         setConfigFlag(CFG_AUTO_CLOSE_OUTPUT, state);
657     }
658
659     public void doSupportNamespaces(boolean state) {
660         setConfigFlag(CFG_ENABLE_NS, state);
661     }
662
663     /**
664      * @since 4.2.2
665      */

666     public void doUseDoubleQuotesInXmlDecl(boolean state) {
667         setConfigFlag(CFG_USE_DOUBLE_QUOTES_IN_XML_DECL, state);
668     }
669
670     public void doOutputCDataAsText(boolean state) {
671         setConfigFlag(CFG_OUTPUT_CDATA_AS_TEXT, state);
672     }
673
674     public void doCopyDefaultAttrs(boolean state) {
675         setConfigFlag(CFG_COPY_DEFAULT_ATTRS, state);
676     }
677
678     public void doEscapeCr(boolean state) {
679         setConfigFlag(CFG_ESCAPE_CR, state);
680     }
681
682     public void doAddSpaceAfterEmptyElem(boolean state) {
683         setConfigFlag(CFG_ADD_SPACE_AFTER_EMPTY_ELEM, state);
684     }
685
686     public void enableAutomaticEndElements(boolean state) {
687         setConfigFlag(CFG_AUTOMATIC_END_ELEMENTS, state);
688     }
689
690     public void doValidateStructure(boolean state) {
691         setConfigFlag(CFG_VALIDATE_STRUCTURE, state);
692     }
693
694     public void doValidateContent(boolean state) {
695         setConfigFlag(CFG_VALIDATE_CONTENT, state);
696     }
697
698     public void doValidateAttributes(boolean state) {
699         setConfigFlag(CFG_VALIDATE_ATTR, state);
700     }
701
702     public void doValidateNames(boolean state) {
703         setConfigFlag(CFG_VALIDATE_NAMES, state);
704     }
705
706     public void doFixContent(boolean state) {
707         setConfigFlag(CFG_FIX_CONTENT, state);
708     }
709
710     /**
711      * @param prefix Prefix to use as the base for automatically generated
712      *   namespace prefixes ("namespace prefix prefix", so to speak).
713      */

714     public void setAutomaticNsPrefix(String prefix) {
715         setSpecialProperty(SP_IX_AUTO_NS_PREFIX, prefix);
716     }
717
718     public void setTextEscaperFactory(EscapingWriterFactory f) {
719         setSpecialProperty(SP_IX_TEXT_ESCAPER_FACTORY, f);
720     }
721
722     public void setAttrValueEscaperFactory(EscapingWriterFactory f) {
723         setSpecialProperty(SP_IX_ATTR_VALUE_ESCAPER_FACTORY, f);
724     }
725
726     public void setProblemReporter(XMLReporter rep) {
727         setSpecialProperty(SP_IX_PROBLEM_REPORTER, rep);
728     }
729
730     public void setInvalidCharHandler(InvalidCharHandler h) {
731         setSpecialProperty(SP_IX_INVALID_CHAR_HANDLER, h);
732     }
733
734     public void setEmptyElementHandler(EmptyElementHandler h) {
735         setSpecialProperty(SP_IX_EMPTY_ELEMENT_HANDLER, h);
736     }
737
738     /*
739     //////////////////////////////////////////////////////////
740     // Extended Woodstox API, profiles
741     //////////////////////////////////////////////////////////
742      */

743
744     /**
745      * For Woodstox, this profile enables all basic well-formedness checks,
746      * including checking for name validity.
747      */

748     public void configureForXmlConformance()
749     {
750         doValidateAttributes(true);
751         doValidateContent(true);
752         doValidateStructure(true);
753         doValidateNames(true);
754     }
755
756     /**
757      * For Woodstox, this profile enables all basic well-formedness checks,
758      * including checking for name validity, and also enables all matching
759      * "fix-me" properties (currently only content-fixing property exists).
760      */

761     public void configureForRobustness()
762     {
763         doValidateAttributes(true);
764         doValidateStructure(true);
765         doValidateNames(true);
766
767         /* This the actual "meat": we do want to not only check if the
768          * content is ok, but also "fix" it if not, and if there's a way
769          * to fix it:
770          */

771         doValidateContent(true);
772         doFixContent(true);
773     }
774
775     /**
776      * For Woodstox, setting this profile disables most checks for validity;
777      * specifically anything that can have measurable performance impact.
778      *
779      */

780     public void configureForSpeed()
781     {
782         doValidateAttributes(false);
783         doValidateContent(false);
784         doValidateNames(false);
785
786         // Structural validation is cheap: can be left enabled (if already so)
787         //doValidateStructure(false);
788     }
789
790     /*
791     /////////////////////////////////////////////////////
792     // Buffer recycling:
793     /////////////////////////////////////////////////////
794      */

795
796     /**
797      * Method called to allocate intermediate recyclable copy buffers
798      */

799     public char[] allocMediumCBuffer(int minSize)
800     {
801         if (mCurrRecycler != null) {
802             char[] result = mCurrRecycler.getMediumCBuffer(minSize);
803             if (result != null) {
804                 return result;
805             }
806         }
807         return new char[minSize];
808     }
809
810     public void freeMediumCBuffer(char[] buffer)
811     {
812         // Need to create (and assign) the buffer?
813         if (mCurrRecycler == null) {
814             mCurrRecycler = createRecycler();
815         }
816         mCurrRecycler.returnMediumCBuffer(buffer);
817     }
818
819     public char[] allocFullCBuffer(int minSize)
820     {
821         if (mCurrRecycler != null) {
822             char[] result = mCurrRecycler.getFullCBuffer(minSize);
823             if (result != null) {
824                 return result;
825             }
826         }
827         return new char[minSize];
828     }
829
830     public void freeFullCBuffer(char[] buffer)
831     {
832         // Need to create (and assign) the buffer?
833         if (mCurrRecycler == null) {
834             mCurrRecycler = createRecycler();
835         }
836         mCurrRecycler.returnFullCBuffer(buffer);
837     }
838
839     public byte[] allocFullBBuffer(int minSize)
840     {
841         if (mCurrRecycler != null) {
842             byte[] result = mCurrRecycler.getFullBBuffer(minSize);
843             if (result != null) {
844                 return result;
845             }
846         }
847         return new byte[minSize];
848     }
849
850     public void freeFullBBuffer(byte[] buffer)
851     {
852         // Need to create (and assign) the buffer?
853         if (mCurrRecycler == null) {
854             mCurrRecycler = createRecycler();
855         }
856         mCurrRecycler.returnFullBBuffer(buffer);
857     }
858
859     private BufferRecycler createRecycler()
860     {
861         BufferRecycler recycler = new BufferRecycler();
862         // No way to reuse/reset SoftReference, have to create new always:
863         mRecyclerRef.set(new SoftReference<BufferRecycler>(recycler));
864         return recycler;
865     }
866
867     /*
868     //////////////////////////////////////////////////////////
869     // Internal methods
870     //////////////////////////////////////////////////////////
871      */

872
873     private void setConfigFlag(int flag, boolean state) {
874         if (state) {
875             mConfigFlags |= flag;
876         } else {
877             mConfigFlags &= ~flag;
878         }
879     }
880
881     private final boolean hasConfigFlag(int flag) {
882         return ((mConfigFlags & flag) == flag);
883     }
884
885     private final Object getSpecialProperty(int ix)
886     {
887         if (mSpecialProperties == null) {
888             return null;
889         }
890         return mSpecialProperties[ix];
891     }
892
893     private final void setSpecialProperty(int ix, Object value)
894     {
895         if (mSpecialProperties == null) {
896             mSpecialProperties = new Object[SPEC_PROC_COUNT];
897         }
898         mSpecialProperties[ix] = value;
899     }
900 }
901