2005/5/9

     
 

CDRObjectWriter.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/CDRObjectWriter.cpp,v 1.26 2005/04/21 08:28:52 kommer Exp $

#include "CDRObjectWriter.h"
#include "ServerDelegate.h"
#include "CorObject.h"
#include "acdk2orb.h"

#include <org/omg/CORBA/portable/Delegate.h>
#include <org/omg/CORBA/portable/ObjectImpl.h>
#include <acdkx/orb/AcdkObject.h>
#include <acdk/util/logging/Log.h>
#include <acdk/text/Format.h>

namespace acdkx {
namespace orb {

using ::acdk::io::AbstractFilterWriter;

using namespace ::acdk::lang::dmi;


CDRObjectWriter::CDRObjectWriter(IN(RWriter) out, IN(org::omg::CORBA::RORB) orb)
: AbstractFilterWriter(out)
, _index(0)
, _orb(orb)
{

}



RInputStream 
CDRObjectWriter::create_input_stream() //### implement
{
  _throwNotImplementedYet("CDRObjectWriter::create_input_stream");
  return Nil;
}

//virtual 
void
CDRObjectWriter::writeBoolean(bool b)
{
  //ACDK_LOG(Debug, RString("bool=[") +  b + "]");
  if (b == true)
    writeChar(1);
  else
    writeChar(0);
}

//virtual 
void
CDRObjectWriter::writeChar(char b)
{
  //ACDK_LOG(Debug, RString("char=[") +  (short)b + "]");
  write(b);
}
 
void 
CDRObjectWriter::writeUcChar(uc2char b)
{
  writeShort(b);
}

//virtual 
void
CDRObjectWriter::writeShort(short value)
{
  //ACDK_LOG(Debug, RString("short=[") +  value + "]");
  _checkAlignment(2);
  byte buffer[3];
  buffer[2] = 0;
  short* sp = (short*)buffer;
  CDRSWAP2(value);
  *sp = value;
  write(buffer, 0, 2);
}
  
//virtual 
void
CDRObjectWriter::writeInt(int value)
{
  //ACDK_LOG(Debug, RString("int=[") +  value + "]");
  _checkAlignment(4);
  byte buffer[5];
  buffer[4] = 0;
  int* sp = (int*)buffer;
  CDRSWAP4(value);
  *sp = value;
  write(buffer, 0, 4);
}

//virtual 
void
CDRObjectWriter::writeLong(jlong value)
{
  //ACDK_LOG(Debug, RString("jlong=[") +  value + "]");
  _checkAlignment(8);
  byte buffer[9];
  buffer[8] = 0;
  jlong* sp = (jlong*)buffer;
  CDRSWAP8(value);
  *sp = value;
  write(buffer, 0, 8);
}
 
//virtual 
void
CDRObjectWriter::writeFloat(float value)
{
  //ACDK_LOG(Debug, RString("float=[") +  value + "]");
  _checkAlignment(4);
  byte buffer[5];
  buffer[4] = 0;
  float* sp = (float*)buffer;
  CDRSWAP4(value);
  *sp = value;
  write(buffer, 0, 4);
}
 
//virtual 
void
CDRObjectWriter::writeDouble(double value)
{
  //ACDK_LOG(Debug, RString("double=[") +  value + "]");
  _checkAlignment(8);
  byte buffer[9];
  buffer[8] = 0;
  double* sp = (double*)buffer;
  CDRSWAP8(value);
  *sp = value;
  write(buffer, 0, 8);
}

  

//virtual 
void
CDRObjectWriter::writeString(IN(RString) str)
{
  write_long(str->length() + 1);
  //ACDK_LOG(Debug, RString("string=[") +  str + "]");
  write((const byte*)str->c_str(), 0, str->length());
  write_octet(0); // 0-terminierung
}

//foreign virtual 
void 
CDRObjectWriter::write_char_array(const char* value, int offset, int length)
{
  //ACDK_LOG(Debug, "charray=[" + acdk::text::Format::hexToString(value + offset, length) + "]");
  write((const byte*)value, offset, length);
}



// virtual
void
CDRObjectWriter::write(const byte* cstr, int offset, int len)
{
  _index += len;
  _out->write(cstr, offset, len);
}

void 
CDRObjectWriter::write(byte c)
{
  _index += 1;
  _out->write(c);
}

//virtual 
void 
CDRObjectWriter::write(IN(RbyteArray) ch, int offset/* = 0*/, int len/* = -1*/)
{
  if (len == -1)
    _index += ch->length() - offset;
  else
    _index += len;
  _out->write(ch, offset, len);
}




void 
CDRObjectWriter::_checkAlignment(int align)
{
  int remainder = align - (_index % align);
  byte data = 0;
  if (remainder != align) {
    for (int i = remainder; i > 0; i--)
      _out->write(data);
    _index += remainder;
  }
}

void 
CDRObjectWriter::write_repid(IN(::acdk::lang::RObject) obj)
{
  write_string("IDL:" + obj->getClass()->getName() + ":1.0");
}

void 
CDRObjectWriter::write_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)
    write_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 ((fi->flags & MiStatic) || (fi->flags & MiFiTransient))
      continue;
    if (isEx == true &&  fi->equalsName("_what") == false)
      continue;
    ScriptVar sv = obj->getMember(fi->name, CorObject::_dmiClient, 0);
    writeValueParam(*this, sv, fi->type, 0, 0);
  }
}

void 
CDRObjectWriter::write_struct(IN(::acdk::lang::RObject) obj, bool withParents)
{
  write_struct(obj, obj->getClazzInfo(), withParents);
}

void 
CDRObjectWriter::write_exception(IN(RThrowable) ex)
{
  
  if (instanceof(ex, ::org::omg::CORBA::SystemException) == true) 
  {
    ::org::omg::CORBA::RSystemException sysex(ex);
    write_string(ex->getClass()->getName());
    write_long(sysex->minor());
    write_long(sysex->completed());
  } 
  else 
  { 
    write_repid(ex);
    write_struct(ex, true);
  }
}


//virtual 
void 
CDRObjectWriter::write_acdk_object(IN(::acdk::lang::RObject) value)
{
  //ACDK_LOG(Debug, RString("obj=[") +  value + "]");
  if (value == Nil) {
    write_value((::acdk::io::RSerializable)value);
    return;
  }
  if (instanceof(value, ::org::omg::CORBA::Object) == true) 
  {
    write_Object(::org::omg::CORBA::RObject(value));
    return;
  }
  if (instanceof(value, String) == true) 
  {
    write_string(RString(value));
    return;
  }
  if (value->getClass()->hasMetaAttribute("acdkx_orb_StructType") == true)
  {
    //write_repid(value);
    write_struct(value);
    return;
  }
  if (instanceof(value, ::acdk::io::Serializable) == true ||
      instanceof(value, ::acdk::lang::Throwable) ||
      value->getClass()->isArray() == true) 
  {
    writeObject(value);
    return;
  }
  
  
  write_Object(new AcdkObject(value));
  //write_fq_object(value, 0);
  //THROW3_FQ(::org::omg::CORBA::, MARSHAL, value->getClass()->getName(), 5, ::org::omg::CORBA::COMPLETED_NO);
}

//virtual 
void 
CDRObjectWriter::write_Object(IN(::org::omg::CORBA::RObject) value) 
{
  ::org::omg::CORBA::portable::RDelegate d = Nil;
  if (instanceof(value, ::org::omg::CORBA::portable::ObjectImpl) == true) {
    RServerDelegate(::org::omg::CORBA::portable::RObjectImpl(value)->_get_delegate())->write(*this);
    return;
  }
  THROW0_FQ(::org::omg::CORBA::, NO_IMPLEMENT);
}

//foreign virtual 
void 
CDRObjectWriter::write_abstract_interface(IN(::acdk::lang::RObject) obj)
{
  if (instanceof(obj, ::org::omg::CORBA::portable::ObjectImpl) == true)
    write_Object(::org::omg::CORBA::RObject(obj));
  else
    write_Object(new AcdkObject(obj));
}

  // 2.3
//virtual 
void 
CDRObjectWriter::write_value(IN(::acdk::io::RSerializable) value) 
{
  writeObject((acdk::lang::Object)value);
}


//virtual 
void 
CDRObjectWriter::writeObject(IN(RClass) cls, IN(acdk::lang::Object) obj)
{
  acdk::lang::Object::_throwNotImplementedYet("CDRObjectWriter::writeObject(RClass cls, acdk::lang::Object obj))"); // ## implement 
}

void
CDRObjectWriter::writeObject(IN(acdk::lang::Object) obj)
{
  if (obj == Nil) {
    write_string("Nil");
    return;
  }
  RClass theClass = obj->getClass();
  //doen't, because reader doesn't expect meta info write_string(theClass->getName());
  ::acdk::lang::dmi::SysFields members = obj->getInternalFields(MiNonStatic);
  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: 
      continue;
    case SysField::FT_Bool: write_boolean(*f.cont.bval); break;
    case SysField::FT_Char : write_octet(*f.cont.cval);  break;
    case SysField::FT_UcChar : write_short(*f.cont.ucval);  break;
    case SysField::FT_Byte : write_octet(*f.cont.cval);  break;
    case SysField::FT_Short : write_short(*f.cont.sval);  break;
    case SysField::FT_Int : write_long((int)*f.cont.ival);  break;
    case SysField::FT_JLong : write_longlong(*f.cont.jlval);  break;
    case SysField::FT_Float : write_float(*f.cont.fval);  break;
    case SysField::FT_Double : write_float(*f.cont.dval);  break;
    case SysField::FT_Object : {
      acdk::lang::Object cobj = f.cont.oval->impl();
      if (instanceof(cobj, String) == true)
        write_string((RString)cobj);
      else  
        write_acdk_object(cobj);
      break;
    }
    }
  }
}

//foreign virtual 
void 
CDRObjectWriter::writeScriptVar(acdk::lang::dmi::ScriptVar& sv, bool withTypeInfo, bool withFlags)
{
  // ####
}

using ::acdk::lang::dmi::ScriptVar;
using ::org::omg::CORBA::portable::CallerWrite;
using ::org::omg::CORBA::portable::CalleeRead;
using ::org::omg::CORBA::portable::CalleeWrite;
using ::org::omg::CORBA::portable::CallerRead;

int scriptVarFlags2GiopFlags(int flags)
{
  int giopflags = 0;
  if (flags & MiAiByref)
    giopflags |= DmiGiopIsReference;
  if (flags & MiAiByval)
    giopflags |= DmiGiopIsSerialized;
  return giopflags;
}


//virtual 
void 
CDRObjectWriter::write_scriptVar(IN(ScriptVar) sv, ParamCallDirection dir)
{
  //ACDK_LOG(Debug, RString("scriptVar=[") +  sv.toCode() + "]");
  if (dir == CalleeWrite) {
    if ((sv.flags & MiAiOut) != MiAiOut)
      return;
  }
  write_long(sv.type);
  write_long(sv.flags);
  
  if (dir == CallerWrite) {
    if ((sv.flags & MiAiIn) != MiAiIn)
      return;
  }

  switch (sv.type)
  {
  case ScriptVar::UnknownType:

    break;
  case ScriptVar::BoolRefType:
  case ScriptVar::BoolType:
    write_boolean(sv.getBoolVar());
    break;
  case ScriptVar::CharRefType:
  case ScriptVar::CharType:
    write_char(sv.getCharVar());
    break;
  case ScriptVar::ByteRefType:
  case ScriptVar::ByteType:
    write_octet(sv.getCharVar());
    break;
  case ScriptVar::ShortRefType:
  case ScriptVar::ShortType:
    write_short(sv.getShortVar());
    break;
  case ScriptVar::IntRefType:
  case ScriptVar::IntType:
    write_long(sv.getIntVar());
    break;
  case ScriptVar::LongRefType:
  case ScriptVar::LongType: // i64
    write_longlong(sv.getLongVar());
    break;
  case ScriptVar::FloatRefType:  
  case ScriptVar::FloatType:
    write_float(sv.getFloatVar());
    break;
  case ScriptVar::DoubleRefType:
  case ScriptVar::DoubleType:
    write_double(sv.getDoubleVar());
    break;
  case ScriptVar::ObjectRefType:
  case ScriptVar::ObjectType:
  {
    write_fq_object(sv.getObjectVar(), scriptVarFlags2GiopFlags(sv.flags));
    break;
  }
  default:
    break;
  }
}

void 
CDRObjectWriter::write_fq_object(IN(acdk::lang::Object) obj, int flags)
{
  //ACDK_LOG(Debug, RString("fq_object=[") +  obj->toString() + "]");
  if (obj == Nil)
  {
    write_long(DmiGiopIsNil);
    return;
  }
  if (instanceof(obj, ::acdk::lang::String) == true)
  {
    write_long(DmiGiopIsString);
    write_string((RString)obj);
    return;
  }
  // ### wrong, using hint in flags
  if ((flags & DmiGiopIsReference) == 0 && 
      (flags & DmiGiopIsSerialized ||
      instanceof(obj, ::acdk::io::Serializable) == true || 
       instanceof(obj, ::acdk::lang::Throwable) ||
       obj->getClass()->isArray() == true)
      ) 
  {
    write_long(DmiGiopIsSerialized);
    write_string(obj->getClass()->getName());
    writeObject(obj);
    return;
  } 
  else 
  {
    write_long(DmiGiopIsReference);
    if (instanceof(obj, ::org::omg::CORBA::Object) == true) 
    {
      write_Object(::org::omg::CORBA::RObject(obj));
    } else {
      write_Object(new AcdkObject(obj));
    }
  }
}



} // namespace orb 
} // namespace acdkx