gt:                     if ( ch == quoteChar ) {
context: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.jena.atlas.json.io ;
  
  import static org.apache.jena.atlas.lib.Chars.CH_QUOTE1 ;
  import static org.apache.jena.atlas.lib.Chars.CH_QUOTE2 ;
  import static org.apache.jena.atlas.lib.Chars.CH_ZERO ;
  
  import java.io.OutputStream ;
  import java.math.BigDecimal ;
  import java.util.ArrayDeque ;
  import java.util.Deque ;
  
  import org.apache.jena.atlas.io.IndentedLineBuffer ;
  import org.apache.jena.atlas.io.IndentedWriter ;
  import org.apache.jena.atlas.lib.BitsInt ;
  import org.apache.jena.atlas.lib.Chars ;
  import org.apache.jena.atlas.lib.Ref ;
  
  /**
   * A low level streaming JSON writer - assumes correct sequence of calls (e.g.
   * keys in objects). Useful when writing JSON directly from some other structure
   */
  
  public class JSWriter {
      protected IndentedWriter out = IndentedWriter.stdout ;
  
      public JSWriter() {
          this(IndentedWriter.stdout) ;
      }
  
      public JSWriter(OutputStream ps) { this(new IndentedWriter(ps)) ; }
  
      public JSWriter(IndentedWriter ps) { out = ps ; }
  
      public void startOutput() {}
  
      public void finishOutput() { out.flush() ; }
  
      // These apply in nested and flat modes (the difference is controlled by the
      // IndentedWriter
  
      public static final String ArrayStart    = "[ " ;
      public static final String ArrayFinish   = " ]" ;
      public static final String ArraySep      = ", " ;
  
      public static final String ObjectStart   = "{ " ;
      public static final String ObjectFinish  = "}" ;
      public static final String ObjectSep     = " ," ;
      public static final String ObjectPairSep = " : " ;
  
      // Remember whether we are in the first element of a compound 
      // (object or array).
      Deque<Ref<Boolean>> stack = new ArrayDeque<Ref<Boolean>>() ;
  
      public void startObject() {
          startCompound() ;
          out.print(ObjectStart) ;
          out.incIndent() ;
      }
  
      public void finishObject() {
          out.decIndent() ;
          if ( isFirst() )
              out.print(ObjectFinish) ;
          else {
              out.ensureStartOfLine() ;
              out.println(ObjectFinish) ;
          }
          finishCompound() ;
      }
  
      public void key(String key) {
          if ( isFirst() ) {
              out.println() ;
              setNotFirst() ;
          } else
              out.println(ObjectSep) ;
          value(key) ;
          out.print(ObjectPairSep) ;
          // Ready to start the pair value.
      }
  
      // "Pair" is the name used in the JSON spec.
      public void pair(String key, String value) {
          key(key) ;
          value(value) ;
      }
  
      public void pair(String key, boolean val) {
          key(key) ;
          value(val) ;
      }
  
      public void pair(String key, long val) {
          key(key) ;
          value(val) ;
      }
      
      public void pair(String key, Number val) {
          key(key) ;
          value(val) ;
      }
  
      public void startArray() {
          startCompound() ;
          out.print(ArrayStart) ;
          // Messy with objects out.incIndent() ;
      }
  
      public void finishArray() {
          // out.decIndent() ;
          out.print(ArrayFinish) ; // Leave on same line.
          finishCompound() ;
      }
  
      public void arrayElement(String str) {
          arrayElementProcess() ;
          value(str) ;
      }
  
      private void arrayElementProcess() {
          if ( isFirst() )
              setNotFirst() ;
          else
              out.print(ArraySep) ;
      }
  
      public void arrayElement(boolean b) {
          arrayElementProcess() ;
          value(b) ;
      }
  
      public void arrayElement(long integer) {
          arrayElementProcess() ;
          value(integer) ;
      }
  
      /**
       * Useful if you are manually creating arrays and so need to print array
       * separators yourself
       */
      public void arraySep() {
          out.print(ArraySep) ;
      }
  
      public static String outputQuotedString(String string) {
          IndentedLineBuffer b = new IndentedLineBuffer() ;
          outputQuotedString(b, string) ;
          return b.asString() ;
      }
  
      /*
       * Output a JSON string with escaping. 
       * \" \\ \/ \b \f \n \r \t control
       * characters (def?) \ u four-hex-digits 
       */
      public static void outputQuotedString(IndentedWriter out, String string) {
          outputQuotedString(out, string, false) ;
      }
  
      /*
       * Output a JSON string with escaping. Optionally allow base words (unquoted
       * strings) which, for member names, is legal javascript but not legal JSON.
       * The Jena JSON parser accepts them.
       */
      public static void outputQuotedString(IndentedWriter out, String string, boolean allowBareWords) {
          char quoteChar = CH_QUOTE2 ;
          int len = string.length() ;
  
          if ( allowBareWords ) {
              boolean safeBareWord = true ;
              if ( len != 0 )
                  safeBareWord = isA2Z(string.charAt(0)) ;
  
              if ( safeBareWord ) {
                  for (int i = 1; i < len; i++) {
                      char ch = string.charAt(i) ;
                      if ( isA2ZN(ch) )
                          continue ;
                      safeBareWord = false ;
                      break ;
                  }
              }
              if ( safeBareWord ) {
                  // It's safe as a bare word in JavaScript.
                  out.print(string) ;
                  return ;
              }
          }
  
          if ( allowBareWords )
              quoteChar = CH_QUOTE1 ;
  
          out.print(quoteChar) ;
          for (int i = 0; i < len; i++) {
              char ch = string.charAt(i) ;
              if ( ch == quoteChar ) {
                  esc(out, quoteChar) ;
                  continue ;
              }
  
              switch (ch) {
              // Done in default. Only \" is legal JSON.
              // case '"': esc(out, '"') ; break ;
              // case '\'': esc(out, '\'') ; break ;
                  case '\\' :
                      esc(out, '\\') ;
                      break ;
                  case '/' :
                      // Avoid </ which confuses if it's in HTML (this is from
                      // json.org)
                      if ( i > 0 && string.charAt(i - 1) == '<' )
                          esc(out, '/') ;
                      else
                          out.print(ch) ;
                      break ;
                  case '\b' :
                      esc(out, 'b') ;
                      break ;
                  case '\f' :
                      esc(out, 'f') ;
                      break ;
                  case '\n' :
                      esc(out, 'n') ;
                      break ;
                  case '\r' :
                      esc(out, 'r') ;
                      break ;
                  case '\t' :
                      esc(out, 't') ;
                      break ;
                  default :
  
  