2005/5/9

     
 

AbstractObjectReader.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// ALL RIGHTS RESERVED
// 
// This file is part of ACDK.
// artefaktur provides this software "as is" with express or implied warranty.
// Any commercial use of this software requires a license.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/io/AbstractObjectReader.cpp,v 1.31 2005/04/15 11:28:47 kommer Exp $

#include "AbstractObjectReader.h"
#include "ObjectStreamException.h"
#include <acdk/lang/System.h>

namespace acdk {
namespace io {

//#define LOCAL_DEBUG
#ifdef LOCAL_DEBUG
#define getDout() ::acdk::lang::System::out

#define DOUT(strexpr) \
do { \
  StringBuffer sb; \
  for (int _i = 0; _i < identlevel; ++_i) \
    sb.append(" "); \
  sb << strexpr; \
  getDout()->println(sb.toString()); \
} while (false)
#else
/FONT>
# define DOUT(str) do { } while(false)
#endif
/FONT>


#define READBASARRAY(ClassName,baseType,ShortReader) \
if (elclass == ClassName ::getTYPE()) { \
    R##baseType##Array ba = new baseType##Array(length); \
    for (int i = 0; i < length; i++) { \
      ba[i] = read##ShortReader##Element(); \
    } \
    return (acdk::lang::Object)ba; \
} \


acdk::lang::Object 
AbstractObjectReader::_readBasicArray(IN(RClass) cls, int length)
{
  RClass elclass = Class::getSingeltonClass((const dmi::ClazzInfo*)cls->objectClazzInfo()->userInfo);
  READBASARRAY(Boolean, bool, Boolean);
  READBASARRAY(Character, char, Char);
  READBASARRAY(Short, short, Short);
  READBASARRAY(Integer, int, Int);
  READBASARRAY(Long, long, Long);
  READBASARRAY(Float, float, Float);
  READBASARRAY(Double, double, Double);
  
  //READBASARRAY(Byte, byte, Byte); will be handled seperatelly
  
  return Nil;
}


namespace {
  int identlevel = 0;
  struct Incrementor { Incrementor() { ++identlevel; } ~Incrementor() { --identlevel; }  };
}

#define DOUTLEVEL() Incrementor _inlevel;



//virtual 
acdk::lang::Object 
AbstractObjectReader::readObject()
{
  try {
    acdk::lang::Object obj = readObject2(Nil);
    resetLRefs();
    return obj;
  } catch (...) {
    resetLRefs();
    throw;
  }
}

//virtual 
acdk::lang::Object 
AbstractObjectReader::readObject2()
{
  return readObject2(Nil);
}

//virtual 
acdk::lang::Object 
AbstractObjectReader::readObject(IN(::acdk::lang::RClass) cls)
{
  try {
    acdk::lang::Object obj = readObject2(cls);
    resetLRefs();
    return obj;
  } catch (...) {
    resetLRefs();
    throw;
  }
}

//virtual 
acdk::lang::Object 
AbstractObjectReader::readObject2(IN(::acdk::lang::RClass) cls)
{
  if (isTagged() == true) 
    readTagStart("acdk::lang::Object");
  acdk::lang::Object obj = _readObject(cls);
  if (isTagged() == true) 
    readTagEnd("acdk::lang::Object");
  return obj;
}

//virtual 
void 
AbstractObjectReader::defaultReadObject(IN(RClass) cls, IN(acdk::lang::Object) obj)
{
  // todo ### if SerializedObjectDescriptor is available use it
  ::acdk::lang::dmi::SysFields members = obj->getInternalFields(::acdk::lang::dmi::MiNonStatic | ::acdk::lang::dmi::MiIvDeclared, cls->objectClazzInfo());
  int membersize = members.size();
  DOUT("RO: " << cls->toString() << "membersize=" << membersize);
  for (int i = 0; i < membersize; i++) 
  {
    ::acdk::lang::dmi::SysField& f = members[i];
    if (f.fieldInfo->getMetaInfo()->isStatic() == true ||
        f.fieldInfo->isTransient() == true)
      continue;
    DOUTLEVEL();
    DOUT(RString(f.fieldInfo->name) << " type: " << f.type);
    switch (f.type) {
    case ::acdk::lang::dmi::SysField::FT_Void: // nothing
        break;
    case ::acdk::lang::dmi::SysField::FT_Bool: *f.cont.bval = readBooleanElement(); break;
    case ::acdk::lang::dmi::SysField::FT_Char : *f.cont.cval = readCharElement();  break;
    case ::acdk::lang::dmi::SysField::FT_UcChar : *f.cont.ucval = readUcCharElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Byte : *f.cont.cval = readCharElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Short : *f.cont.sval= readShortElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Int :  *f.cont.ival = readIntElement();  break;
    case ::acdk::lang::dmi::SysField::FT_JLong : *f.cont.jlval = readLongElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Float : *f.cont.fval = readFloatElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Double : *f.cont.dval = readDoubleElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Object : 
    {
      acdk::lang::Object fo = readObject2();
      if (f.fieldInfo->accessor != 0)
      {
        dmi::AcdkDmiClient dc;
        dmi::ScriptVar sv = inOf(fo);
        f.fieldInfo->accessor(obj, Nil, sv, dc, 0, 0, 0);
      }
      else
      {
        f.set(fo);
      }
      break;
    }
    }
  }
}

RClass 
AbstractObjectReader::readClassDescriptor(IN(RClass) cls)
{
  if (isNamed() == true)
    return readClassId();
  return cls;
}

void 
AbstractObjectReader::readObjectHierarchy(IN(RClass) cls, IN(acdk::lang::Object) obj)
{
  RClassArray supers = cls->getSuperClasses();
  for (int i = 1; i < supers->length(); ++i)
  {
    RClass cclass = supers[i];
    if (cclass->hasReadObject() == true) 
    {
      obj->readObject(this, cclass);
    }
    else
    {
      defaultReadObject(cclass, obj);
    }
  }
}

//virtual 
acdk::lang::Object 
AbstractObjectReader::_readObject(IN(::acdk::lang::RClass) theClass)
{
  RClass cls = theClass;
  int lref = -1;
  if (isReduced() == true) {
    lref = readObjectLocalId();
    if (lref > _lrefs.length())
    {
      THROW1(ObjectStreamException, "Inkonsitent ObjectStream (ObjectRefID is out of range)");
    }
    if (lref < _lrefs.length()) {
      DOUT("RRO: " <<  (_lrefs[lref] == Nil ? RString("<Nil>") : _lrefs[lref]->getClass()->toString()) << " lref=" << lref);

      return _lrefs[lref];
    }
  }
  if (isNamed() == false && cls == Nil)
      THROW1(ObjectStreamException, "Cannot read acdk::lang::Object without given Class");
  
  cls = readClassDescriptor(cls);
   

  if (cls == Nil) {
    _lrefs->append(acdk::lang::Object(Nil));
    DOUT("RO: " << "<NilObject>" << " lref=" << lref);
    return Nil;
  }
  DOUT("RO: " << cls->toString() << " lref=" << lref);

  acdk::lang::Object obj = cls->newInstance();
  

  if (cls->hasReadResolve() == true)
    obj = obj->readResolve();

  
  if (instanceof(obj, String) == true) 
  {
    _lrefs->append(obj);
    return (acdk::lang::Object)readString();
  }
  if (instanceof(obj, byteArray) == true)
  {
    return &readOpaque();
  }
  
  if (cls->isArray() == true) 
  {
    int elcount = readIntElement();
    if (Class::getSingeltonClass((const dmi::ClazzInfo*)cls->objectClazzInfo()->userInfo)->isPrimitive() == true) {
      acdk::lang::Object o = _readBasicArray(cls, elcount);
      _lrefs->append(o);
      return o;
    }
    ObjectArrayBase* oar = (ObjectArrayBase*)obj.iptr();
    oar->resize(elcount);
    _lrefs->append(obj);
    for (int i = 0; i < elcount; i++) 
    {
      acdk::lang::Object co = readObject2();
      oar->setElement(i, co);
    }
    return obj;
  }
  _lrefs->append(obj);

  readObjectHierarchy(cls, obj);
 /*
  // ### TODO AbstractObjectReader allow read members not by field position, but by name

  //doen't, because reader doesn't expect meta info write_string(theClass->getName());
  ::acdk::lang::dmi::SysFields members = obj->getInternalFields(::acdk::lang::dmi::MiNonStatic);
  int membersize = members.size();
  DOUT("RO: " << cls->toString() << "membersize=" << membersize);
  for (int i = 0; i < membersize; i++) 
  {
    ::acdk::lang::dmi::SysField& f = members[i];
    if (f.fieldInfo->getMetaInfo()->isStatic() == true ||
        f.fieldInfo->isTransient() == true)
      continue;
    DOUTLEVEL();
    DOUT(RString(f.fieldInfo->name) << " type: " << f.type);
    switch (f.type) {
    case ::acdk::lang::dmi::SysField::FT_Void: // nothing
        break;
    case ::acdk::lang::dmi::SysField::FT_Bool: *f.cont.bval = readBooleanElement(); break;
    case ::acdk::lang::dmi::SysField::FT_Char : *f.cont.cval = readCharElement();  break;
    case ::acdk::lang::dmi::SysField::FT_UcChar : *f.cont.ucval = readUcCharElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Byte : *f.cont.cval = readCharElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Short : *f.cont.sval= readShortElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Int :  *f.cont.ival = readIntElement();  break;
    case ::acdk::lang::dmi::SysField::FT_JLong : *f.cont.jlval = readLongElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Float : *f.cont.fval = readFloatElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Double : *f.cont.dval = readDoubleElement();  break;
    case ::acdk::lang::dmi::SysField::FT_Object : 
      *f.set(readObject2());
      break;
    }
  }
  */
  return obj;
}

//foreign virtual 
RString 
AbstractObjectReader::readString()
{
  if (joinStrings() == false)
    return readStringImpl();
  int lref = readObjectLocalId();
  /*
  for (int i = 0; i < _stringCache->length(); ++i)
  {
      DOUT("LSREF: " << i << " " << _stringCache[i]);
  }*/
  if (lref < _stringCache->length())
  {
    //Integer key(lref);
    //RString val = (RString)_stringCache->get(&key);
    RString val = _stringCache[lref];
    DOUT("CS: " << val << " sref=" << lref);
    return val;
  }
  if (lref != _stringCache->length())
    THROW1(StreamCorruptedException, "Inkonsitent ObjectStream (StringRefID is out of range)");

   RString sret = readStringImpl();
   _stringCache->append(sret);
   sret = Nil;
   sret = _stringCache[_stringCache->length() - 1];
  return sret;
}
  
using acdk::lang::dmi::ScriptVar;

//virtual 
acdk::lang::dmi::ScriptVar 
AbstractObjectReader::readScriptVar(bool withTypeInfo, bool withFlags)
{
  if (withTypeInfo == false && isTagged() == true)
    THROW1(StreamCorruptedException, "Cannot read ScriptVar from untagged String");
  
  if (withTypeInfo == false)
    THROW1(StreamCorruptedException, "Untyped ScriptVar not yet supported");

  if (isTagged() == true)  
    readTagStart("ScriptVar");

  int type = readInt();
  int flags = 0;
  if (withFlags == true)
    flags = readInt();
  
  ScriptVar erg = _readScriptVar(type, flags);
  if (isTagged() == true)  
    readTagStart("ScriptVar");
  DOUT("SC: type=" << type << ": " << erg.toString());
  return erg;
}

ScriptVar
AbstractObjectReader ::_readScriptVar(int type, int flags)
{
  
  switch (type) {
  case ScriptVar::BoolType : return ScriptVar(readBoolean(), flags);
  case ScriptVar::CharType : return ScriptVar(readChar(), flags);
  case ScriptVar::ByteType : return ScriptVar(readChar(), flags);
  case ScriptVar::ShortType : return ScriptVar(readShort(), flags);
  case ScriptVar::IntType : return ScriptVar(readInt(), flags);
  case ScriptVar::LongType : return ScriptVar(readLong(), flags);
  case ScriptVar::FloatType : return ScriptVar(readFloat(), flags);
  case ScriptVar::DoubleType : return ScriptVar(readDouble(), flags);
  case ScriptVar::ObjectType : return ScriptVar(readObject2(), flags);
  
  case ScriptVar::UnknownType: 
  default :
  {
    ScriptVar sv;
    sv.flags = flags;
    return sv;
  }
  }
}


} // io
} // acdk