2005/5/9

     
 

CDRObjectReader.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.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdkx_orb/src/acdkx/orb/CDRObjectReader.cpp,v 1.30 2005/04/21 08:28:52 kommer Exp $
#include "CDRObjectReader.h"
#include "ObjectKey.h"
#include "AORB.h"
#include "ServerDelegate.h"
#include "acdk2orb.h"
#include <acdk/util/logging/Log.h>
#include <acdk/text/Format.h>
#include <acdk/io/EOFException.h>
#include <org/omg/CORBA/OrbExceptions.h>
#include <org/omg/CORBA/portable/InvokeHandler.h>

namespace acdkx {
namespace orb {

USING_CLASS(::acdk::io::, EOFException);

using namespace acdk::lang::dmi;

CDRObjectReader::CDRObjectReader(IN(RReader) in, IN(org::omg::CORBA::RORB) orb)
: ACDK_FQ_SUPER_QUALIFIER(::acdk::io::, AbstractFilterReader)(in),
  _index(0)
{
}
 
//virtual 
int 
CDRObjectReader::read()
{
  int erg = ACDK_FQ_SUPER_QUALIFIER(::acdk::io::, AbstractFilterReader)::read();
  if (erg != -1)
    ++_index;
  return erg;
}

//virtual 
int 
CDRObjectReader::read(IN(RbyteArray) buffer, int offset/* = 0*/, int len/* = -1*/)
{
  int erg = ACDK_FQ_SUPER_QUALIFIER(::acdk::io::, AbstractFilterReader)::read(buffer, offset, len);
  if (erg != -1)
    _index += erg;
  return erg;
}


//virtual 
int 
CDRObjectReader::read(byte* buffer, int offset, int len)
{
  int erg = ACDK_FQ_SUPER_QUALIFIER(::acdk::io::, AbstractFilterReader)::read(buffer, offset, len);
  if (erg != -1)
    _index += erg;
  return erg;
}


//virtual 
bool 
CDRObjectReader::readBoolean()
{
  char c = readChar();
  //ACDK_LOG(Debug, RString("bool<[") +  c + "]");
  if (c == 1)
    return true;
  return false;
}

//virtual 
char 
CDRObjectReader::readChar()
{
  char c = (unsigned char)read();
  //ACDK_LOG(Debug, RString("char<[") +  (short)c + "]");
  return c;
}

uc2char 
CDRObjectReader::readUcChar()
{
  return readShort();
}
  
#define READBUFFER(size) \
  _checkAlignment(size); \
  byte buffer[size]; \
  if (read(buffer, 0, size) != size) \
    throw REOFException(new EOFException())

//virtual 
double 
CDRObjectReader::readDouble()
{
  READBUFFER(8);
  double retval = *(double*)buffer;
  CDRSWAP8(retval);
  //ACDK_LOG(Debug, RString("double<[") +  retval + "]");
  return retval;
}

//virtual 
float 
CDRObjectReader::readFloat()
{
  READBUFFER(4);
  float retval = *(float*)buffer;
  CDRSWAP4(retval);
  //ACDK_LOG(Debug, RString("float<[") +  retval + "]");
  return retval;
}

//virtual 
int 
CDRObjectReader::readInt()
{
  READBUFFER(4);
  int retval = *(int*)buffer;
  CDRSWAP4(retval);
  //ACDK_LOG(Debug, RString("int<[") +  retval + "]");
  return retval;
}

//virtual 
jlong 
CDRObjectReader::readLong()
{
  READBUFFER(8);
  jlong retval = *(jlong*)buffer;
  CDRSWAP8(retval);
  //ACDK_LOG(Debug, RString("jlong<[") +  retval + "]");
  return retval;
}

//virtual 
short 
CDRObjectReader::readShort()
{
  READBUFFER(2);
  short retval = *(short*)buffer;
  CDRSWAP2(retval);
  //ACDK_LOG(Debug, RString("short<[") +  retval + "]");
  return retval;
}

//virtual 
RString 
CDRObjectReader::readString()
{
  int size = read_long();
  if (size == 0)
    THROW1(Exception, RString("Buffer must be greater as 0"));
  if (size > 1024 * 1024)
    THROW1(Exception, RString("Buffer probably too big: ") + size);
  
  RString str = new String(size + 1); // ### FIXME unicode
  char* ptr = const_cast<char*>(str->c_str());
  read_char_array(ptr, 0, size);
  ptr[size - 1] = 0;
  str->_setEnd((byte*)ptr + size - 1);
  
  //ACDK_LOG(Debug, RString("string<[") +  str + "]");
  return str;  
}

//virtual 
acdk::lang::Object 
CDRObjectReader::readObject()
{
  THROW0_FQ(::org::omg::CORBA::, NO_IMPLEMENT);
  return Nil;
}

using ::acdk::lang::reflect::Modifier;
using ::acdk::lang::dmi::SysField;


#define CDR_READ_ARRAY(Char, char, octet) \
if (elci == ClazzInfo::get##Char##Clazz()) \
{ \
  R##char##Array arr = new char##Array(count); \
  for (int i = 0; i < count; ++i) \
    arr[i] = read_##octet(); \
  return &arr; \
}


//virtual 
::acdk::lang::RObject 
CDRObjectReader::readObject(IN(::acdk::lang::RClass) theClass)
{
  RClass theRealClass = theClass; //Class::forName(theRealClassname);
  
  if (theRealClass == String::GetClass())
    return &read_string();
  const ClazzInfo* ci = theRealClass->objectClazzInfo();
  
  if (theRealClass->isArray() == true) 
  {
    const ClazzInfo* elci = ci->getElementClazzInfo();
    RClass elcls = Class::getSingeltonClass(elci);
    int count = read_long();
    if (elci->isBasicClazz() == true)
    {
      CDR_READ_ARRAY(Bool, bool, boolean)
      CDR_READ_ARRAY(Char, char, octet)
      CDR_READ_ARRAY(Byte, byte, octet)
      CDR_READ_ARRAY(Short, short, short)
      CDR_READ_ARRAY(Int, int, long)
      CDR_READ_ARRAY(Long, long, longlong)
      CDR_READ_ARRAY(Float, float, float)
      CDR_READ_ARRAY(Double, double, float)
      // ### TODO handle wchar
      // ### TODO THROW unknonw basic type
    }
    else
    {
      RObjectArray tobj;
      if (elci->array_creator != 0)
        tobj = (RObjectArray)elci->array_creator(count);
      else
        tobj = (ObjectArray*)new ObjectArrayBase(elci, count);
      ObjectArray* ta = reinterpret_cast<ObjectArray*>(&tobj);
      for (int i = 0; i < count; ++i)
      {
        if (elci == String::clazzInfo())
          ta->set(i, &read_string());
        else
          ta->set(i, read_acdk_object(elcls));
      }
      return ta;
    }
  }
  acdk::lang::Object newObj = theRealClass->newInstance();
  
  ::acdk::lang::dmi::SysFields members = newObj->getInternalFields(MiNonStatic);
  /*bool hasChild = members.size() > 0; */
  for (int i = 0; i < members.size(); i++) 
  {
    ::acdk::lang::dmi::SysField& f = members[i];
    if (f.fieldInfo->flags & MiStatic)
      continue;
    switch (f.type) {
    case SysField::FT_Void: break;
    case SysField::FT_Bool: *f.cont.bval = read_boolean(); break;
    case SysField::FT_Char : *f.cont.cval = read_octet();  break;
    case SysField::FT_UcChar: *f.cont.ucval = read_short();  break;
    case SysField::FT_Byte : *f.cont.cval= read_octet();  break;
    case SysField::FT_Short : *f.cont.sval = read_short();  break;
   
    case SysField::FT_Int : *f.cont.ival = read_long();  break;
    case SysField::FT_JLong : *f.cont.jlval = read_longlong();  break;
    case SysField::FT_Float : *f.cont.fval = read_float();  break;
    case SysField::FT_Double : *f.cont.dval = read_float();  break;
    case SysField::FT_Object : {
      RClass member = Class::getSingeltonClass(f.fieldInfo->type);
      if (member == String::GetClass())
        f.set((acdk::lang::Object)read_string());
      else
        f.set(readObject(member));
      break;
    }
    }
  }
  return newObj;
}

//foreign virtual 
acdk::lang::dmi::ScriptVar 
CDRObjectReader::readScriptVar(bool withTypeInfo, bool withFlags)
{
  // ### implement me
  return acdk::lang::dmi::ScriptVar();
}

void 
CDRObjectReader::_checkAlignment(int align)
{
  int remainder = align - (_index % align);
  char data;
  if (remainder != align) {
    for (int i = remainder; i > 0; i--) {
      int erg = _in->read();
      if (erg == -1)
        return;
    }
    _index += remainder;
  }
  
}

//virtual 
void 
CDRObjectReader::read_char_array(char* value, int offset, int length) 
{ 
  int erg = read((byte*)value, offset, length);
  //ACDK_LOG(Debug, "charray<[" + acdk::text::Format::hexToString(value + offset, length) + "]");
}


//virtual 
::acdk::lang::RObject 
CDRObjectReader::read_acdk_object(IN(::acdk::lang::RClass) clz)
{
  if (clz == String::GetClass())
    return &read_string();
  if (::org::omg::CORBA::Object::GetClass()->isAssignableFrom(clz) == true ||
      ::org::omg::CORBA::portable::InvokeHandler::GetClass()->isAssignableFrom(clz) == true )
    return (::acdk::lang::RObject)read_Object();
  if (clz->hasMetaAttribute("acdkx_orb_StructType") == true)
  {
    acdk::lang::Object tobj = clz->newInstance();
    read_struct(tobj);
    return tobj;
  }
  if (clz->isArray() == true)
    return readObject(clz);
  return (::acdk::lang::RObject)read_Object();
  
  //THROW3_FQ(::org::omg::CORBA::, MARSHAL, clz->getName(), 5, ::org::omg::CORBA::COMPLETED_NO);
  //return Nil;
  
  //return (::acdk::lang::RObject)read_Object();
   /*
  if (::acdk::io::Serializable::GetClass()->isAssignableFrom(clz) == true ||
      ::acdk::lang::Throwable::GetClass()->isAssignableFrom(clz) == true ||
      clz->isArray() == true)
    return readObject(clz);
  
  
  */
  /* not used
  RObjectKey objectkey = new ObjectKey();
  objectkey->ior.read(*this);
  objectkey->ior_inited = true;
  objectkey->fromIOR();
  if (objectkey->isLocal() == true) {
    RServerDelegate serverobj(objectkey->localObject);
    return &serverobj;
  }
  return &AORB::createProxy(objectkey);
  */
  /*THROW0_FQ(::org::omg::CORBA::, NO_IMPLEMENT);
  return Nil;*/
}

//virtual 
::org::omg::CORBA::RObject 
CDRObjectReader::read_Object()
{
  return &ServerDelegate::read(*this, Nil);
  
}

//virtual 
::org::omg::CORBA::RObject 
CDRObjectReader::read_Object(IN(::acdk::lang::RClass) clz)
{
  return &ServerDelegate::read(*this, clz);
}

//foreign virtual 
::acdk::lang::RObject 
CDRObjectReader::read_abstract_interface() 
{
  return (::acdk::lang::RObject)read_Object();
}

//foreign virtual 
::acdk::lang::RObject 
CDRObjectReader::read_abstract_interface(IN(::acdk::lang::RClass) clz) 
{
  if (clz == Nil || clz->isAssignableFrom(::org::omg::CORBA::Object::GetClass()) == true)
    return (::acdk::lang::RObject)read_Object();
  THROW3_FQ(::org::omg::CORBA::, MARSHAL, clz->getName(), 5, ::org::omg::CORBA::COMPLETED_NO);
  return Nil;
}

using ::acdk::lang::dmi::ScriptVar;


#define READ_VALUES() ((dir != CalleeRead) || ((flags & MiAiIn) == MiAiIn))

//virtual 
void 
CDRObjectReader::read_scriptVar(OUT(::acdk::lang::dmi::ScriptVar) sv, ParamCallDirection dir)
{
  if (dir == CallerRead) {
    if ((sv.flags & MiAiOut) != MiAiOut)
      return;
  }
  int type = read_long();
  int flags = read_long();
  switch (type)
  {
  case ScriptVar::UnknownType:
    // Nothing
    sv = ScriptVar();
    break;
  case ScriptVar::BoolRefType:
  case ScriptVar::BoolType:
    if (READ_VALUES())
      sv = read_boolean();
    else
      sv = false;
    break;
  case ScriptVar::CharRefType:
  case ScriptVar::CharType:
    if (READ_VALUES())
      sv = read_char();
    else
      sv = (char)0;
    break;
  case ScriptVar::ByteRefType:
  case ScriptVar::ByteType:
    if (READ_VALUES())
      sv = read_octet(); 
    else
      sv = (byte)0;
    break;
  case ScriptVar::ShortRefType:
  case ScriptVar::ShortType:
    if (READ_VALUES())
      sv = read_short();
    else
      sv = (short)0;
    break;
  case ScriptVar::IntRefType:
  case ScriptVar::IntType:
    if (READ_VALUES())
      sv = read_long();
    else
      sv = (int)0;
    break;
  case ScriptVar::LongRefType:
  case ScriptVar::LongType: // i64
    if (READ_VALUES())
      sv = read_longlong();
    else
      sv = (jlong)0;
    break;
  case ScriptVar::FloatRefType:  
  case ScriptVar::FloatType:
    if (READ_VALUES())
      sv = read_float();
    else
      sv = (float)0.0;
    break;
  case ScriptVar::DoubleRefType:
  case ScriptVar::DoubleType:
    if (READ_VALUES())
      sv = read_double(); 
    else
      sv = (double)0.0;
    break;
  case ScriptVar::ObjectRefType:
    if (READ_VALUES())
      sv.setOwnObjectReference(read_fq_object(flags));
    else
      sv.setOwnObjectReference();
    break;
  case ScriptVar::ObjectType:
  {
    if (READ_VALUES())
    {
      sv = read_fq_object(flags);
    } else
      sv = acdk::lang::Object();
    break;
  }
  default:
    break;
  }
  sv.flags = flags;
}

acdk::lang::Object 
CDRObjectReader::read_fq_object(int flags)
{
  int sflags = read_long();
  
  if ((sflags & DmiGiopIsNil) == DmiGiopIsNil)
    return Nil;

  if ((sflags & DmiGiopIsString) == DmiGiopIsString)
    return &readString();
  if ((sflags & DmiGiopIsSerialized) == DmiGiopIsSerialized)
  {
    RString cname = read_string();
    RClass cls = Class::forName(cname);
    return readObject(cls);
  } 
  if ((sflags & DmiGiopIsReference) == DmiGiopIsReference)
  {
    return (acdk::lang::Object)read_Object();
  }
  // ### ex
  return Nil;
}


void 
CDRObjectReader::read_struct(IN(::acdk::lang::RObject) obj, const ::acdk::lang::dmi::ClazzInfo* ci, bool withParents)
{
  if (withParents == true && 
      ci != Throwable::clazzInfo()  &&
      ci != ::org::omg::CORBA::SystemException::clazzInfo() &&  
      ci != ::org::omg::CORBA::OrbException::clazzInfo() &&  
      ci->interfaces[0] != 0)
    read_struct(obj, ci->interfaces[0]->type, withParents);
  ci = ci->loadFullClazzInfo();
  bool isEx = ci == Throwable::clazzInfo();
  
  for (int i = 0; i < ci->getFieldsCount(); ++i)
  {
    const acdk::lang::dmi::ClazzFieldInfo* fi = ci->fields[i];
    if (MetaInfo::isStatic(fi->flags) == true ||
          fi->flags & MiFiTransient)
      continue;
    if (isEx == true &&  fi->equalsName("_what") == false)
      continue;
    ScriptVar sv;
    readValueParam(*this, sv, fi->type, 0, 0);
    obj->setMember(fi->name, sv, CorObject::_dmiClient, 0);
    
  }
}

void 
CDRObjectReader::read_struct(IN(acdk::lang::Object) obj, bool withParents)
{
  read_struct(obj, obj->getClazzInfo(), withParents);
}

RThrowable 
CDRObjectReader::read_exception()
{
  try {
    RString exname = read_string();
    if (exname->startsWith("IDL:") == true)
    {
      RString clsname = exname->substr(4);
      clsname = clsname->substr(0, clsname->lastIndexOf(":"));
      RClass cls = Class::forName(ObjectKey::classNameFromRepId(clsname));

      RThrowable ex = (RThrowable)cls->newInstance();
      read_struct(&ex, true);
      return ex;
    } 
    else
    {
      RClass cls = Class::forName(exname);
      int minor = read_long();
      int completed = read_long();
      ::org::omg::CORBA::RSystemException ex = (::org::omg::CORBA::RSystemException)cls->newInstance();
      ex->minor(minor);
      ex->completed(completed);
      return (RThrowable)&ex;
    }
  } 
  catch (RThrowable ex)
  {
    return new ::org::omg::CORBA::UNKNOWN();
  }
  return Nil; // ### implement
}

} // namespace orb 
} // namespace acdkx