]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/parser/DataValuePrinter.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / parser / DataValuePrinter.java
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/parser/DataValuePrinter.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/parser/DataValuePrinter.java
new file mode 100644 (file)
index 0000000..d515e38
--- /dev/null
@@ -0,0 +1,837 @@
+/*******************************************************************************\r
+ *  Copyright (c) 2010 Association for Decentralized Information Management in\r
+ *  Industry THTH ry.\r
+ *  All rights reserved. This program and the accompanying materials\r
+ *  are made available under the terms of the Eclipse Public License v1.0\r
+ *  which accompanies this distribution, and is available at\r
+ *  http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ *  Contributors:\r
+ *      VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.parser;
+
+import java.io.IOException;\r
+\r
+import org.simantics.databoard.binding.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.BooleanBinding;\r
+import org.simantics.databoard.binding.ByteBinding;\r
+import org.simantics.databoard.binding.DoubleBinding;\r
+import org.simantics.databoard.binding.FloatBinding;\r
+import org.simantics.databoard.binding.IntegerBinding;\r
+import org.simantics.databoard.binding.LongBinding;\r
+import org.simantics.databoard.binding.MapBinding;\r
+import org.simantics.databoard.binding.OptionalBinding;\r
+import org.simantics.databoard.binding.RecordBinding;\r
+import org.simantics.databoard.binding.StringBinding;\r
+import org.simantics.databoard.binding.UnionBinding;\r
+import org.simantics.databoard.binding.VariantBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.error.RuntimeBindingException;\r
+import org.simantics.databoard.binding.mutable.MutableVariant;\r
+import org.simantics.databoard.file.RuntimeIOException;\r
+import org.simantics.databoard.parser.repository.DataTypeRepository;\r
+import org.simantics.databoard.parser.repository.DataValueRepository;\r
+import org.simantics.databoard.type.Component;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.databoard.type.RecordType;\r
+import org.simantics.databoard.type.UnionType;\r
+
+/**
+ * A class that converts values to their text presentation.
+ * 
+ * Refereable records are printed after their name. The name is checked
+ * from a data value repository. If the record doesn't exist, a name is 
+ * made up and an entry is added. 
+ * 
+ * Names of referable record objects are acquired from a data values repository.
+ * If object is not in the repository, it is added. 
+ * 
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public class DataValuePrinter implements Binding.Visitor1 {
+
+       Appendable out;
+       int indentLevel = 0;
+       PrintFormat format = PrintFormat.SINGLE_LINE;
+       int nameCounter = 1;
+       DataValueRepository repo;       
+       Object root;
+
+       /**
+        * Serialize value to a single line text string
+        * 
+        * @param type
+        * @param value
+        * @return the print
+        * @throws IOException
+        * @throws BindingException
+        */
+       public static String writeValueSingleLine(Binding type, Object value)
+                       throws IOException, BindingException {
+               StringBuffer sb = new StringBuffer();
+               DataValuePrinter writable = new DataValuePrinter(sb, new DataValueRepository());
+               writable.setFormat(PrintFormat.SINGLE_LINE);
+               writable.print(type, value);
+               return sb.toString();
+       }
+
+       /**
+        * Write value to one or more lines
+        * 
+        * @param type
+        * @param value
+        * @return the print
+        * @throws IOException
+        * @throws BindingException
+        */
+       public static String writeValueMultiLine(Binding type, Object value)
+                       throws IOException, BindingException {
+               StringBuffer sb = new StringBuffer();
+               DataValuePrinter writable = new DataValuePrinter(sb, new DataValueRepository());
+               writable.setFormat(PrintFormat.MULTI_LINE);
+               writable.print(type, value);
+               return sb.toString();
+       }
+
+       public DataValuePrinter(Appendable out, DataValueRepository valueRepository) {
+               setOutput(out);
+               this.repo = valueRepository;
+       }
+       
+       public DataValueRepository getValueRepository() {
+               return repo;
+       }
+       
+       public DataTypeRepository getTypeRepository() {
+               return repo.getTypeRepository();
+       }
+
+       public void setOutput(Appendable out) {
+               this.out = out;
+       }
+
+       public void setFormat(PrintFormat format) {
+               if (format == null)
+                       throw new IllegalArgumentException("null arg");
+               this.format = format;
+       }
+
+       public void print(MutableVariant variant) throws IOException,
+       BindingException {
+               print(variant.getBinding(), variant.getValue());
+       }
+       
+       public void print(Binding binding, Object instance) throws IOException,
+                       BindingException {
+               try {
+                       root = instance;
+                       binding.accept(this, instance);
+               } catch (RuntimeIOException e) {
+                       throw e.getCause();
+               } catch (RuntimeBindingException e) {
+                       throw e.getCause();
+               } finally {
+                       root = null;
+               }
+       }
+
+       @Override
+       public void visit(ArrayBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       Binding cb = b.getComponentBinding();
+                       if (instance == null) {
+                               out.append(format.openArray);
+                               out.append(format.closeArray);
+                               return;
+                       }
+                       int len = b.size(instance);
+                       out.append(format.openArray);
+                       for (int i = 0; i < len; i++) {
+                               Object component = b.get(instance, i);\r
+                               if (component == null)\r
+                                       out.append("null");\r
+                               else
+                                       cb.accept(this, component);
+                               
+                               if (i < len - 1) {\r
+                                       out.append(format.arraySeparator);\r
+                                       out.append(' ');\r
+                               }\r
+                       }
+                       out.append(format.closeArray);
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               }
+       }
+
+       @Override
+       public void visit(BooleanBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       boolean value = b.getValue_(instance);
+                       out.append(value ? format.True : format.False);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               }
+       }
+
+       @Override
+       public void visit(DoubleBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       out.append(b.getValue(instance).toString());
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               }
+       }
+
+       @Override
+       public void visit(FloatBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       out.append(b.getValue(instance).toString());
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               }
+       }
+
+       @Override
+       public void visit(IntegerBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       out.append(b.getValue(instance).toString());
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               }
+       }
+
+       @Override
+       public void visit(ByteBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       out.append(b.getValue(instance).toString());
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               }
+       }
+
+       @Override
+       public void visit(LongBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       out.append(b.getValue(instance).toString());
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               }
+       }
+
+       @Override
+       public void visit(OptionalBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               if (!b.hasValueUnchecked(instance))
+                       try {
+                               out.append(format.Null);
+                               return;
+                       } catch (IOException e) {
+                               throw new RuntimeIOException(e);
+                       }
+
+               try {
+                       instance = b.getValue(instance);
+                       b.getComponentBinding().accept(this, instance);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               }
+       }
+
+       /**
+        * Create a new unique name that doesn't exist in the value repository.
+        * 
+        * @return new name 
+        */
+       String createNewName() {
+               String name;
+               do {
+                       name = "obj" + (nameCounter++);
+               } while (repo.get(name)!=null);
+               return name;
+       }
+       
+       @Override
+       public void visit(RecordBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               boolean singleLine = format.newLine == null;
+               boolean tuple = b.type().isTupleType();
+               try {
+                       RecordType type = b.type();
+                       Binding[] bindings = b.getComponentBindings();
+                       Component[] components = b.type().getComponents();
+                       int len = bindings.length;
+
+                       // Has Name
+                       if (type.isReferable() && instance!=root) {
+                               String name = repo.getName(instance);
+                               if (name == null) {
+                                       name = createNewName();
+                                       repo.put(name, b, instance);
+                               }
+                               out.append(name);
+                               return;
+                       }
+                       
+                       if (tuple) {
+
+                               out.append(format.openTuple);
+                               for (int i = 0; i < len; i++) {
+                                       Binding componentBinding = bindings[i];
+                                       Object value = b.getComponent(instance, i);
+
+                                       if (i > 0) {
+                                               out.append(format.arraySeparator);
+                                       }
+
+                                       // Write object name
+                                       String name = repo.getName(value);
+                                       if (name != null) {
+                                               out.append(name);
+                                               continue;
+                                       }
+
+                                       // Write value
+                                       componentBinding.accept(this, value);
+
+                               }
+                               out.append(format.closeTuple);
+
+                       } else if (len == 0) {
+                               out.append(format.openRecord);
+                               out.append(format.closeRecord);
+                       } else if (singleLine) {
+
+                               out.append(format.openRecord);
+                               for (int i = 0; i < len; i++) {
+                                       Binding componentBinding = bindings[i];
+                                       Object value = b.getComponent(instance, i);
+
+                                       // Omit null OptionalType (Syntactic Sugar)
+                                       if (componentBinding instanceof OptionalBinding) {
+                                               OptionalBinding ob = (OptionalBinding) componentBinding;
+                                               if (!ob.hasValue(value))
+                                                       continue;
+                                       }
+
+                                       if (i > 0) {
+                                               out.append(format.arraySeparator);
+                                               out.append(' ');
+                                       }
+
+                                       String fieldName = components[i].name;
+                                       putFieldName(fieldName);
+                                       out.append(" = ");
+
+                                       // Write object name
+                                       String name = repo.getName(value);
+                                       if (name != null) {
+                                               out.append(name);
+                                       } else {
+                                               // Write value
+                                               componentBinding.accept(this, value);
+                                       }
+                               }
+                               out.append(format.closeRecord);
+
+                       } else {
+
+                               out.append(format.openRecord);
+                               putLineFeed();
+                               addIndent();
+                               try {\r
+                                       int fieldsLeft = 0;\r
+                                       for (int i = 0; i < len; i++) {\r
+                                               Binding componentBinding = bindings[i];\r
+                                               Object value = b.getComponent(instance, i);\r
+                                               if (componentBinding instanceof OptionalBinding) {\r
+                                                       OptionalBinding ob = (OptionalBinding) componentBinding;\r
+                                                       if (!ob.hasValue(value)) continue;\r
+                                               }\r
+                                               fieldsLeft++;\r
+                                       }\r
+                                       
+                                       for (int i = 0; i < len; i++) {
+                                               Binding componentBinding = bindings[i];
+                                               Object value = b.getComponent(instance, i);
+
+                                               // Omit null OptionalType (Syntactic Sugar)
+                                               if (componentBinding instanceof OptionalBinding) {
+                                                       OptionalBinding ob = (OptionalBinding) componentBinding;
+                                                       if (!ob.hasValue(value))
+                                                               continue;
+                                               }
+
+                                               putIndent();
+
+                                               String fieldName = components[i].name;
+                                               putFieldName(fieldName);
+                                               out.append(" = ");
+
+                                               // Write object name
+                                               String name = repo.getName(value);
+                                               if (name != null) {
+                                                       out.append(name);
+                                               } else {
+                                                       // Write value
+                                                       componentBinding.accept(this, value);
+                                               }
+\r
+                                               // Add "," if there are more fields
+                                               fieldsLeft--;\r
+                                               if (fieldsLeft>0)\r
+                                                       out.append(format.arraySeparator);\r
+                                               putLineFeed();
+                                       }
+
+                               } finally {
+                                       decIndent();
+                               }
+                               putIndent();
+                               out.append(format.closeRecord);
+                       }
+
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               }
+       }
+
+       @Override
+       public void visit(StringBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       boolean singleLineFormat = format.newLine == null;
+                       String unescapedString = b.getValue(instance);
+
+                       // Analyse the string
+                       boolean canUseLongString = true;
+                       boolean hasCharsToBeEscaped = false;
+//                     boolean hasCharsToBeEscaped = true;
+                       boolean hasLineFeeds = false;
+
+                       char c = 0x00;
+                       char pc = 0x00;
+                       char ppc = 0x00;
+                       for (int i = 0; i < unescapedString.length(); i++) {
+                               ppc = pc;
+                               pc = c;
+                               c = unescapedString.charAt(i);
+
+                               canUseLongString &= c != '\"' && pc != '\"' && ppc != '\"';
+
+                               switch (c) {
+                               // Backspace \b or \u0008
+                               case '\b': {
+                                       hasCharsToBeEscaped = true;
+                               }
+                                       // Form feed \f or
+                               case '\f': {
+                                       hasCharsToBeEscaped = true;
+                               }
+                                       // Backslash \\ or \u005c
+                               case '\\': {
+                                       hasCharsToBeEscaped = true;
+                               }
+                                       // Double Quote \" or \u0022
+                               case '\"': {
+                                       hasCharsToBeEscaped = true;
+                               }
+                                       // Single Quote \" or \u0027
+                               case '\'': {
+                                       hasCharsToBeEscaped = true;
+                               }
+                                       // New Line \n or\u000a
+                               case '\n': {
+                                       hasCharsToBeEscaped = true;
+                                       hasLineFeeds = true;
+                               }
+                                       // Carriage Return \r or\u000d
+                               case '\r': {
+                                       hasCharsToBeEscaped = true;
+                                       hasLineFeeds = true;
+                               }
+                                       // Tabulator \t or
+                               case '\t': {
+                                       hasCharsToBeEscaped = true;
+                               }
+                               default:
+                               }
+                       }
+
+                       // Make a selection between short and long string
+                       // Short string prints everything in a single line and can escape
+                       // anything
+                       // Long string is more readable as it doesn't have escape characters
+                       // Prefer Long string over short if there are characters to escape
+
+                       if (canUseLongString && hasCharsToBeEscaped) {
+                               if (singleLineFormat && hasLineFeeds)
+                                       putShortString(unescapedString);
+                               else
+                                       putLongString(unescapedString);
+                       } else {
+                               putShortString(unescapedString);
+                       }
+
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               }
+       }
+
+       @Override
+       public void visit(UnionBinding b, Object instance)
+                       throws RuntimeIOException, RuntimeBindingException {
+               try {
+                       UnionType datatype = (UnionType) b.type();
+                       int ordinal = b.getTag(instance);
+                       Object component = b.getValue(instance);
+                       Binding cb = b.getComponentBindings()[ordinal];
+                       // boolean isTuple = (cb instanceof RecordBinding) &&
+                       // ((RecordBinding)cb).getDataType().isTupleType();
+
+                       String tagName = datatype.components[ordinal].name;
+                       putFieldName(tagName);
+                       out.append(' ');
+                       // if (!isTuple) out.append( format.openUnion );
+                       cb.accept(this, component);
+                       // out.append( format.closeUnion );
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               }
+       }
+
+       @Override
+    public void visit(MapBinding b, Object entity) {
+       boolean singleLine = format.newLine == null;  
+       try {
+               Binding keyBinding = b.getKeyBinding();
+               Binding valueBinding = b.getValueBinding();
+               int len = b.size(entity);               
+               
+                       out.append("map ");             
+               
+                   if (len==0) {
+                       out.append(format.openRecord);
+                       out.append(format.closeRecord);
+               }
+               else if (singleLine) {
+
+                               out.append(format.openRecord);
+                               Object keys[] = b.getKeys(entity);
+                               for (int i=0; i<len; i++) {
+                                       Object key = keys[i];
+                                       Object value = b.get(entity, key);
+                               
+                               if (i>0) {
+                                       out.append(format.arraySeparator);
+                                       out.append(' ');
+                               }
+                               
+                               keyBinding.accept(this, key);
+                               out.append( " = ");
+                               
+                               // Write object name
+                               String name = repo.getName(value);
+                               if (name != null) {
+                                       out.append(name);
+                               } else {                                
+                                       // Write value
+                                       valueBinding.accept(this, value);
+                               }
+                       }                       
+                               out.append(format.closeRecord);
+                       
+               } else {
+
+                               out.append(format.openRecord);
+                               putLineFeed();
+                               addIndent();
+                               try {
+                               Object keys[] = b.getKeys(entity);
+                               for (int i=0; i<len; i++) {
+                                       Object key = keys[i];
+                                       Object value = b.get(entity, key);
+       
+                                       putIndent();
+       
+                                       keyBinding.accept(this, key);
+                                       out.append( " = ");
+                                       
+                                       // Write object name
+                                       String name = repo.getName(value);
+                                       if (name != null) {
+                                               out.append(name);
+                                       } else {                                
+                                               // Write value
+                                               valueBinding.accept(this, value);
+                                       }
+                                       
+                                       if (i<len-1)
+                                               out.append(format.arraySeparator);
+                                       putLineFeed();
+                               }                       
+
+                               } finally {
+                                       decIndent();
+                               }
+                               putIndent();
+                               out.append(format.closeRecord);
+               }
+               
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               } 
+       }
+
+       @Override
+       public void visit(VariantBinding b, Object variant) {
+               try {
+                       Binding valueBinding = b.getContentBinding(variant);
+                       Object value = b.getContent(variant, valueBinding);
+                       Datatype type = b.getContentType(variant);
+
+                       valueBinding.accept(this, value);
+
+                       out.append(" : ");
+
+                       //Binding typeBinding = Bindings.getBindingUnchecked(DataType.class);
+                       // TODO Use type name if available
+                       //typeBinding.printValue(type, out, true);
+                       out.append(type.toSingleLineString());
+
+               } catch (IOException e) {
+                       throw new RuntimeIOException(e);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               }
+       }
+
+       private void putLongString(String unescapedString) throws IOException {
+               out.append(format.openLongString);\r
+               // Escape the following characters \\ " \ \t\r
+               for (int i = 0; i < unescapedString.length(); i++) {\r
+                       char c = unescapedString.charAt(i);\r
+                       switch (c) {\r
+                       // Backspace \b or \u0008\r
+                       case '\b':\r
+                           out.append("\\b");\r
+                           break;\r
+                           // Form feed \f or\r
+                       case '\f':\r
+                           out.append("\\f");\r
+                           break;\r
+                           // Backslash \\ or \u005c\r
+                       case '\\':\r
+                           out.append("\\\\");\r
+                           break;\r
+                           // Single Quote \' or \u0027\r
+                       case '\'':\r
+                           out.append("\\\'");\r
+                           break;\r
+                           // Double Quote \" or \u0022\r
+                       case '\"':\r
+                           out.append("\\\"");\r
+                           break;\r
+                           // Tabulator \t or\r
+                       case '\t':\r
+                           out.append("\\t");\r
+                           break;\r
+                       default:\r
+                           out.append(c);\r
+                           break;\r
+                       }\r
+               }\r
+               out.append(format.closeLongString);
+       }
+
+       private void putShortString(String unescapedString) throws IOException {
+               out.append(format.openString);
+               // Escape the following characters \\ " \ \n \r \t
+               for (int i = 0; i < unescapedString.length(); i++) {
+                       char c = unescapedString.charAt(i);
+                       switch (c) {
+                       // Backspace \b or \u0008
+                       case '\b':
+                               out.append("\\b");
+                               break;
+                       // Form feed \f or
+                       case '\f':
+                               out.append("\\f");
+                               break;
+                       // Backslash \\ or \u005c
+                       case '\\':
+                               out.append("\\\\");
+                               break;
+                       // Single Quote \' or \u0027
+                       case '\'':
+                               out.append("\\\'");
+                               break;
+                       // Double Quote \" or \u0022
+                       case '\"':
+                               out.append("\\\"");
+                               break;
+                       // New Line \n or\u000a
+                       case '\n':
+                               out.append("\\n");
+                               break;
+                       // Carriage Return \r or\u000d
+                       case '\r':
+                               out.append("\\r");
+                               break;
+                       // Tabulator \t or
+                       case '\t':
+                               out.append("\\t");
+                               break;
+                       default:
+                               out.append(c);
+                               break;
+                       }
+               }
+               out.append(format.closeString);
+       }
+
+       /**
+        * Put a field name of a record type. The name is writted as a long string,
+        * if it contains " " or escapeable characters.
+        * 
+        * @param fieldName
+        * @throws IOException
+        */
+       private void putFieldName(String fieldName) throws IOException {
+               boolean hasCharsToBeEscaped = false;
+               for (int i = 0; i < fieldName.length(); i++) {
+                       char c = fieldName.charAt(i);
+                       switch (c) {
+                       case '\b':
+                               hasCharsToBeEscaped = true;
+                               break;
+                       case '\f':
+                               hasCharsToBeEscaped = true;
+                               break;
+                       case '\\':
+                               hasCharsToBeEscaped = true;
+                               break;
+                       case '\"':
+                               hasCharsToBeEscaped = true;
+                               break;
+                       case '\'':
+                               hasCharsToBeEscaped = true;
+                               break;
+                       case '\n':
+                               hasCharsToBeEscaped = true;
+                               break;
+                       case '\r':
+                               hasCharsToBeEscaped = true;
+                               break;
+                       case '\t':
+                               hasCharsToBeEscaped = true;
+                               break;
+                       default:
+                       }
+               }
+
+               if (hasCharsToBeEscaped) {
+                       out.append('\'');
+                       for (int i = 0; i < fieldName.length(); i++) {
+                               char c = fieldName.charAt(i);
+                               switch (c) {
+                               // Backspace \b or \u0008
+                               case '\b':
+                                       out.append("\\b");
+                                       break;
+                               // Form feed \f or
+                               case '\f':
+                                       out.append("\\f");
+                                       break;
+                               // Backslash \\ or \u005c
+                               case '\\':
+                                       out.append("\\\\");
+                                       break;
+                               // Double Quote \" or \u0022
+                               case '\"':
+                                       out.append("\\\"");
+                                       break;
+                               // Single Quote \' or \u0027
+                               case '\'':
+                                       out.append("\\\'");
+                                       break;
+                               // New Line \n or\u000a
+                               case '\n':
+                                       out.append("\\n");
+                                       break;
+                               // Carriage Return \r or\u000d
+                               case '\r':
+                                       out.append("\\r");
+                                       break;
+                               // Tabulator \t or
+                               case '\t':
+                                       out.append("\\t");
+                                       break;
+                               default:
+                                       out.append(c);
+                                       break;
+                               }
+                       }
+                       out.append('\'');
+               } else {
+                       out.append(fieldName);
+               }
+       }
+
+       private void putIndent() throws IOException {
+               if (format.indent == null)
+                       return;
+               for (int j = 0; j < indentLevel; j++)
+                       out.append(format.indent);
+       }
+
+       private void putLineFeed() throws IOException {
+               if (format.newLine == null)
+                       return;
+               out.append(format.newLine);
+       }
+
+       private void addIndent() {
+               if (format.indent == null)
+                       return;
+               indentLevel++;
+       }
+
+       private void decIndent() {
+               if (format.indent == null)
+                       return;
+               indentLevel--;
+       }
+
+}