Package com.jaxo.mozutil

Source Code of com.jaxo.mozutil.Json$Tokenizer$Exception

/*
* (C) Copyright 2013 Jaxo Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0.  If a copy of the MPL was not distributed with this
* file, you can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author:  Pierre G. Richard
* Written: 4/21/2013
*/
package com.jaxo.mozutil;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/*-- class Json --+
*//**
* This class implements a JSON parser / generator (decode / encode).
* It's a strict interpretation of RFC 4627.
* Monolithic, lightweight, no rings and bells: good enough is good enough.
*
* @author  Pierre G. Richard
*/
public class Json
{
   /** A Json.Root is a Json.Object or a Json.Array */
   public static interface Root {
   }

   /** A Json.Object holds a list of Json.Members */
   public static class Object implements Root {
      public List<Member> members;
      Object() { members = new ArrayList<Member>(); }
   }

   /** A Json.Member is a pair of name, value
   * - a name is a Java String
   * - a value is a Java Object, out of:
   *   null, String, Long, Double, Boolean, Json.Object, Json.Array.
   */
   public static class Member extends AbstractMap.SimpleEntry<String, java.lang.Object> {
      private static final long serialVersionUID = 1L;
      Member(String name, java.lang.Object value) { super(name, value); }
   }

   /** A Json.Array holds a list of values
   *  A value is a Java Object, out of:
   *  null, String, Long, Double, Boolean, Json.Object, Json.Array.
   */
   public static class Array implements Root {
      public List<java.lang.Object> values;
      Array() { values = new Vector<java.lang.Object>(); }
   }

   /*-------------------------------------------------------------------parse-+
   *//**
   * Construct a Json.Root from reading JSON text off a Reader
   *
   * @param in Reader of the JSON text.
   * @return a Json.Root
   * @exception Exception if syntax errors were found
   *//*
   +-------------------------------------------------------------------------*/
   public static Root parse(Reader in) throws Exception {
      Tokenizer tokenizer = new Tokenizer(in);
      Root root;
      java.lang.Object token = tokenizer.nextToken();
      if (token == Tokenizer.BEGIN_OBJECT) {
         root = parseObject(tokenizer);
      }else if (token == Tokenizer.BEGIN_ARRAY) {
         root = parseArray(tokenizer);
      }else {
         throw tokenizer.new Exception("'[' or '{' expected");
      }
      if (tokenizer.nextToken() != Tokenizer.EOF) {
         throw tokenizer.new Exception("Extraneous data found");
      }
      return root;
   }

   /*----------------------------------------------------------------generate-+
   *//**
   * Generate JSON text from a Json.ROOT
   *
   * @param root the Json.Root to generate the JSON text from
   * @param out Writer for the resulting JSON Text.
   * @exception Exception if the Json.Root is invalid
   *//*
   +-------------------------------------------------------------------------*/
   public static void generate(Root root, Writer out) throws Exception {
      if (root instanceof Object) {
         generate((Object)root, out);
      }else if (root instanceof Array) {
         generate((Array)root, out);
      }else {
         throw new Exception("Not a JSON Root");
      }
   }

   private static class Tokenizer
   {
      private Reader m_in;
      private int m_chBack;
      private int m_ofs;
      public static final Character BEGIN_ARRAY = '[';
      public static final Character BEGIN_OBJECT = '{';
      public static final Character END_ARRAY = ']';
      public static final Character END_OBJECT = '}';
      public static final Character NAME_SEPARATOR = ':';
      public static final Character VALUE_SEPARATOR = ',';
      public static final Character EOF = '\uFFFF';

      public Tokenizer(Reader in) {
         m_chBack = -1;
         m_in = new FilterReader(in) {
            public int read() throws IOException {
               if (m_chBack != -1) {
                  int ch = m_chBack;
                  m_chBack = -1;
                  return ch;
               }else {
                  ++m_ofs;
                  return super.read();
               }
            }
         };
      }

      public java.lang.Object nextToken() throws Exception, IOException {
         int ch;
         while ((ch=m_in.read()) != -1) {
            switch (ch) {
            case ' ':
            case '\r':
            case '\n':
            case '\t':
               continue;
            case '[': return BEGIN_ARRAY;
            case ']': return END_ARRAY;
            case '{': return BEGIN_OBJECT;
            case '}': return END_OBJECT;
            case ':': return NAME_SEPARATOR;
            case ',': return VALUE_SEPARATOR;
            case 't':
               if ((m_in.read() == 'r') && (m_in.read() == 'u') && (m_in.read() == 'e')) {
                  return Boolean.TRUE;
               }
               break;
            case 'f':
               if ((m_in.read() == 'a') &&  (m_in.read() == 'l') &&  (m_in.read() == 's') &&  (m_in.read() == 'e')) {
                  return Boolean.FALSE;
               }
               break;
            case 'n':
               if ((m_in.read() == 'u') && (m_in.read() == 'l') && (m_in.read() == 'l')) {
                  return null;
               }
               break;
            case '"':
               return getStringValue();
            default:
               return getNumberValue(ch); // Double or Long
            }
         }
         return EOF;
      }

      private java.lang.Object getNumberValue(int ch) throws Exception, IOException
      {
         int ofs = m_ofs;
         if (((ch >= '0') && (ch <= '9')) || (ch == '-')) {
            StringBuilder sb = new StringBuilder(30);
            do {
               sb.append((char)ch);
            }while (((ch=m_in.read()) != -1) && (" ,\n\r\t]}".indexOf(ch) == -1));
            m_chBack = ch;
            String val = sb.toString();
            try {
               return new Long(Long.parseLong(val));
            }catch (java.lang.Exception e) {
               try {
                  return new Double(Double.parseDouble(val));
               }catch (java.lang.Exception e2) {}
            }
         }
         throw new Exception("Invalid token", ofs);
      }

      private String getStringValue() throws Exception, IOException
      {
         StringBuilder sb = new StringBuilder();
         int ofs = m_ofs;
         int ch;
         while ((ch=m_in.read()) != -1) {
            switch (ch) {
            case '\"':
               return sb.toString();
            case '\\':
               if ((ch=m_in.read()) == -1) {
                  throw new Exception("Quote not ended", ofs);
               }
               switch (ch) {
               case '\"':
               case '\\':
               case '/':
                  sb.append((char)ch);
                  break;
               case 'b':
                  sb.append('\b');
                  break;
               case 'f':
                  sb.append('\f');
                  break;
               case 'r':
                  sb.append('\r');
                  break;
               case 'n':
                  sb.append('\n');
                  break;
               case 't':
                  sb.append('\t');
                  break;
               case 'u':
                  {
                     int val = 0;
                     for (int i=0; i < 4; ++i) {
                        if ((ch=m_in.read()) == -1) {
                           throw new Exception("Quote not ended", ofs);
                        }
                        if ((ch <= '9') && (ch >= '0')) {
                           val = (val << 4) + (ch & 0xF);
                        }else if (((ch=(char)((ch & ~('a'-'A'))-'A')) < (char)6)) {
                           val += (val << 4) + (ch + 10);
                        }else {
                           throw new Exception("Invalid hex digits", m_ofs-i);
                        }
                     }
                     sb.append((char)val);
                  }
                  break;
               }
               break;
            default:
               if (ch < ' ') throw new Exception("Invalid character");
               sb.append((char)ch);
            }
         }
         throw new Exception("Quote not ended", m_ofs);
      }

      private class Exception extends java.lang.Exception {
         private static final long serialVersionUID = 1L;
         Exception(String reason) {
            this(reason, m_ofs);
         }
         Exception(String reason, int pos) {
            super(reason + " at offset " + pos);
         }
      }
   }

   private static Object parseObject(Tokenizer t) throws Exception {
      Object obj = new Object();
      java.lang.Object name = t.nextToken();
      if (name != Tokenizer.END_OBJECT) {
         for (;;) {
            if (name instanceof String) {
               if (t.nextToken() == Tokenizer.NAME_SEPARATOR) {
                  java.lang.Object value = t.nextToken();
                  if (
                     (value == null) ||
                     (value instanceof Double) ||
                     (value instanceof Long) ||
                     (value instanceof String) ||
                     (value instanceof Boolean)
                  ) {
                     obj.members.add(new Member((String)name, value));
                  }else if (value == Tokenizer.BEGIN_OBJECT) {
                     obj.members.add(new Member((String)name, parseObject(t)));
                  }else if (value == Tokenizer.BEGIN_ARRAY) {
                     obj.members.add(new Member((String)name, parseArray(t)));
                  }else {
                     throw new Exception("Value expected");
                  }
                  if ((value = t.nextToken()) == Tokenizer.VALUE_SEPARATOR) {
                     name = t.nextToken();
                  }else if (value != Tokenizer.END_OBJECT) {
                     throw new Exception("Value separator expected");
                  }else {
                     break;
                  }
               }else {
                  throw new Exception("Name separator expected");
               }
            }else {
               throw new Exception("Name expected");
            }
         }
      }
      return obj;
   }

   private static Array parseArray(Tokenizer t) throws Exception {
      Array array = new Array();
      java.lang.Object value = t.nextToken();
      if (value != Tokenizer.END_ARRAY) {
         for (;;) {
            if (
               (value == null) ||
               (value instanceof Double) ||
               (value instanceof Long) ||
               (value instanceof String) ||
               (value instanceof Boolean)
            ) {
               array.values.add(value);
            }else if (value == Tokenizer.BEGIN_OBJECT) {
               array.values.add(parseObject(t));
            }else if (value == Tokenizer.BEGIN_ARRAY) {
               array.values.add(parseArray(t));
            }else {
               throw new Exception("Value expected");
            }
            if ((value = t.nextToken()) == Tokenizer.VALUE_SEPARATOR) {
               value = t.nextToken();
            }else if (value != Tokenizer.END_ARRAY) {
               throw new Exception("Value separator expected");
            }else {
               break;
            }
         }
      }
      return array;
   }

   private static void generate(Object parent, Writer out) throws IOException {
      out.write(Tokenizer.BEGIN_OBJECT);
      boolean isContinuation = false;
      for (Member member : parent.members) {
         if (isContinuation) {
            out.write(Tokenizer.VALUE_SEPARATOR);
         }else {
            isContinuation = true;
         }
         generateString(member.getKey(), out);
         out.write(Tokenizer.NAME_SEPARATOR);
         generateValue(member.getValue(), out);
      }
      out.write(Tokenizer.END_OBJECT);
   }

   private static void generate(Array parent, Writer out) throws IOException {
      out.write(Tokenizer.BEGIN_ARRAY);
      boolean isContinuation = false;
      for (java.lang.Object value : parent.values) {
         if (isContinuation) {
            out.write(Tokenizer.VALUE_SEPARATOR);
         }else {
            isContinuation = true;
         }
         generateValue(value, out);
      }
      out.write(Tokenizer.END_ARRAY);
   }

   private static void generateValue(java.lang.Object value, Writer out) throws IOException {
      if (value == null) {
         out.write("null");
      }else if (
         (value instanceof Double) ||
         (value instanceof Long) ||
         (value instanceof Boolean)
      ) {
         out.write(value.toString());
      }else if (value instanceof String) {
         generateString((String)value, out);
      }else if (value instanceof Object) {
         generate((Object)value, out);
      }else if (value instanceof Array) {
         generate((Array)value, out);
      }
   }

   private static void generateString(String s, Writer out) throws IOException {
      out.write("\"" + s.replace("\\", "\\\\").replace("\"", "\\\"") + "\"");
   }
}
/*===========================================================================*/ 
TOP

Related Classes of com.jaxo.mozutil.Json$Tokenizer$Exception

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.