/*
    genidl - Generate interface defintion language listing from a
    Portable Executable.
    Copyright (C) 2009, 2010, 2011, 2012, 2013  mingw-w64 project

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

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#define _CRT_SECURE_NO_WARNINGS
#include "genidl_cfg.h"
#include "genidl_typeinfo.h"
#include "genidl_typinfo.h"
#include <malloc.h>
#include <string.h>
#include <memory.h>

int32_t
TI_init_typs (sTITyps *ptyp)
{
  if (!ptyp)
    return -1;
  memset (ptyp, 0, sizeof (sTITyps));
  return 0;
}

int32_t
TI_dest_typs (sTITyps *ptyp)
{
  size_t i;
  int32_t j;
  if (!ptyp)
    return -1;
  for (j=0;j<TITYP_MAX;j++)
    {
      if (ptyp->buc[j].arr != NULL)
	{
	  for (i = 0; i < ptyp->buc[j].count; i++)
	    {
	      if (ptyp->buc[j].arr[i]->refstr)
		free (ptyp->buc[j].arr[i]->refstr);
	      if (ptyp->buc[j].arr[i]->poststr)
		free (ptyp->buc[j].arr[i]->poststr);
	      free (ptyp->buc[j].arr[i]);
	    }
	  free (ptyp->buc[j].arr);
	}
    }
  memset (ptyp, 0, sizeof (sTITyps));
  return 0;
}

int32_t TI_add_typ (sTITyps *ptyp, uint32_t memid, int32_t kind, int32_t refkind, uint32_t refmem,
		const char *refstr, const char *name, const char *poststr)
{
  sTITyp *t, **h;
  if (TI_get_typ (ptyp, memid, kind) != NULL || kind >= TITYP_MAX)
    return -1;
  if (!name)
    name = "";
  if (!refstr)
    refstr="";
  if (!poststr)
    poststr = "";
  if (ptyp->buc[kind].count >= ptyp->buc[kind].max)
    {
      h = (sTITyp **) malloc (sizeof (sTITyp *) * (ptyp->buc[kind].count + 32));
      if (ptyp->buc[kind].arr)
	{
	  memcpy (h, ptyp->buc[kind].arr, sizeof (sTITyp*) * ptyp->buc[kind].count);
	  free (ptyp->buc[kind].arr);
	}
      ptyp->buc[kind].arr = h;
      ptyp->buc[kind].max += 32;
    }
  t = (sTITyp *) malloc (sizeof (sTITyp) + strlen (name));
  t->memid = memid;
  t->kind = kind;
  t->refkind = refkind;
  t->refmem = refmem;
  t->refstr = strdup (refstr);
  t->poststr = strdup (poststr);
  strcpy (t->name, name);
  ptyp->buc[kind].arr[ptyp->buc[kind].count] = t;
  ptyp->buc[kind].count += 1;
  return 0;
}

sTITyp *
TI_get_typ (sTITyps *ptyp, uint32_t memid, int32_t kind)
{
  size_t i;
  if (!ptyp || kind < 0 || kind >= TITYP_MAX)
    return NULL;
  for (i = 0; i < ptyp->buc[kind].count; i++)
    {
      if (ptyp->buc[kind].arr[i]->kind == kind && ptyp->buc[kind].arr[i]->memid == memid)
	return ptyp->buc[kind].arr[i];
    }
  return NULL;
}

static char *
ti_cat (const char *t, const char *r)
{
  char *ret;
  size_t l;
  if (!t)
    t = "";
  if (!r)
    r = "";
  l = strlen (t) + strlen (r) +1;
  ret = (char *) malloc (l);
  strcpy (ret, t);
  strcat (ret, r);
  return ret;
}

static char *
ti_cat_freel (char *t, const char *r)
{
  char *ret = ti_cat (t, r);
  if (t)
    free (t);
  return ret;
}

static int32_t
end_isref (const char *ret)
{
  if (!ret || *ret == 0)
    return 1;
  ret += strlen (ret);
  if (ret[-1] == '&' || ret[-1] == '*' || ret[-1] == ']')
    return 1;
  return 0;
}


char *
TI_get_typ_name (sTITyps *ptyp, uint32_t memid, int32_t kind, const char *varName)
{
  static const char *szKind[TITYP_MAX] = {
    "Name_", "Str_", "Guid_", "TypeB_", "TypeD_", "Arr_", "Ref_", "Imp_",
    "Unknown_", "CD_", "CDGuid_", "ImpR_"
  };
  sTITyp *t = TI_get_typ (ptyp, memid, kind);
  char s[128];
  char *ret;

  if (!t)
    {
      sprintf (s, "%s%x",szKind[kind],memid);
      ret = strdup (s);
    }
  else if (t->name[0] == 0)
    {
      ret = TI_get_typ_name (ptyp, t->refmem, t->refkind, "");
    }
  else
    ret = strdup (t->name);
  if (t && t->refstr != NULL && t->refstr[0] != 0)
    {
      if (!end_isref (ret))
	ret = ti_cat_freel (ret, " ");
      ret = ti_cat_freel (ret, t->refstr);
    }
  if (varName != NULL && varName[0] != 0)
    {
      char *hl = strchr (ret, '[');
      char *ar = NULL;
      if (hl)
      {
	ar = strdup (hl);
	*hl = 0;
      }
      if (!end_isref (ret))
	ret = ti_cat_freel (ret, " ");
      ret = ti_cat_freel (ret, varName);
      if (ar)
	{
	  ret = ti_cat_freel (ret, ar);
	  free (ar);
	}
    }
  if (t && t->poststr != NULL && t->poststr[0] != 0)
    {
      if (!end_isref (ret) && t->poststr[0] != '[')
	ret = ti_cat_freel (ret, " ");
      ret = ti_cat_freel (ret, t->poststr);
    }
  return ret;
}

int32_t
TI2_import_name (sTITyps *nptr, unsigned char *dta, uint32_t len)
{
  struct sMSFTNamePrologue {
    int32_t res1;
    int32_t res2;
#ifdef __GNUC__
    __extension__
#endif
    union {
      unsigned char v[4];
      uint16_t us[2];
    };
  };
#ifdef __GNUC__
  __extension__
#endif
  union {
    unsigned char *dta;
    struct sMSFTNamePrologue *p;
  } v;
  uint32_t off = 0;

  if (!len)
    return 0;
  while ((off + 12) <= len)
    {
      uint32_t memid = off;
      unsigned char l;
      char *name;
      v.dta = &dta[off];
      l = v.p->v[0];

      name = (char *) malloc (l + 1);
      if (!name)
	return -1;
      if (l != 0)
	memcpy (name, &dta[off + 12], l);
      name[l] = 0;

      if (TI_add_typ (nptr,memid,TITYP_NAME, 0,0,"", name, "") < 0)
	return -1;
      free (name);
      off = (12 + off + (uint32_t) l + 3) & ~3;
    }
  return 0;
}

int32_t
TI2_import_string (sTITyps *sptr, unsigned char *dta, uint32_t len)
{
  uint32_t off = 0;
  union {
    unsigned char *dta;
    unsigned short *len;
  } v;

  if (!len)
    return 0;

  while ((off + 2) <= len)
  {
    char *h;
    v.dta = &dta[off];
    h = (char *) malloc (v.len[0] + 1);
    memcpy (h, &dta[off + 2], v.len[0]);
    h[v.len[0]]=0;
    if (TI_add_typ (sptr, off, TITYP_STR, 0, 0, "", h, "") < 0)
      return -1;
    free (h);
    off += 2 + (uint32_t) v.len[0];
    off = (off + 3) & ~3;
  }
  return 0;
}

int32_t
TI2_import_guid (sTITyps *gptr, unsigned char *dta, uint32_t length)
{
  struct sGuidTab {
    uint32_t data1;
    uint16_t data2[2];
    unsigned char data3[8];
    int32_t res1;
    int32_t res2; /* Forwarder GUID */
  };

  char str[260];
  uint32_t off = 0;
  union {
    unsigned char *d;
    struct sGuidTab *g;
  } v;
  if (!length)
    return -1;
  while ((off + 24) <= length)
    {
      v.d = &dta[off];
      sprintf (str ,"\"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\"",
	v.g->data1, v.g->data2[0], v.g->data2[1],
	v.g->data3[0],v.g->data3[1],v.g->data3[2],v.g->data3[3],
	v.g->data3[4],v.g->data3[5],v.g->data3[6],v.g->data3[7]);
      TI_add_typ (gptr, (uint32_t) off, TITYP_GUIDS, 0, 0, "", str, "");
      off += 24;
    }
  return 0;
}

int32_t
TI2_import_typinfo_names (sTITyps *tptr, unsigned char *dta, uint32_t length)
{
  char name_unk[32];
  char prefix_unk[32];
  char *h;
  char *name;
  const char *prefix;
  sMSFT_TypeInfoBase *t = (sMSFT_TypeInfoBase *) dta;
  int32_t i;
  int32_t free_name;
  uint32_t off = 0;

  if (!length)
    return 0;
  i = 0;
  while ((off + sizeof (sMSFT_TypeInfoBase)) <= length)
  {
    free_name = 1;
    name = TI_get_typ_name (tptr, (uint32_t) t[i].NameOffset, TITYP_NAME,"");
    prefix = "";
    if (!name)
    {
      free_name = 0;
      sprintf (name_unk,"Name_%0x", t[i].NameOffset);
      name = &name_unk[0];
    }
    switch (t[i].typekind & 0xf)
    {
    case TKIND_ENUM: prefix = "enum "; break;
    case TKIND_RECORD: prefix = "struct "; break;
    case TKIND_MODULE: prefix = "module "; break;
    case TKIND_INTERFACE: prefix = "interface "; break;
    case TKIND_DISPATCH: prefix = "dispinterface "; break;
    case TKIND_COCLASS: prefix = "coclass "; break;
    case TKIND_ALIAS: break;
    case TKIND_UNION: prefix = "union "; break;
    default:
      prefix = &prefix_unk[0];
      sprintf (prefix_unk, "TK_%u ", t[i].typekind&0xf);
      break;
    }
    h = (char *) malloc (strlen (prefix) + strlen (name) + 1);
    sprintf (h, "%s%s", prefix, name);
    TI_add_typ (tptr, (uint32_t) off, TITYP_TYPINFO_NAMES, 0,0, "", h, "");
    free (h);
    if (free_name)
      free (name);
    off += sizeof (sMSFT_TypeInfoBase);
    i++;
  }
  return 0;
}

char *
getTypeBOrImpRef (sTITyps *dptr, uint32_t off, const char *var)
{
  if (off == (uint32_t) -1)
    return NULL;
  if ((off&1) != 0)
    return TI_get_typ_name (dptr, off & ~1U,TITYP_IMPREF, var);
  return TI_get_typ_name (dptr, off, TITYP_TYPINFO_NAMES, var);
}

int32_t
TI2_import_typedesc (sTITyps *dptr, unsigned char *dta, uint32_t len)
{
  sMSFT_TypeDesc *p;
  uint32_t off = 0;
  if (!len)
    return -1;
  while ((off + 7) < len)
  {
    p = (sMSFT_TypeDesc *) &dta[off];
    
    switch ((p->kind))
    {
    case 26: /* VT_PTR */
      if ((p->vt & 0x80000000) != 0)
        {
	  const char *name;
	  name = decode_VT_name_tmp (((uint32_t) (p->vt)) & 0xffff);
	  TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF, TITYP_UNKNOWN,
	      (uint32_t) p->oArrayD & 0xffff,
	      ((p->flag & 0x7fff) != 0x7ffe ? "*" : ""), &name[0], "");
        }
      else
        {
	  if ((p->oTypeB & 1) != 0)
	    TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF,
	      TITYP_IMPREF, (uint32_t) p->oTypeB & 0xfffffffe,
	      ((p->flag & 0x7fff) != 0x7ffe ? "*" : ""), "", "");
	  else
	    TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF,
	      TITYP_DEREF, (uint32_t) p->oTypeB,
	      ((p->flag & 0x7fff) != 0x7ffe ? "*" : ""), "", "");
        }
      break;
    case 27: /* SAFEARRAY */
      if ((p->vt & 0x80000000) != 0)
        {
	  const char *name;
	  name = decode_VT_name_tmp (((uint32_t) (p->vt)) & 0xffff);
	  TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF, TITYP_UNKNOWN,
	      (uint32_t) p->oArrayD  & 0xffff,
	      "", &name[0], ((p->flag & 0x7fff) != 0x7ffe ? "[]" : ""));
        }
      else
        {
	  if ((p->oTypeB & 1) != 0)
	    TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF,
	      TITYP_IMPREF, (uint32_t) p->oTypeB & 0xfffffffe,
	      "", "", ((p->flag & 0x7fff) != 0x7ffe ? "[]" : ""));
	  else
	    TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF,
	      TITYP_DEREF, (uint32_t) p->oTypeB,
	      "", "", ((p->flag & 0x7fff) != 0x7ffe ? "[]" : ""));
        }
      break;
    case 28: /* VT_CARRAY */
	TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF, TITYP_ARRAY,
	  (uint32_t) p->oArrayD & 0xffff, "", "", "");
	break;
    case 29: /* VT_USERDEFINED */
      if ((p->vt & 0x80000000) != 0)
        {
	  const char *name;
	  name = decode_VT_name_tmp (((uint32_t) (p->vt)) & 0xffff);
	  TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF, TITYP_UNKNOWN,
	      (uint32_t) p->oArrayD  & 0xffff,
	      "", &name[0], "");
        }
      else
        {
	  if ((p->oTypeB & 1) != 0)
	    TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF,
	      TITYP_IMPREF, (uint32_t) p->oTypeB & 0xfffffffe,
	      "", "", "");
	  else
	    TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF,
	      TITYP_TYPINFO_NAMES, (uint32_t) p->oTypeB,
	      "", "", "");
        }
      break;
    default:
      {
	const char *name;
	const char *prefix = "";
	name = decode_VT_name_tmp (((uint32_t) (p->vt)) & 0xffff);
	if ((p->flag & 0xf000) == 0x4000)
	  prefix = "*";
	TI_add_typ (dptr, (uint32_t) off, TITYP_DEREF, TITYP_UNKNOWN,
	    (uint32_t) p->oArrayD, prefix, &name[0], "");
      }
      break;
    }
    off += 8;
  }
  return 0;
}

int32_t
TI2_import_customdata (sTITyps *dptr, unsigned char *dta, uint32_t length)
{
  sMSFT_CustomData *p;
  uint32_t off = 0;
  if (!length)
    return 0;
  while (off < length)
  {
    uint32_t soff = off;
    char *s;
    s = NULL;
    p = (sMSFT_CustomData *) &dta[off];
    off += getVT_data (dptr, p->vt, p->dta, &s);
    TI_add_typ (dptr,soff,TITYP_CUSTOMDATA,0,0,"",s,"");
    if(s) free (s);
    off = (off + 3) & ~3;
    //fprintf (fp, "\n");
  }
  return 0;
}

size_t
getVT_data (sTITyps *dptr, uint32_t vt, unsigned char *dta, char **ret)
{
  char s[4096];
  size_t b, l, sz;
  if (dptr)
    sz = 0;
  l = getVT_size (vt, dta,&b);
  dta += b - 2;
  if (l == 0xffffffff)
    {
      if (vt == 8)
        sprintf (s, "L\"\"");
      else {
        fprintf (stderr, "vt: 0x%x with size of -1!!!\n", vt);
        sprintf (s, "vt:0x%x_zero", vt);
      }
      if (ret)
        *ret = strdup (s);
      return b;
    }
  sz = l;
  s[0] = 0;

  switch (vt) {
  case 16: /* VT_I1 */ sprintf (s,"(char) %d", *((char *) dta)); break;
  case 17: /* VT_UI1 */ sprintf (s,"(unsigned char) %u", *((unsigned char *) dta)); break;
  case 18: /* VT_UI2 */ sprintf (s,"(USHORT) %u", *((uint16_t *) dta)); break;
  case 23: /* VT_UINT */
  case 19: /* VT_UI4 */ sprintf (s,"(UINT) %uU", *((uint32_t *) dta)); break;
  case 20: /* VT_I8 */
#ifdef _WIN32
    sprintf (s,"(LONGLONG) %I64dLL", *((int64_t *) dta)); break;
#else
    sprintf (s,"(LONGLONG) %lldLL", *((int64_t *) dta)); break;
#endif
  case 21: /* VT_UI8 */
#ifdef _WIN32
  sprintf (s,"(ULONGLONG) %I64uULL", *((uint64_t *) dta)); break;
#else
  sprintf (s,"(ULONGLONG) %lluULL", *((uint64_t *) dta)); break;
#endif
  case 10: /* VT_ERROR */ sprintf (s, " = (SCODE) %dL", *((int32_t *) dta)); break;
  case 11: /* VT_BOOL */ sprintf (s,"(WINBOOL) %d", *((int16_t *) dta)); break;
  case 2: /* VT_I2 */ sprintf (s,"(short) %d", *((int16_t *) dta)); break;
  case 22: /* VT_INT */
  case 3: /* VT_I4 */ sprintf (s,"(int) %d", *((int32_t *) dta)); break;
  case 4: /* VT_R4 */ sprintf (s,"(float) %f", *((float *) dta)); break;
  case 5: /* VT_R8 */ sprintf (s,"(double) %g", *((double *) dta)); break;
  case 6: /* VT_CY */
#ifdef _WIN32
    sprintf (s,"(CY) %I64dLL", *((int64_t *) dta)); break;
#else
    sprintf (s,"(CY) %lldLL", *((int64_t *) dta)); break;
#endif
  case 8: /* VT_BSTR */
    sprintf (s,"L\"");
    while (sz>0 && sz < 4094)
    {
      if (strlen (s) >= 4080)
        {
          fprintf (stderr, "String too big (%lu)\n", (unsigned long) l);
          break;
        }
      if (*dta >= 0x20 && *dta <= 0x7f)
	sprintf (&s[strlen(s)], "%c", *dta);
      else
	sprintf (&s[strlen(s)],"\\%03o", *dta);
      dta++; --sz;
    }
    sprintf (&s[strlen(s)],"\"");
    break;
  case 25: /* VT_HRESULT */
  case 26: /* VT_PTR */
     sprintf (s,"(HRESULT) 0x%x", *((int32_t *) dta)); break;
  default:
    sprintf (s, "(%s) with %u size", decode_VT_name_tmp (vt), (uint32_t) l);
    break;
  }
  if (ret)
    *ret = strdup (s);
  return l + b;
}

size_t
getVT_size (uint32_t vt, unsigned char *dta, size_t *basesz)
{
  size_t ret = 0;
  size_t bsz = 2;

  switch (vt&0xfff) {
  case 0: /* VT_EMPTY */ break;
  case 1: /* VT_NULL */ break;
  case 2: /* VT_I2 */ ret = 2; break;
  case 3: /* VT_I4 */ ret = 4; break;
  case 4: /* VT_R4 */ ret = 4; break;
  case 5: /* VT_R8 */ ret = 8; break;
  case 6: /* VT_CY */ ret = 16; break;
  case 7: /* VT_DATE */ ret = 16; break;
  case 8: /* VT_BSTR */ ret = 0; bsz += 4; break;
  case 9: /* VT_DISPATCH */ ret = 4; break;
  case 10: /* VT_ERROR */ ret = 4; break;
  case 11: /* VT_BOOL */ ret = 2; break;
  case 12: /* VT_VARIANT */ ret = 0; break;
  case 13: /* VT_UNKNOWN */ ret = 4; break;
  case 14: /* VT_DECIMAL */ ret = 16; break;
  case 16: /* VT_I1 */ ret = 1; break;
  case 17: /* VT_UI1 */ ret = 1; break;
  case 18: /* VT_UI2 */ ret = 2; break;
  case 19: /* VT_UI4 */ ret = 4; break;
  case 20: /* VT_I8 */ ret = 8; break;
  case 21: /* VT_UI8 */ ret = 8; break;
  case 22: /* VT_INT */ ret = 4; break;
  case 23: /* VT_UINT */ ret = 4; break;
  case 24: /* VT_VOID */ ret = 0; break;
  case 25: /* VT_HRESULT */ ret = 4; break;
  case 26: /* VT_PTR */ ret = 4; break;
  case 27: /* VT_SAFEARRAY */ ret = 0; bsz+=4; break;
  case 28: /* VT_CARRAY */ ret = 0; bsz+=4; break;
  case 29: /* VT_USERDEFINED */ ret = 0; bsz+=4; break;
  case 30: /* VT_LPSTR */ ret = 4; break;
  case 31: /* VT_LPWSTR */ ret = 4; break;
  case 36: /* VT_RECORD */  ret = 0; bsz+=4; break;
  case 37: /* VT_INT_PTR */ ret = 4; break;
  case 38: /* VT_UINT_PTR */ ret = 4; break;
  case 64: /* VT_FILETIME */ ret = 8; break;
  case 65: /* VT_BLOB */  ret = 0; bsz+=4; break;
  case 66: /* VT_STREAM */  ret = 0; bsz+=4; break;
  case 67: /* VT_STORAGE */  ret = 0; bsz+=4; break;
  case 68: /* VT_STREAMED_OBJECT */  ret = 0; bsz+=4; break;
  case 69: /* VT_STORED_OBJECT */  ret = 0; bsz+=4; break;
  case 70: /* VT_BLOB_OBJECT */  ret = 0; bsz+=4; break;
  case 71: /* VT_CF*/ ret = 0; bsz+=4; break;
  case 72: /* VT_CLSID */ ret = 0; bsz+=4; break;
  case 73: /* VT_VERSIONED_STREAM */ ret = 0; bsz+=4; break;
  case  0xfff: /* VT_BSTR_BLOB */ ret = 0; bsz+=4; break;
  default:
    ret = 0; break;
    break;
  }
  if (bsz>2)
  {
    ret = *((uint32_t *) dta);
  }
  if (basesz)
    *basesz = bsz;
  return ret;
}

const char *
decode_VT_name_tmp (uint16_t vt)
{
  static char str[128];
  const char *name = "???";

  switch ((vt&0xfff))
  {
  case 0: /* VT_EMPTY */ name = "EMPTY"; break;
  case 1: /* VT_NULL */ name = "NULL"; break;
  case 2: /* VT_I2 */ name = "short"; break;
  case 3: /* VT_I4 */ name = "long"; break;
  case 4: /* VT_R4 */ name = "float"; break;
  case 5: /* VT_R8 */ name = "double"; break;
  case 6: /* VT_CY */ name = "CY"; break;
  case 7: /* VT_DATE */ name = "DATE"; break;
  case 8: /* VT_BSTR */ name = "BSTR"; break;
  case 9: /* VT_DISPATCH */ name = "IDispatch *"; break;
  case 10: /* VT_ERROR */ name = "SCODE"; break;
  case 11: /* VT_BOOL */ name = "WINBOOL"; break;
  case 12: /* VT_VARIANT */ name = "VARIANT"; break;
  case 13: /* VT_UNKNOWN */ name = "IUnknown *"; break;
  case 14: /* VT_DECIMAL */ name = "DECIMAL"; break;
  case 16: /* VT_I1 */ name = "CHAR"; break;
  case 17: /* VT_UI1 */ name = "UCHAR"; break;
  case 18: /* VT_UI2 */ name = "USHORT"; break;
  case 19: /* VT_UI4 */ name = "UINT"; break;
  case 20: /* VT_I8 */ name = "LONGLONG"; break;
  case 21: /* VT_UI8 */ name = "ULONGLONG"; break;
  case 22: /* VT_INT */ name = "int"; break;
  case 23: /* VT_UINT */ name = "unsigned int"; break;
  case 24: /* VT_VOID */ name = "void"; break;
  case 25: /* VT_HRESULT */ name = "HRESULT"; break;
  case 26: /* VT_PTR */ name = "PTR"; break;
  case 27: /* VT_SAFEARRAY */ name = "SAFEARRAY"; break;
  case 28: /* VT_CARRAY */ name = "CARRAY"; break;
  case 29: /* VT_USERDEFINED */ name = "USERDEFINED"; break;
  case 30: /* VT_LPSTR */ name = "LPSTR"; break;
  case 31: /* VT_LPWSTR */ name = "LPWSTR"; break;
  case 36: /* VT_RECORD */ name = "RECORD"; break;
  case 37: /* VT_INT_PTR */ name = "INT_PTR"; break;
  case 38: /* VT_UINT_PTR */ name = "UINT_PTR"; break;
  case 64: /* VT_FILETIME */ name = "FILETIME"; break;
  case 65: /* VT_BLOB */ name = "BLOB"; break;
  case 66: /* VT_STREAM */ name = "STREAM"; break;
  case 67: /* VT_STORAGE */ name = "STORAGE"; break;
  case 68: /* VT_STREAMED_OBJECT */ name = "STREAMED_OBJECT"; break;
  case 69: /* VT_STORED_OBJECT */ name = "STORED_OBJECT"; break;
  case 70: /* VT_BLOB_OBJECT */ name = "BLOB_OBJECT"; break;
  case 71: /* VT_CF*/ name = "CF"; break;
  case 72: /* VT_CLSID */ name = "CLSID"; break;
  case 73: /* VT_VERSIONED_STREAM */ name = "VERSIONED_STREAM"; break;
  case  0xfff: /* VT_BSTR_BLOB */ name = "BSTR_BLOB"; break;
  default:
    sprintf (str, "VT_%08x", vt & 0xfff);
    name = &str[0];
    break;
  }
  if ((vt & 0xf000) == 0x4000)
    strcat (str, " *");
  return name;
}

char *
TI_getVTorDref (sTITyps *ptyp,uint32_t vt, const char *varName, int beBase)
{
  char *name;
  if ((vt & 0x80000000)!=0)
  {
    name = strdup (decode_VT_name_tmp (vt));
    if (varName != NULL && varName[0] != 0)
    {
      name = ti_cat_freel (name, " ");
      name = ti_cat_freel (name, varName);
    }
  }
  else if ((vt&1)!=0)
    name = TI_get_typ_name (ptyp, vt & ~1, TITYP_IMPREF, varName);
  else if ((vt&3)!=0)
    name = TI_get_typ_name (ptyp, vt, TITYP_UNKNOWN, varName);
  else
  {
    if (!beBase)
      name = TI_get_typ_name (ptyp, vt, TITYP_DEREF, varName);
    else
      name = TI_get_typ_name (ptyp, vt, TITYP_TYPINFO_NAMES, varName);
  }
  return name;
}

int32_t
TI2_import_importlibs (sTITyps *iptr, unsigned char *dta, uint32_t len)
{
  sMSFT_ImpFiles *p;
  uint32_t off = 0;
  if (!len)
    return 0;
  while ((off + 13) < len)
  {
    char *h;
    unsigned short l;
    p = (sMSFT_ImpFiles *) &dta[off];
    l = (p->flag >> 2);
    h = (char *) malloc (l + 1);
    memcpy (h, &dta[off + 14], l);
    h[l] = 0;
    genidl_strlwr (h);
    TI_add_typ (iptr, (uint32_t) off, TITYP_IMP, 0,0,"",h,"");
    off = (off + 14 + l + 3) & ~3;
  }
  return 0;
}

int32_t
TI2_import_ref (sTITyps *gptr, unsigned char *dta, uint32_t len)
{
  sMSFT_RefTab *p;
  uint32_t off = 0;
  if (!len)
    return 0;
  while ((off + 15) < len)
    {
      char *h;
      p = (sMSFT_RefTab *) & dta[off];
      h = getTypeBOrImpRef (gptr, (uint32_t) p->oData1, "");
      TI_add_typ (gptr, (uint32_t) off, TITYP_REF, p->data2, p->oNextRef,"",h,"");
      free (h);
      off += sizeof (sMSFT_RefTab);
    }
  return 0;
}

int32_t
TI2_import_array (sTITyps *gptr, unsigned char *dta, uint32_t len)
{
  char postfix[256];
  uint32_t off = 0;
  sMSFT_ArrayDesc *p;
  if (!len)
    return 0;
  while ((off + 7) < len)
  {
    uint32_t num_dims;
    uint32_t size;
    char *name = NULL;
    uint32_t i;
    p = (sMSFT_ArrayDesc *) &dta[off];
    if ((p->vt & 0x80000000) != 0)
      name = strdup (decode_VT_name_tmp (p->vt));
    num_dims = p->count;
    size = p->size;
    if (!size)
      size = (num_dims * 2 * 4);
    postfix[0] = 0;
    for (i=0;i < num_dims; i++)
    {
      sprintf (&postfix[strlen (postfix)], "[%u]", p->vt_offset[i*2]);
    }
    TI_add_typ (gptr, (uint32_t) off, TITYP_ARRAY, TITYP_DEREF, (uint32_t) p->vt,"",
      (name ? name : ""), postfix);
    off += 8 + size;
    off +=3; off &= ~3;
  }
  return 0;
}

int32_t
TI2_import_importref (sTITyps *gptr, unsigned char *dta, uint32_t length)
{
  MSFT_ImpInfo *p;
  uint32_t off = 0;
  char *idstr;
  char *iname;
  if (!length)
    return 0;
  while ((off + 11) < length)
  {
    const char *str;
    char s[128];
    p = (MSFT_ImpInfo *) &dta[off];
    iname = TI_get_typ_name (gptr, (uint32_t) p->oImpFile, TITYP_IMP, "");
    
    if ((p->flags & 1) == 0)
      {
	sprintf (s, "TypeB_%x", p->oGuid);
      }
    else
      {
	char *ni = TI_get_typ_name (gptr, (uint32_t) p->oGuid & ~1, TITYP_GUIDS, "");
	if (ni)
	  {
	    strcpy (s, ni + 1);
	    if (strrchr (s, '\"') != NULL)
	      *strrchr (s, '\"')=0;
	    free (ni);
	  }
	else
	 sprintf (s, "Guid_%x", p->oGuid);
      }
    str = genidl_find_type (iname, &s[0]);
    /*if (!str)
      {
	 sprintf (s, "Name_%x", p->oGuid);
	 str = genidl_find_type (iname, &s[0]);
      }*/
    if (str)
      {
	TI_add_typ (gptr, (uint32_t) off, TITYP_IMPREF, 0,0, "", str, "");
      }
    else
      {
        idstr = (char *) malloc (strlen (s) + strlen (iname) + 2 + 10);
        sprintf (idstr, "%s_%s_%02x_%x", iname, s, p->flags, p->tkind);
	fprintf (stderr, "Type %s count: 0x%x tkind:0x%x not found\n", idstr, p->count, p->tkind);
        TI_add_typ (gptr, (uint32_t) off, TITYP_IMPREF, 0,0, "", idstr, "");  
        free (idstr);
      }
    if (iname)
      free (iname);
    off += 12;
  }
  return 0;
}

int32_t
TI2_import_customdataguid (sTITyps *gptr, unsigned char *dta, uint32_t len)
{
  if (gptr || dta || len)
    return 0;
  return 0;
}
