content: /*
   * Copyright (c) 2001-2008 Caucho Technology, Inc.  All rights reserved.
   *
   * The Apache Software License, Version 1.1
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Caucho Technology (http://www.caucho.com/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
   *    endorse or promote products derived from this software without prior
   *    written permission. For written permission, please contact
   *    info@caucho.com.
   *
   * 5. Products derived from this software may not be called "Resin"
   *    nor may "Resin" appear in their names without prior written
   *    permission of Caucho Technology.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
   * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * @author Scott Ferguson
   */
  
  package com.caucho.hessian.io;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Date;
  
  /**
   * Serializing an object for known object types.
   */
  public class BasicDeserializer extends AbstractDeserializer {
    public static final int NULL = BasicSerializer.NULL;
    public static final int BOOLEAN = BasicSerializer.BOOLEAN;
    public static final int BYTE = BasicSerializer.BYTE;
    public static final int SHORT = BasicSerializer.SHORT;
    public static final int INTEGER = BasicSerializer.INTEGER;
    public static final int LONG = BasicSerializer.LONG;
    public static final int FLOAT = BasicSerializer.FLOAT;
    public static final int DOUBLE = BasicSerializer.DOUBLE;
    public static final int CHARACTER = BasicSerializer.CHARACTER;
    public static final int CHARACTER_OBJECT = BasicSerializer.CHARACTER_OBJECT;
    public static final int STRING = BasicSerializer.STRING;
    public static final int DATE = BasicSerializer.DATE;
    public static final int NUMBER = BasicSerializer.NUMBER;
    public static final int OBJECT = BasicSerializer.OBJECT;
    
    public static final int BOOLEAN_ARRAY = BasicSerializer.BOOLEAN_ARRAY;
    public static final int BYTE_ARRAY = BasicSerializer.BYTE_ARRAY;
    public static final int SHORT_ARRAY = BasicSerializer.SHORT_ARRAY;
    public static final int INTEGER_ARRAY = BasicSerializer.INTEGER_ARRAY;
    public static final int LONG_ARRAY = BasicSerializer.LONG_ARRAY;
    public static final int FLOAT_ARRAY = BasicSerializer.FLOAT_ARRAY;
    public static final int DOUBLE_ARRAY = BasicSerializer.DOUBLE_ARRAY;
    public static final int CHARACTER_ARRAY = BasicSerializer.CHARACTER_ARRAY;
    public static final int STRING_ARRAY = BasicSerializer.STRING_ARRAY;
    public static final int OBJECT_ARRAY = BasicSerializer.OBJECT_ARRAY;
  
    private int _code;
  
    public BasicDeserializer(int code)
    {
      _code = code;
    }
  
    public Class getType()
    {
      switch (_code) {
      case NULL:
        return void.class;
      case BOOLEAN:
        return Boolean.class;
      case BYTE:
        return Byte.class;
      case SHORT:
        return Short.class;
      case INTEGER:
        return Integer.class;
      case LONG:
        return Long.class;
      case FLOAT:
        return Float.class;
      case DOUBLE:
        return Double.class;
      case CHARACTER:
        return Character.class;
      case CHARACTER_OBJECT:
        return Character.class;
      case STRING:
        return String.class;
      case DATE:
        return Date.class;
      case NUMBER:
        return Number.class;
      case OBJECT:
        return Object.class;
  
      case BOOLEAN_ARRAY:
        return boolean[].class;
      case BYTE_ARRAY:
        return byte[].class;
      case SHORT_ARRAY:
        return short[].class;
      case INTEGER_ARRAY:
        return int[].class;
      case LONG_ARRAY:
        return long[].class;
      case FLOAT_ARRAY:
        return float[].class;
      case DOUBLE_ARRAY:
        return double[].class;
      case CHARACTER_ARRAY:
        return char[].class;
      case STRING_ARRAY:
        return String[].class;
      case OBJECT_ARRAY:
        return Object[].class;
      default:
        throw new UnsupportedOperationException();
      }
    }
    
    public Object readObject(AbstractHessianInput in)
      throws IOException
    {
      switch (_code) {
      case NULL:
        // hessian/3490
        in.readObject();
        
        return null;
        
      case BOOLEAN:
        return Boolean.valueOf(in.readBoolean());
        
      case BYTE:
        return Byte.valueOf((byte) in.readInt());
        
      case SHORT:
        return Short.valueOf((short) in.readInt());
        
      case INTEGER:
        return Integer.valueOf(in.readInt());
  
      case LONG:
        return Long.valueOf(in.readLong());
  
      case FLOAT:
        return Float.valueOf((float) in.readDouble());
  
      case DOUBLE:
        return Double.valueOf(in.readDouble());
        
      case STRING:
        return in.readString();
        
      case OBJECT:
        return in.readObject();
        
      case CHARACTER:
        {
          String s = in.readString();
          if (s == null || s.equals(""))
            return Character.valueOf((char) 0);
          else
            return Character.valueOf(s.charAt(0));
        }
        
      case CHARACTER_OBJECT:
        {
          String s = in.readString();
          if (s == null || s.equals(""))
            return null;
          else
            return Character.valueOf(s.charAt(0));
        }
        
      case DATE:
        return new Date(in.readUTCDate());
        
      case NUMBER:
        return in.readObject();
  
      case BYTE_ARRAY:
        return in.readBytes();
  
      case CHARACTER_ARRAY:
      {
        String s = in.readString();
  
        if (s == null)
          return null;
        else {
          int len = s.length();
          char []chars = new char[len];
          s.getChars(0, len, chars, 0);
          return chars;
        }
      }
  
      case BOOLEAN_ARRAY:
      case SHORT_ARRAY:
      case INTEGER_ARRAY:
      case LONG_ARRAY:
      case FLOAT_ARRAY:
      case DOUBLE_ARRAY:
      case STRING_ARRAY:
      {
        int code = in.readListStart();
  
        switch (code) {
        case 'N':
          return null;
  
        case 0x10: case 0x11: case 0x12: case 0x13:
        case 0x14: case 0x15: case 0x16: case 0x17:
        case 0x18: case 0x19: case 0x1a: case 0x1b:
        case 0x1c: case 0x1d: case 0x1e: case 0x1f:
          int length = code - 0x10;
          in.readInt();
  
          return readLengthList(in, length);
  
        default:
          String type = in.readType();
          length = in.readLength();
  
          return readList(in, length);
        }
      }
  
      default:
        throw new UnsupportedOperationException();
      }
    }
    
    public Object readList(AbstractHessianInput in, int length)
      throws IOException
    {
      switch (_code) {
      case BOOLEAN_ARRAY: {
        if (length >= 0) {
          boolean []data = new boolean[length];
  
          in.addRef(data);
  
          for (int i = 0; i < data.length; i++)
            data[i] = in.readBoolean();
  
          in.readEnd();
  
          return data;
        }
        else {
          ArrayList list = new ArrayList();
  
          while (! in.isEnd())
            list.add(Boolean.valueOf(in.readBoolean()));
  
          in.readEnd();
  
          boolean []data = new boolean[list.size()];
          
          in.addRef(data);
          
          for (int i = 0; i < data.length; i++)
            data[i] = ((Boolean) list.get(i)).booleanValue();
  
          return data;
        }
      }
      
      case SHORT_ARRAY: {
        if (length >= 0) {
          short []data = new short[length];
  
          in.addRef(data);
          
          for (int i = 0; i < data.length; i++)
            data[i] = (short) in.readInt();
  
          in.readEnd();
  
          return data;
        }
        else {
          ArrayList list = new ArrayList();
  
          while (! in.isEnd())
            list.add(Short.valueOf((short) in.readInt()));
  
          in.readEnd();
  
          short []data = new short[list.size()];
          for (int i = 0; i < data.length; i++)
            data[i] = ((Short) list.get(i)).shortValue();
  
          in.addRef(data);
          
          return data;
        }
      }
      
      case INTEGER_ARRAY: {
        if (length >= 0) {
          int []data = new int[length];
  
          in.addRef(data);
          
          for (int i = 0; i < data.length; i++)
            data[i] = in.readInt();
  
          in.readEnd();
  
          return data;
        }
        else {
          ArrayList list = new ArrayList();
  
          while (! in.isEnd())
            list.add(Integer.valueOf(in.readInt()));
  
  
          in.readEnd();
  
          int []data = new int[list.size()];
          for (int i = 0; i < data.length; i++)
            data[i] = ((Integer) list.get(i)).intValue();
          
          in.addRef(data);
  
          return data;
        }
      }
      
      case LONG_ARRAY: {
        if (length >= 0) {
          long []data = new long[length];
  
          in.addRef(data);
  
          for (int i = 0; i < data.length; i++)
            data[i] = in.readLong();
  
          in.readEnd();
  
          return data;
        }
        else {
          ArrayList list = new ArrayList();
  
          while (! in.isEnd())
            list.add(Long.valueOf(in.readLong()));
  
          in.readEnd();
          
          long []data = new long[list.size()];
          for (int i = 0; i < data.length; i++)
            data[i] = ((Long) list.get(i)).longValue();
          
          in.addRef(data);
  
          return data;
        }
      }
      
      case FLOAT_ARRAY: {
        if (length >= 0) {
          float []data = new float[length];
          in.addRef(data);
  
          for (int i = 0; i < data.length; i++)
            data[i] = (float) in.readDouble();
  
          in.readEnd();
  
          return data;
        }
        else {
          ArrayList list = new ArrayList();
  
          while (! in.isEnd())
            list.add(new Float(in.readDouble()));
  
          in.readEnd();
          
          float []data = new float[list.size()];
          for (int i = 0; i < data.length; i++)
            data[i] = ((Float) list.get(i)).floatValue();
          
          in.addRef(data);
  
          return data;
        }
      }
      
      case DOUBLE_ARRAY: {
        if (length >= 0) {
          double []data = new double[length];
          in.addRef(data);
  
          for (int i = 0; i < data.length; i++)
            data[i] = in.readDouble();
  
          in.readEnd();
  
          return data;
        }
        else {
          ArrayList list = new ArrayList();
  
          while (! in.isEnd())
            list.add(new Double(in.readDouble()));
  
          in.readEnd();
          
          double []data = new double[list.size()];
          in.addRef(data);
          for (int i = 0; i < data.length; i++)
            data[i] = ((Double) list.get(i)).doubleValue();
  
          return data;
        }
      }
      
      case STRING_ARRAY: {
        if (length >= 0) {
          String []data = new String[length];
          in.addRef(data);
  
          for (int i = 0; i < data.length; i++)
            data[i] = in.readString();
  
          in.readEnd();
  
          return data;
        }
        else {
          ArrayList list = new ArrayList();
  
          while (! in.isEnd())
            list.add(in.readString());
  
          in.readEnd();
          
          String []data = new String[list.size()];
          in.addRef(data);
          for (int i = 0; i < data.length; i++)
            data[i] = (String) list.get(i);
  
          return data;
        }
      }
      
      case OBJECT_ARRAY: {
        if (length >= 0) {
          Object []data = new Object[length];
          in.addRef(data);
  
          for (int i = 0; i < data.length; i++)
            data[i] = in.readObject();
  
          in.readEnd();
  
          return data;
        }
        else {
          ArrayList list = new ArrayList();
          
          in.addRef(list); // XXX: potential issues here
  
          while (! in.isEnd())
            list.add(in.readObject());
  
          in.readEnd();
          
          Object []data = new Object[list.size()];
          for (int i = 0; i < data.length; i++)
            data[i] = (Object) list.get(i);
  
          return data;
        }
      }
      
      default:
        throw new UnsupportedOperationException(String.valueOf(this));
      }
    }
    
    public Object readLengthList(AbstractHessianInput in, int length)
      throws IOException
    {
      switch (_code) {
      case BOOLEAN_ARRAY: {
        boolean []data = new boolean[length];
  
        in.addRef(data);
  
        for (int i = 0; i < data.length; i++)
          data[i] = in.readBoolean();
  
        return data;
      }
      
      case SHORT_ARRAY: {
        short []data = new short[length];
  
        in.addRef(data);
          
        for (int i = 0; i < data.length; i++)
          data[i] = (short) in.readInt();
  
        return data;
      }
      
      case INTEGER_ARRAY: {
        int []data = new int[length];
  
        in.addRef(data);
          
        for (int i = 0; i < data.length; i++)
          data[i] = in.readInt();
  
        return data;
      }
      
      case LONG_ARRAY: {
        long []data = new long[length];
  
        in.addRef(data);
          
        for (int i = 0; i < data.length; i++)
          data[i] = in.readLong();
  
        return data;
      }
      
      case FLOAT_ARRAY: {
        float []data = new float[length];
        in.addRef(data);
  
        for (int i = 0; i < data.length; i++)
          data[i] = (float) in.readDouble();
  
        return data;
      }
      
      case DOUBLE_ARRAY: {
        double []data = new double[length];
        in.addRef(data);
  
        for (int i = 0; i < data.length; i++)
          data[i] = in.readDouble();
  
        return data;
      }
      
      case STRING_ARRAY: {
        String []data = new String[length];
        in.addRef(data);
  
        for (int i = 0; i < data.length; i++)
          data[i] = in.readString();
  
        return data;
      }
      
      case OBJECT_ARRAY: {
        Object []data = new Object[length];
        in.addRef(data);
  
        for (int i = 0; i < data.length; i++)
          data[i] = in.readObject();
  
        return data;
      }
      
      default:
        throw new UnsupportedOperationException(String.valueOf(this));
      }
    }
    
    public String toString()
    {
      return getClass().getSimpleName() + "[" + _code + "]";
    }
  }
  