/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 picoiiop - network support for picoSQL

 Copyright (C) Picosoft s.r.l. 1994-2002

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 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 GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include <stdlib.h>
#include <string.h>
#include "message.h"
#include "log.h"

static char *rcsid = "$Id: message.c,v 1.3 2002/05/06 10:23:25 picoSoft Exp $";
static char *rcsidh = message_h;
#define BUFF_ALIGNMENT 16
#define calcAlign(p,s) ((s-((p-(unsigned char *) 0)%s))&(s-1))
#define align(p,s) ((s-(p%s))&(s-1))

static CORBA_Boolean
checkEndian ()
{
   short  num = 0x3132;

   if ( ((((char *)&num)[0]) == 0x31) && ((((char *)&num)[1]) == 0x32))
      return CORBA_False;
   else
      return CORBA_True; 
}

static void
swapDouble (CORBA_Double *d)
{
   CORBA_ULong sw;
   union uu {
      CORBA_Double dbl;
      struct ss {
         CORBA_ULong w1;
         CORBA_ULong w2;
      } s;
   } *ud = (union uu*) d;
   sw = ud->s.w1;
   ud->s.w1 = ud->s.w2;
   ud->s.w2 = sw;
}

Message *
Message_new ()
{
   Message *This = (Message *)malloc(sizeof(Message));
   if (This) {
      This->phisicBuffer = malloc (Message_DEFAULT_SIZE + BUFF_ALIGNMENT - 1);
      if (This->phisicBuffer) {
         This->logicBuffer =  This->phisicBuffer +
                              calcAlign(This->phisicBuffer,BUFF_ALIGNMENT);
         This->lenBuffer = Message_DEFAULT_SIZE;
         This->unusedSpace = This->lenBuffer;
         This->currPnt = This->logicBuffer;
         memset (This->currPnt, 0, This->unusedSpace);
         This->myByteOrder = checkEndian();
      } else {
         free(This);
         This = 0;
      }
   }
   return This;
}

void
Message_delete (Message *This)
{
   if (This) {
      if (This->phisicBuffer)
         free(This->phisicBuffer);
      free(This);
   }
}

CORBA_Boolean
Message_grow (Message *This, int incr)
{
   CORBA_Boolean Return = CORBA_True;
   unsigned char *newPhisicBuffer;
   unsigned char *newLogicBuffer;

   if (incr < Message_DEFAULT_SIZE)
      incr = Message_DEFAULT_SIZE;

   newPhisicBuffer = malloc (This->lenBuffer + incr + BUFF_ALIGNMENT -1);
   if (newPhisicBuffer) {
      newLogicBuffer =  newPhisicBuffer +
                        calcAlign(newPhisicBuffer,BUFF_ALIGNMENT);
      memcpy (newLogicBuffer, This->logicBuffer, This->lenBuffer);
      free(This->phisicBuffer);
      This->phisicBuffer = newPhisicBuffer;
      This->logicBuffer = newLogicBuffer;
      This->lenBuffer += incr;
      This->unusedSpace += incr;
      This->currPnt = This->logicBuffer + (This->lenBuffer - This->unusedSpace);
      memset (This->currPnt, 0, This->unusedSpace);
   } else 
      Return = CORBA_False;
   return Return;
}

unsigned char *
Message_getBuffer (Message *This, unsigned int reqLen, CORBA_Boolean byteOrd)
{
   This->msgByteOrder = byteOrd;
   if (reqLen > This->lenBuffer &&
        Message_grow (This, reqLen - This->lenBuffer) == CORBA_False)
      return (unsigned char *) 0;
   return This->logicBuffer;
}

CORBA_Octet *
Message_skipBytes (Message *This, unsigned int nBytes)
{
   CORBA_Octet *Return;
   if (This->unusedSpace < nBytes &&
       Message_grow (This, nBytes - This->unusedSpace) == CORBA_False)
      Return = (CORBA_Octet *) 0;
   else {
      Return = This->currPnt;
      This->currPnt += nBytes;
      This->unusedSpace -= nBytes;
   }
   return Return;
}

CORBA_Boolean
Message_putByte (Message *This, unsigned char c)
{
   if (This->unusedSpace < sizeof(c) && Message_grow(This,0) == CORBA_False)
      return CORBA_False;
   *(This->currPnt)++ = (unsigned char) c;
   This->unusedSpace--;
   return CORBA_True;
}

CORBA_Boolean
Message_putBoolean (Message *This, CORBA_Boolean c)
{
   if (This->unusedSpace < 1 && Message_grow(This,0) == CORBA_False)
      return CORBA_False;
   *(This->currPnt)++ = (unsigned char) (c == CORBA_True ? 1 : 0);
   This->unusedSpace--;
   return CORBA_True;
}

CORBA_Boolean
Message_putShort (Message *This, CORBA_Short c)
{
   unsigned long align = calcAlign(This->currPnt,sizeof(c));
   if (This->unusedSpace < sizeof(c) + align &&
         Message_grow(This,0) == CORBA_False)
      return CORBA_False;
   This->currPnt += align;
   *((CORBA_Short *)This->currPnt) = c;
   This->unusedSpace -= align + sizeof(c);
   This->currPnt += sizeof(c);
   return CORBA_True;
}

CORBA_Boolean
Message_putLong (Message *This, CORBA_Long c)
{
   unsigned long align = calcAlign(This->currPnt,sizeof(c));
   if (This->unusedSpace < sizeof(c) + align &&
         Message_grow(This,0) == CORBA_False)
      return CORBA_False;
   This->currPnt += align;
   *((CORBA_Long *)This->currPnt) = c;
   This->unusedSpace -= align + sizeof(c);
   This->currPnt += sizeof(c);
   return CORBA_True;
}

CORBA_Boolean
Message_putFloat (Message *This, CORBA_Float c)
{
   unsigned long align = calcAlign(This->currPnt,sizeof(c));
   if (This->unusedSpace < sizeof(c) + align &&
         Message_grow(This,0) == CORBA_False)
      return CORBA_False;
   This->currPnt += align;
   *((CORBA_Float *)This->currPnt) = c;
   This->unusedSpace -= align + sizeof(c);
   This->currPnt += sizeof(c);
   return CORBA_True;
}


/* Assume the floating point number are in IEEE format */
CORBA_Boolean
Message_putDouble (Message *This, CORBA_Double c)
{
   unsigned long align = calcAlign(This->currPnt,sizeof(c));
   if (This->unusedSpace < sizeof(c) + align &&
         Message_grow(This,0) == CORBA_False)
      return CORBA_False;
   This->currPnt += align;
   *((CORBA_Double *)This->currPnt) = c;
# ifdef ARM_LE
   swapDouble ((CORBA_Double *)This->currPnt);
# endif
   This->unusedSpace -= align + sizeof(c);
   This->currPnt += sizeof(c);
   return CORBA_True;
}

CORBA_Boolean
Message_putString (Message *This, CORBA_String c)
{
   CORBA_Boolean Return = CORBA_False;

   if (c == 0) {
      Return = Message_putULong (This, 0);
   } else {
      int size = strlen (c) + 1;
      if (Message_putLong(This, size)) {
         char *str = Message_skipBytes (This, size);
         if (str) {
            memcpy (str, c, size);
            Return = CORBA_True;
         }
      }
   }
   return Return;
}

CORBA_Boolean
Message_putPrincipal (Message *This, CORBA_Principal *c)
{
   CORBA_Boolean Return = CORBA_True;

   if (c == 0) {
      Return = Message_putULong (This, 0);
   } else if ((Return = Message_putLong(This, c->size))) {
      unsigned char *pnt = Message_skipBytes (This, c->size);
      if (pnt)
         memcpy (pnt, c->data, c->size);
      else
         Return = CORBA_False;
   } else
      Return = CORBA_False;
   return Return;
}

CORBA_Boolean
Message_putStruct (Message *This, Exception *ex, CORBA_Octet *c,
                   CORBA_TCKindDesc **kdesc, CORBA_ULong *offs)
{
   CORBA_Boolean Return = CORBA_True;
   register int i;

    for (i = 0; kdesc[i]->kind != TC_KIND_LAST && Return; i++)
       if (kdesc[i]->kind == tk_struct)
          Return = Message_putStruct (This, ex, c, kdesc[i]->suppl, offs);
       else if (kdesc[i]->kind == tk_array) {
          int j;
          for (j = 0; j < kdesc[i]->len && Return; j++)
             Return = Message_putStruct (This, ex, c, kdesc[i]->suppl, offs);
       } else {
          *offs += align (*offs, Feature[kdesc[i]->kind].align);
          if (Feature[kdesc[i]->kind].isPnt)
             Return = Message_encode (This, ex, kdesc[i], *(void**)&c[*offs]);
          else
             Return = Message_encode (This, ex, kdesc[i], &c[*offs]);
          CORBA_Object_calcSize (kdesc[i], offs);
       }
   return Return;
}

CORBA_Boolean
Message_putSequence (Message *This, Exception *ex, const CORBA_TCKindDesc *k,
                     const void *data)
{
   CORBA_Boolean Return = CORBA_True;

   if (k->suppl) {
      CORBA_Sequence *seq = (CORBA_Sequence *) data;
      unsigned int i;
      char *pnt;
      int size;
      Return = Message_putULong (This, seq->count);
      switch (k->suppl[0]->kind) {
      case tk_short:
      case tk_long:
      case tk_ushort:
      case tk_ulong:
      case tk_float:
      case tk_double:
      case tk_boolean:
      case tk_char:
      case tk_octet:
         size = Feature[k->suppl[0]->kind].size;
         if (size == 1) {
            pnt = Message_skipBytes (This, seq->count);
            if (pnt)
               memcpy (pnt, data, seq->count);
            else
               Return = CORBA_False;
         } else {
            for (pnt = (char *) seq->data, i = 0; i < seq->count && Return;
                                                              i++, pnt += size)
               Return = Message_encode (This, ex, k->suppl[0], pnt);
         }
         break;
      default:
         for (i = 0; i < seq->count && Return; i++)
            Return = Message_encode (This, ex, k->suppl[0], seq->data[i]);
         break;
      }
   } else {
      Return = CORBA_False;
   }
   return Return;
}


CORBA_Boolean
Message_getByte (Message *This, unsigned char *c)
{
   if (This->unusedSpace < sizeof(*c))
      return CORBA_False;
   if (c)
      *c = *(This->currPnt);
   This->currPnt++;
   This->unusedSpace--;
   return CORBA_True;
}

CORBA_Boolean
Message_getBoolean (Message *This, CORBA_Boolean *c)
{
   if (This->unusedSpace < 1)
      return CORBA_False;
   if (c)
      *c = *(This->currPnt) == 1 ? CORBA_True : CORBA_False;
   This->currPnt++;
   This->unusedSpace--;
   return CORBA_True;
}

CORBA_Boolean
Message_getShort (Message *This, CORBA_Short *c)
{
   unsigned long align = calcAlign(This->currPnt,sizeof(*c));
   if (This->unusedSpace < sizeof(*c) + align)
      return CORBA_False;
   This->currPnt += align;
   if (c) {
      if (This->msgByteOrder == This->myByteOrder) {
         *c = *((CORBA_Short *)This->currPnt);
      } else {
         ((unsigned char *)c)[1] = (This->currPnt)[0];
         ((unsigned char *)c)[0] = (This->currPnt)[1];
      }
   }
   This->currPnt += sizeof(*c);
   This->unusedSpace -= align + sizeof(*c);
   return CORBA_True;
}

CORBA_Boolean
Message_getLong (Message *This, CORBA_Long *c)
{
   unsigned long align = calcAlign(This->currPnt,sizeof(*c));
   if (This->unusedSpace < sizeof(*c) + align)
      return CORBA_False;
   This->currPnt += align;
   if (c) {
      if (This->msgByteOrder == This->myByteOrder) {
         *c = *((CORBA_Long *)This->currPnt);
      } else {
         ((unsigned char *)c)[3] = (This->currPnt)[0];
         ((unsigned char *)c)[2] = (This->currPnt)[1];
         ((unsigned char *)c)[1] = (This->currPnt)[2];
         ((unsigned char *)c)[0] = (This->currPnt)[3];
      }
   }
   This->currPnt += sizeof(*c);
   This->unusedSpace -= align + sizeof(*c);
   return CORBA_True;
}

CORBA_Boolean
Message_getString (Message *This, CORBA_String *c, CORBA_Boolean autoAlloc)
{
   CORBA_Boolean Return;
   CORBA_ULong len;

   if ((Return = Message_getULong(This, &len))) {
      if (len > 0) {
         char *str = Message_skipBytes (This, len);
         if (str) {
            if (autoAlloc)
               *c = malloc (len);
            if (*c)
               memcpy (*c, str, len);
         } else
            Return = CORBA_False;
      }
   }
   return Return;
}

CORBA_Boolean
Message_getPrincipal(Message *This,CORBA_Principal **c,CORBA_Boolean autoAlloc)
{
   CORBA_Boolean Return;
   CORBA_ULong len;

   if ((Return = Message_getULong(This, &len))) {
      char *pnt = Message_skipBytes (This, len);
      if (pnt) {
         if (autoAlloc)
            *c = CORBA_Object_new (&TCD_Principal, len);
         if (*c && (*c)->data)
            memcpy ((*c)->data, pnt, len);
      } else
         Return = CORBA_False;
   }
   return Return;
}

/* Assume the floating point number are in IEEE format */
CORBA_Boolean
Message_getDouble (Message *This, CORBA_Double *c)
{
   unsigned long align = calcAlign(This->currPnt,sizeof(*c));
   if (This->unusedSpace < sizeof(*c) + align)
      return CORBA_False;
   This->currPnt += align;
   if (c) {
# ifdef ARM_LE
      swapDouble ((CORBA_Double *)This->currPnt);
# endif
      if (This->msgByteOrder == This->myByteOrder) {
         *c = *((CORBA_Double *)This->currPnt);
      } else {
         ((unsigned char *)c)[7] = (This->currPnt)[0];
         ((unsigned char *)c)[6] = (This->currPnt)[1];
         ((unsigned char *)c)[5] = (This->currPnt)[2];
         ((unsigned char *)c)[4] = (This->currPnt)[3];
         ((unsigned char *)c)[3] = (This->currPnt)[4];
         ((unsigned char *)c)[2] = (This->currPnt)[5];
         ((unsigned char *)c)[1] = (This->currPnt)[6];
         ((unsigned char *)c)[0] = (This->currPnt)[7];
      }
   } 
   This->currPnt += sizeof(*c);
   This->unusedSpace -= align + sizeof(*c);
   return CORBA_True;
}

CORBA_Boolean
Message_getStruct(Message *This, Exception *ex, CORBA_Octet *c,
                  CORBA_TCKindDesc **kdesc, CORBA_ULong *offs,
                  CORBA_Boolean autoAlloc)
{
   CORBA_Boolean Return = CORBA_True;
   register int i;
   void **data;
   void *dummy;

    for (i = 0; kdesc[i]->kind != TC_KIND_LAST && Return; i++)
       if (kdesc[i]->kind == tk_struct)
          Return = Message_getStruct (This, ex, c, kdesc[i]->suppl,
                                      offs, autoAlloc);
       else if (kdesc[i]->kind == tk_array) {
          int j;
          for (j = 0; j < kdesc[i]->len && Return; j++)
             Return = Message_getStruct (This, ex, c, kdesc[i]->suppl,
                                         offs, autoAlloc);
       } else {
          *offs += align (*offs, Feature[kdesc[i]->kind].align);
          if (Feature[kdesc[i]->kind].isPnt) {
             data = (void **) &c[*offs];
             Return = Message_decode (This, ex, kdesc[i], data, autoAlloc);
          } else {
             dummy =  &c[*offs];
             data = &dummy;
             Return = Message_decode (This, ex, kdesc[i], data, CORBA_False);
          }
          CORBA_Object_calcSize (kdesc[i], offs);
       }
   return Return;
}

CORBA_Boolean
Message_getSequence(Message *This, Exception *ex, const CORBA_TCKindDesc *k,
                                          void **data, CORBA_Boolean autoAlloc)
{
   CORBA_Boolean Return = CORBA_True;
   CORBA_ULong len;

   if (k->suppl && (Return = Message_getULong(This, &len))) {
      CORBA_Sequence *seq;
      unsigned int i;
      char *pnt;
      int size;
      switch (k->suppl[0]->kind) {
      case tk_short:
      case tk_long:
      case tk_ushort:
      case tk_ulong:
      case tk_float:
      case tk_double:
      case tk_boolean:
      case tk_char:
      case tk_octet:
         size = Feature[k->suppl[0]->kind].size;
         if (autoAlloc) {
            seq=(CORBA_Sequence *)(*data = malloc (sizeof(CORBA_Sequence)));
            seq->count = len;
            seq->data = malloc (size * seq->count);
         } else {
            seq = (CORBA_Sequence *) *data;
         }
         if (*data) {
            if (size == 1) {
               pnt = Message_skipBytes (This, seq->count);
               if (pnt)
                  memcpy (seq->data, pnt, seq->count);
               else
                  Return = CORBA_False;
            } else {
               for (pnt = (char *) seq->data, i = 0; i < seq->count && Return;
                                                               i++, pnt += size)
                  Return = Message_decode (This, ex, k->suppl[0],
                                                   (void**)&pnt, CORBA_False);
            }
         }
         break;
      default:
         if (autoAlloc) {
            seq=(CORBA_Sequence *)(*data = malloc (sizeof(CORBA_Sequence)));
            seq->count = len;
            seq->data = malloc (sizeof(void*) * seq->count);
            memset ((char *)seq->data, 0, sizeof(void*) * seq->count);
         } else {
            seq = (CORBA_Sequence *) *data;
         }
         if (*data)
            for (i = 0; i < seq->count && Return; i++)
               Return = Message_decode (This, ex, k->suppl[0],
                                      &seq->data[i], autoAlloc);
         break;
      }
   }
   return Return;
}

CORBA_Boolean
Message_encode (Message *This, Exception *ex, const CORBA_TCKindDesc *k,
                const void *data)
{
   CORBA_Boolean Return = CORBA_True;
   CORBA_Octet *ulpnt;

   switch (k->kind) {
   case tk_null:
   case tk_void:
      break;
   case tk_char:
   case tk_octet:
      Return = Message_putByte (This, *((char *)data));
      break;
   case tk_short:
   case tk_ushort:
      Return = Message_putShort(This, *((CORBA_Short *) data));
      break;
   case tk_long:
   case tk_ulong:
   case tk_enum:
      Return = Message_putLong (This, *((CORBA_Long *)data));
      break;
   case tk_float:
      Return = Message_putFloat (This, *((CORBA_Float *)data));
      break;
   case tk_double:
      Return = Message_putDouble (This, *(CORBA_Double *)data);
      break;
   case tk_boolean:
      Return = Message_putBoolean (This, *(CORBA_Boolean *)data);
      break;
   case tk_string:
      Return = Message_putString (This, (CORBA_String)data);
      break;
   case tk_Principal:
      Return = Message_putPrincipal (This, (CORBA_Principal *)data);
      break;
   case tk_struct:
      if (k->suppl) {
         CORBA_ULong offs = 0;
         Return = Message_putStruct (This, ex, (CORBA_Octet *)data,
                  k->suppl, &offs);
      }
      break;
   case tk_sequence:
      Return = Message_putSequence (This, ex, k, data);
      break;
   case tk_any:
      if (data) {
         CORBA_TypeCode tc;
         CORBA_Any *any = (CORBA_Any *)data;
         tc.kdesc = any->tcIn;
         tc.repositoryId = 0;
         Return = Message_encode(This,ex, &TCD_TypeCode, &tc);
         if (Return)
            Return = Message_encode(This,ex, any->tcIn, any->data);
      }
      break;
   case tk_TypeCode:
      if (data) {
         CORBA_TypeCode *tc = (CORBA_TypeCode *)data;
         if ((Return = Message_putLong (This, tc->kdesc->kind))) {
            switch (tc->kdesc->kind) {
            case tk_null:
            case tk_void:
            case tk_char:
            case tk_octet:
            case tk_short:
            case tk_ushort:
            case tk_long:
            case tk_ulong:
            case tk_enum:
            case tk_float:
            case tk_double:
            case tk_boolean:
            case tk_Principal:
            case tk_TypeCode:
            case tk_any:
               break;
            case tk_string:
               Return = Message_putULong (This, 0);
               break;
            case tk_struct:
                         /* il padding lo ha messo la precedente putLong */
               ulpnt = Message_skipBytes (This, sizeof (CORBA_ULong));
               Message_putBoolean (This,This->myByteOrder);
               Return = Message_putString(This, tc->repositoryId);
               if (!Return)
                  break;
               Return = Message_putString(This, tc->kdesc->name);
               if (!Return)
                  break;
               if (tc->kdesc->suppl) {
                  CORBA_ULong i;
                  CORBA_TypeCode iTc;
                  for (i = 0; tc->kdesc->suppl[i]->kind != TC_KIND_LAST; i++)
                     ;
                  Message_putULong (This, i);
                  for (i = 0;tc->kdesc->suppl[i]->kind!=TC_KIND_LAST && Return;
                       i++) {
                     Return = Message_putString(This,tc->kdesc->suppl[i]->name);
                     if (Return) {
                        iTc.kdesc = tc->kdesc->suppl[i];
                        iTc.repositoryId = 0;
                        Return = Message_encode(This,ex, &TCD_TypeCode, &iTc);
                     }
                  }
               } else {
                  Message_putULong (This, 0);
               }
               *((CORBA_ULong *) ulpnt) = (char *)This->currPnt - 
                                      (char *) (ulpnt + sizeof(CORBA_ULong));
               break;
            case tk_sequence:
               ulpnt = Message_skipBytes (This, sizeof (CORBA_ULong));
               Message_putBoolean (This,This->myByteOrder);
               if (tc->kdesc->suppl) {
                  CORBA_TypeCode iTc;
                  iTc.kdesc = tc->kdesc->suppl[0];
                  iTc.repositoryId = 0;
                  Return = Message_encode(This,ex, &TCD_TypeCode, &iTc);
               } else
                  Return = Message_encode(This,ex, &TCD_TypeCode, &TCD_null);
               if (Return) {
                  Return = Message_putULong (This, 0);
                  *((CORBA_ULong *) ulpnt) = (char *)This->currPnt - 
                                         (char *) (ulpnt + sizeof(CORBA_ULong));
               }
               break;
            case tk_array:
               ulpnt = Message_skipBytes (This, sizeof (CORBA_ULong));
               Message_putBoolean (This,This->myByteOrder);
               if (tc->kdesc->suppl) {
                  CORBA_TypeCode iTc;
                  iTc.kdesc = tc->kdesc->suppl[0];
                  iTc.repositoryId = 0;
                         /* il padding lo ha messo la precedente putLong */
                  Return = Message_encode(This,ex, &TCD_TypeCode, &iTc);
               } else
                  Return = Message_encode(This,ex, &TCD_TypeCode, &TCD_null);
               if (Return) {
                  Return = Message_putULong (This, tc->kdesc->len);
                  *((CORBA_ULong *) ulpnt) = (char *)This->currPnt - 
                                      (char *) (ulpnt + sizeof(CORBA_ULong));
               }
               break;
         
            /* not implemented yet */
            case tk_longlong:
            case tk_ulonglong:
            case tk_objref:
            case tk_union:
            case tk_alias:
            case tk_except:
            case tk_wstring:
            case tk_longdouble:
            case tk_wchar:
            default:
               break;
            }
         }
      }
      break;
   case tk_array:
      if (k->suppl && k->len) {
         CORBA_ULong itemSize = 0;
         register int i;
         CORBA_Object_calcSize (k->suppl[0], &itemSize);
         for (i = 0; i < k->len && Return; i++,data=((CORBA_Octet *)data)+itemSize)
            Return = Message_encode (This, ex, k->suppl[0], data);
      }
      break;
        
   /* not implemented yet */
   case tk_longlong:
   case tk_ulonglong:
   case tk_objref:
   case tk_union:
   case tk_alias:
   case tk_except:
   case tk_wstring:
   case tk_longdouble:
   case tk_wchar:
   default:
      Return = CORBA_False;
      break;
   }
   return Return;
}


CORBA_Boolean
Message_decode (Message *This, Exception *ex, const CORBA_TCKindDesc *k,
                void **data, CORBA_Boolean autoAlloc)
{
   CORBA_Boolean Return = CORBA_True;
   switch (k->kind) {
   case tk_null:
   case tk_void:
      break;
   case tk_char:
   case tk_octet:
      if (autoAlloc)
         *data = malloc (sizeof (CORBA_Char));
      Return = Message_getByte (This, (CORBA_Char *)*data);
      break;
   case tk_short:
   case tk_ushort:
      if (autoAlloc)
         *data = malloc (sizeof (CORBA_Short));
      Return = Message_getShort(This, (CORBA_Short *)*data);
      break;
   case tk_long:
   case tk_ulong:
   case tk_enum:
      if (autoAlloc)
         *data = malloc (sizeof (CORBA_Long));
      Return = Message_getLong (This, (CORBA_Long *)*data);
      break;
   case tk_float:
      if (autoAlloc)
         *data = malloc (sizeof (CORBA_Float));
      Return = Message_getFloat (This, (CORBA_Float *)*data);
      break;
   case tk_double:
      if (autoAlloc)
         *data = malloc (sizeof (CORBA_Double));
      Return = Message_getDouble (This, (CORBA_Double *)*data);
      break;
   case tk_boolean:
      if (autoAlloc)
         *data = malloc (sizeof (CORBA_Boolean));
      Return = Message_getBoolean (This, (CORBA_Boolean *)*data);
      break;
   case tk_string:
      Return = Message_getString (This, (CORBA_String *) data, autoAlloc);
      break;
   case tk_Principal:
      Return = Message_getPrincipal(This,(CORBA_Principal **) data, autoAlloc);
      break;
   case tk_struct:
      if (k->suppl) {
         CORBA_ULong offs;
         if (autoAlloc) {
            offs = 0;
            CORBA_Object_calcSize (k, &offs);
            *data = malloc (offs);
            memset (*data, 0, offs);
         } 
         offs = 0;
         if (*data)
            Return = Message_getStruct(This, ex, (CORBA_Octet *)*data,
                                       k->suppl, &offs, autoAlloc);
      }
      break;
   case tk_sequence:
      Message_getSequence (This, ex, k, data, autoAlloc);
      break;
   case tk_any:
      {
         CORBA_Any *any;
         CORBA_TypeCode *tc = 0;
         if (autoAlloc) {
            any = (CORBA_Any *)(*data = CORBA_Object_new (&TCD_any, 0));
         } else {
            any = (CORBA_Any *)*data;
            if (any->tcOut) {
               CORBA_TCKindDesc_delete (any->tcOut);
               any->tcOut = 0;
            }
         }
         Return = Message_decode(This,ex,&TCD_TypeCode,(void **)&tc,CORBA_True);
         if (Return) {
            any->tcOut = tc->kdesc;
            any->tcIn = tc->kdesc;
            tc->kdesc = 0;
            Return = Message_decode (This,ex,any->tcOut, &any->data,autoAlloc);
         }
         CORBA_Object_delete (tc, &TCD_TypeCode);
      }
      break;
   case tk_TypeCode:
      {
         CORBA_TypeCode *iTc = 0;
         CORBA_String name = 0;
         CORBA_String repositoryId = 0;
         CORBA_TCKind type;
         if ((Return = Message_getLong (This, (long *)&type))) {
            CORBA_ULong i;
            CORBA_ULong count;
            CORBA_TypeCode *tc;
            /* Il TypeCode viene allocato SEMPRE!!! indipendentemente 
               da autoAlloc */
            tc =(CORBA_TypeCode *)(*data=CORBA_Object_new (&TCD_TypeCode, 0));
            switch (type) {
            case tk_null:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_null);
               break;
            case tk_void:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_void);
               break;
            case tk_char:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_char);
               break;
            case tk_octet:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_octet);
               break;
            case tk_short:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_short);
               break;
            case tk_ushort:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_ushort);
               break;
            case tk_long:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_long);
               break;
            case tk_ulong:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_ulong);
               break;
            case tk_enum:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_enum);
               break;
            case tk_float:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_float);
               break;
            case tk_double:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_double);
               break;
            case tk_boolean:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_boolean);
               break;
            case tk_Principal:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_Principal);
               break;
            case tk_TypeCode:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_TypeCode);
               break;
            case tk_any:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_any);
               break;
            case tk_string:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_string);
               Message_getULong (This, &count); /* Stringhe solo unbounded */
               break;
            case tk_struct:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_struct);
               Message_getULong (This, &tc->seqLen);
               Message_getByte (This, &tc->endian);
               Return = Message_getString(This, &tc->repositoryId, CORBA_True);
               if (!Return)
                  break;
               Return = Message_getString(This, &tc->kdesc->name, CORBA_True);
               if (!Return)
                  break;
               Message_getULong (This, &count);
               tc->kdesc->suppl = (CORBA_TCKindDesc **)
                               malloc (sizeof(CORBA_TCKindDesc*)*(count+1));
               for (i = 0; i < count && Return; i++) {
                  Return = Message_getString(This, &name, CORBA_True);
                  if (Return) {
                     iTc = 0;
                     Return = Message_decode (This, ex, &TCD_TypeCode,
                                              (void **)&iTc, CORBA_True);
                     tc->kdesc->suppl[i] = iTc->kdesc;
                     tc->kdesc->suppl[i]->name = name;
                     iTc->kdesc = 0;
                     CORBA_Object_delete (iTc, &TCD_TypeCode);
                  }
               }
               tc->kdesc->suppl[i] = CORBA_TCKindDesc_dup (&TCD_KIND_LAST);
               break;
            case tk_sequence:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_sequence);
               iTc = 0;
               tc->kdesc->suppl = (CORBA_TCKindDesc **)
                               malloc (sizeof(CORBA_TCKindDesc*)*2);
               Message_getULong (This, &tc->seqLen);
               Message_getByte (This, &tc->endian);
               Return = Message_decode (This, ex, &TCD_TypeCode, (void**)&iTc,
                                              CORBA_True);
               tc->kdesc->suppl[0] = iTc->kdesc;
               iTc->kdesc = 0;
               CORBA_Object_delete (iTc, &TCD_TypeCode);
               if (Return)
                  Return = Message_getULong (This, &count);
               tc->kdesc->suppl[1] = CORBA_TCKindDesc_dup (&TCD_KIND_LAST);
               break;
            case tk_array:
               tc->kdesc = CORBA_TCKindDesc_dup (&TCD_array);
               iTc = 0;
               tc->kdesc->suppl = (CORBA_TCKindDesc **)
                               malloc (sizeof(CORBA_TCKindDesc*)*2);
               Message_getULong (This, &tc->seqLen);
               Message_getByte (This, &tc->endian);
               Return = Message_decode (This, ex, &TCD_TypeCode, (void**)&iTc,
                                              CORBA_True);
               tc->kdesc->suppl[0] = iTc->kdesc;
               iTc->kdesc = 0;
               CORBA_Object_delete (iTc, &TCD_TypeCode);
               if (Return)
                  Return = Message_getULong (This, &tc->kdesc->len);
               tc->kdesc->suppl[1] = CORBA_TCKindDesc_dup (&TCD_KIND_LAST);
               break;
            case tk_alias:
               Message_getULong (This, &tc->seqLen);
               Message_getByte (This, &tc->endian);
               Return = Message_getString(This, &repositoryId, CORBA_True);
               if (!Return)
                  break;
               Return = Message_getString(This, &name, CORBA_True);
               if (!Return) {
                  free (repositoryId);
                  break;
               }
               iTc = 0;
               Return = Message_decode(This, ex, &TCD_TypeCode,
                                       (void **)&iTc, CORBA_True);
               if (Return) {
                  tc->kdesc = iTc->kdesc;
                  tc->repositoryId = repositoryId;
                  tc->kdesc->name = name;
                  iTc->kdesc = 0;
                  CORBA_Object_delete (iTc, &TCD_TypeCode);
               } else {
                  free (repositoryId);
                  free (name);
               }
               break;
         
            /* not implemented yet */
            case tk_longlong:
            case tk_ulonglong:
            case tk_objref:
            case tk_union:
            case tk_except:
            case tk_wstring:
            case tk_longdouble:
            case tk_wchar:
            default:
               break;
            }
         }
      }
      break;
   case tk_array:
      if (k->suppl && k->len) {
         CORBA_ULong itemSize = 0;
         register int i;
         CORBA_Octet *pnt;
         CORBA_Object_calcSize (k->suppl[0], &itemSize);
         if (autoAlloc)
            *data = CORBA_Object_new (k, 0);
         for (i = 0, pnt = *data; i < k->len && Return; i++, pnt += itemSize)
            Return = Message_decode(This, ex, k->suppl[0],
                                    (void**)&pnt, CORBA_False);
         
      }
      break;
   /* not implemented yet */
   case tk_longlong:
   case tk_ulonglong:
   case tk_objref:
   case tk_union:
   case tk_alias:
   case tk_except:
   case tk_wstring:
   case tk_longdouble:
   case tk_wchar:
   default:
      Return = CORBA_False;
      break;
   }
   return Return;
}

