//
// Copyright (C) 1999-2004 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <WScom.h>
#include <WSDserialize.h>
#include <WSClistData.h>
#include <WSCconductor.h>
#include <WSCserializeData.h>

WSMFclassInit(WSDserialize,WSCroot);

WSCserializeData::WSCserializeData(){
  _data_name = NULL;
  _data_name_len = 0;
  _type = WS_DcLong;
  _type_name_len = 0;
  _type_name = NULL;
  _data_len = 0;
  _data = NULL;
  _cache_ptr = 0;
};

void WSCserializeData::clearChildren(){
  long num = _children.getNum();
  long i;
  for(i=0; i< num; i++){
    WSCserializeData* serialize = (WSCserializeData*)_children.getData(i);
    delete serialize;
  }
  _children.clear();
};

WSCserializeData::~WSCserializeData(){
  if (_data != NULL){
    delete (char*)_data;
  }
  if (_type_name != NULL){
    delete _type_name;
  }
  if (_data_name != NULL){
    delete _data_name;
  }

  clearChildren();
};

long WSCserializeData::size(){
   long ret = 1; //data_name_len

   if (_data_name != NULL){
     ret += strlen(_data_name); //data_name
   }

   ret += 2; //type,_type_name_len

   if (_type_name != NULL){
     ret += strlen(_type_name); //_type_name
   }

   ret += 4; //_data_len

   ret += _data_len; //_data

   long num = _children.getNum();
   long i;
   for(i=0; i< num; i++){
     WSCserializeData* cdata = (WSCserializeData*)_children.getData(i);
     ret += cdata->size();
   }
   return ret;
};

long WSCserializeData::write(WSDserialize* serialize){
//printf("WSCserializeData::write len=%d %d\n",sizeof(char),_data_name_len);
  serialize->_write(&_data_name_len,sizeof(char));
//printf("WSCserializeData::write len=%d #%s#\n",_data_name_len,_data_name);
  serialize->_write(_data_name,_data_name_len);

  serialize->_write(&_type,sizeof(char));
  serialize->_write(&_type_name_len,sizeof(char));

  if (_type == WS_DcObject){
    serialize->_write(_type_name,_type_name_len);
    char tmp2[4];
    long num = _children.getNum();
    WSGIbinType()->memcpy4b(tmp2,num);
    long ret = serialize->_write(tmp2,sizeof(char)*4);
    long i;
    WSCserializeData* dt;
    for(i=0; i< num; i++){
      dt = (WSCserializeData*)_children.getData(i);
      dt->write(serialize);
    }
    return ret;
  }else{
    char tmp[4];
    WSGIbinType()->memcpy4b(tmp,_data_len);
    serialize->_write(tmp,sizeof(char)*4);
    long ret = serialize->_write(_data,_data_len);
    return ret;
  }
};

long WSCserializeData::read(WSDserialize* serialize){
//printf("WSCserializeData::read read start size=%d\n",sizeof(char));
  long len = serialize->_read(&_data_name_len,sizeof(char));
//printf("WSCserializeData::read len=%d %d\n",len,_data_name_len);
  if (len < (long)sizeof(char)){
    return 0;
  }
  if (_data_name != NULL){
    delete _data_name;
    _data_name = NULL;
  }
  _data_name = new char[_data_name_len+1];
  len = serialize->_read(_data_name,_data_name_len);
//printf("WSCserializeData::read len=%d _data_name_len\n",len,_data_name_len);
  if (len <_data_name_len){
    _data_name[0] = 0;
    return 0;
  }
  _data_name[_data_name_len] = 0;
//printf("WSCserializeData::read len=%d #%s#\n",_data_name_len,_data_name);

  len = serialize->_read(&_type,sizeof(char));
  if (len <(long)sizeof(char)){
    _type = 0;
    return 0;
  }
  len = serialize->_read(&_type_name_len,sizeof(char));
  if (len <(long)sizeof(char)){
    _type_name_len = 0;
    return 0;
  }

  if (_type_name != NULL){
    delete _type_name;
    _type_name = NULL;
  }
  if (_type == WS_DcObject){
    _type_name = new char[_type_name_len+1];
    len = serialize->_read(_type_name,_type_name_len);
    if (len < _type_name_len){
      _type_name[0] = 0;
      return 0;
    }
    _type_name[_type_name_len] = 0;

    char tmp2[4];
    long ret = serialize->_read(tmp2,sizeof(char)*4);
    if (ret < (long)sizeof(char)*4){
      return 0;
    }
    long num;
    WSGIbinType()->memscan4b(&num,tmp2);

    long i;
    WSCserializeData* dt;
    for(i=0; i< num; i++){
      dt = new WSCserializeData;
      len = dt->read(serialize);
      if (len == 0){
        return 0;
      }
      _children.add(dt);
    }
    return ret;
  }else{
    char tmp[4];
    len = serialize->_read(tmp,sizeof(char)*4);
    if (len < (long)sizeof(char)*4){
      delete (char*)_data;
      _data = NULL;
      return 0;
    }
    WSGIbinType()->memscan4b(&_data_len,tmp);
    if (_data != NULL){
      delete (char*)_data;
      _data = NULL;
    }
    _data = new char[_data_len];
    long ret = serialize->_read(_data,_data_len);
    if(ret < _data_len){
      return 0;
    }
    return ret;
  }
};



WSDserialize::WSDserialize(){
  _current_data = NULL;
  _transact = False;
  _need_save = False;
  _path.setString("./",WS_EN_ISO8859_1);
  _use_socket = False;
}

WSDserialize::~WSDserialize(){
  long i;
  long num = _data_list.getNum();
  WSCserializeData* dt;
  for(i=0; i< num; i++){
    dt  = (WSCserializeData*)_data_list.getData(i);
    if (dt != NULL){
      delete dt;
    }
  }
}

char* WSDserialize::getPath(){
  return _path.getString();
}

void WSDserialize::setPath(char* path){
  _path.setString(path);
}

long WSDserialize::_write_data(WSCserializeData* dt,char* type,void* data, long items){
  if (dt->_data != NULL){
      delete (char*)dt->_data;
      dt->_data = NULL;
  }
  if (type[0] == '#'){
    if (!strcmp(type,WS_DcRString)){
      char* d = WSGFstrdup((char*)data);
      dt->_type = WS_DcString;
      dt->_type_name_len = 0;
      dt->_data_len = strlen(d)+1;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRShort)){
      char* d = new char[2*items];
      short* dat = (short*)data;
      long i;
      for(i=0; i < items; i++){
        WSGIbinType()->memcpy2b(&d[2*i],dat[i]);
      }
      dt->_type = WS_DcShort;
      dt->_type_name_len = 0;
      dt->_data_len = 2*items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRUShort)){
      char* d = new char[2*items];
      WSCushort* dat = (WSCushort*)data;
      long i;
      for(i=0; i < items; i++){
        WSGIbinType()->memcpy2b(&d[2*i],dat[i]);
      }
      dt->_type = WS_DcUShort;
      dt->_type_name_len = 0;
      dt->_data_len = 2*items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRChar)){
      char* d = new char[items];
      memcpy(d,data,items);
      dt->_type = WS_DcChar;
      dt->_type_name_len = 0;
      dt->_data_len = items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRLong)){
      char* d = new char[4*items];
      long* dat = (long*)data;
      long i;
      for(i=0; i < items; i++){
        WSGIbinType()->memcpy4b(&d[4*i],dat[i]);
      }
      dt->_type = WS_DcLong;
      dt->_type_name_len = 0;
      dt->_data_len = 4*items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRUChar)){
      char* d = new char[items];
      memcpy(d,data,items);
      dt->_type = WS_DcUChar;
      dt->_type_name_len = 0;
      dt->_data_len = items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRULong)){
      char* d = new char[4*items];
      WSCulong* dat = (WSCulong*)data;
      long i;
      for(i=0; i < items; i++){
        WSGIbinType()->memcpy4b(&d[4*i],dat[i]);
      }
      dt->_type = WS_DcULong;
      dt->_type_name_len = 0;
      dt->_data_len = 4*items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRInt) ){
      char* d = new char[4*items];
      int* dat = (int*)data;
      long i;
      for(i=0; i < items; i++){
        WSGIbinType()->memcpy4b(&d[4*i],dat[i]);
      }
      dt->_type = WS_DcInt;
      dt->_type_name_len = 0;
      dt->_data_len = 4*items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRUInt)){
      char* d = new char[4*items];
      WSCuint* dat = (WSCuint*)data;
      long i;
      for(i=0; i < items; i++){
        WSGIbinType()->memcpy4b(&d[4*i],dat[i]);
      }
      dt->_type = WS_DcUInt;
      dt->_type_name_len = 0;
      dt->_data_len = 4*items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRFloat)){
      char* d = new char[4*items];
      float* dat = (float*)data;
      long i;
      for(i=0; i < items; i++){
        WSGIbinType()->memcpy4b(&d[4*i],(long)dat[i]);
      }
      dt->_type = WS_DcFloat;
      dt->_type_name_len = 0;
      dt->_data_len = 4*items;
      dt->_data = d;
    }else
    if (!strcmp(type,WS_DcRDouble)){
      char* d = new char[8*items];
      double* dat = (double*)data;
      long i;
      for(i=0; i < items; i++){
        WSGIbinType()->memcpy8b(&d[8*i],&dat[i]);
      }
      dt->_type = WS_DcDouble;
      dt->_type_name_len = 0;
      dt->_data_len = 8*items;
      dt->_data = d;
    }
  }else{

    WSCtypeServer* sv = WSGIconductor()->searchTypeServer(type);
    if (sv == NULL){
      return WS_ERR_NOTYPE;
    }

    //DEVELOLP//XXXXXXXXXXXXXXX   ここの型変換は配列でない
    long num = sv->getParentClassNum();
    long i;
    for(i=0; i< num; i++){
      char* ptype = sv->getParentClassName(i);
      void* pptr = sv->getParentClassPtr(ptype,data);
      if (ptype[0] == '#'){
        _write_data(dt, ptype, pptr, items);
      }else{
        _write_sub_class(dt, ptype, pptr, items);
      }
    }

    void (*svh)(WSDserialize*,void*);
    svh = (void (*)(WSDserialize*,void*))sv->getSaveHandler();
    WSCserializeData* bk = _current_data;
    _current_data = dt;
    svh(this,data); //ハンドラでセーブ
    _current_data = bk;
  }
  return WS_NO_ERR;
}

long WSDserialize::_write_sub_class(WSCserializeData* dt,char* type,void* data,long items){

  WSCtypeServer* sv = WSGIconductor()->searchTypeServer(type);
  if (sv == NULL){
    return WS_ERR_NOTYPE;
  }

  //DEVELOP//XXXXXXXXXXXXXXX   ここの型変換は配列でない
  long num = sv->getParentClassNum();
  long i;
  for(i=0; i< num; i++){
    char* ptype = sv->getParentClassName(i);
    void* pptr = sv->getParentClassPtr(ptype,data);
    if (ptype[0] == '#'){
      _write_data(dt, ptype, pptr, items);
    }else{
      _write_sub_class(dt, ptype, pptr,items);
    }
  }

  void (*svh)(WSDserialize*,void*);
  svh = (void (*)(WSDserialize*,void*))sv->getSaveHandler();
  WSCserializeData* bk = _current_data;
  _current_data = dt;
  svh(this,data); //ハンドラでセーブ
  _current_data = bk;
  return WS_NO_ERR;
}

long WSDserialize::_save(WSClistData* dt_list,char* type,char* name,void* data){

  long num = dt_list->getNum();
  long i;
  //DEVELOP//高速化をするよちがある XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  for(i=0; i< num; i++){
    WSCserializeData* dt = (WSCserializeData*)dt_list->getData(i);
    if (!strcmp(dt->_data_name,name)){
      dt->clearChildren();
      dt->_type = WS_DcObject;
      dt->_type_name_len = strlen(type);
      dt->_data_len = 0;
      if (dt->_type_name != NULL){
          delete dt->_type_name;
          dt->_type_name = NULL;
      }
      dt->_type_name = WSGFstrdup(type);
      _write_data(dt,type,data,1);
      return WS_NO_ERR;
    }
  }

  WSCserializeData* dt = new WSCserializeData;
  dt->_data_name = WSGFstrdup(name);
  dt->_data_name_len = strlen(name);
  dt->_type = WS_DcObject;
  dt->_type_name = WSGFstrdup(type);
  dt->_type_name_len = strlen(type);
  dt->_data_len = 0;

   dt_list->add(dt);
  _write_data(dt,type,data,1);
  return WS_NO_ERR;
}

long WSDserialize::save(char* type,char* name,void* data){
  if (_use_socket != False){
    WSClistData tmp_list;
    _current_data = NULL;
    long ret = _save(&tmp_list,type,name,data);
    if (ret == WS_NO_ERR){
      WSCserializeData* dt = (WSCserializeData*)tmp_list[0];
      if (dt != NULL){
//printf("WSDserialize::save call dt->write\n");
        ret = dt->write(this);
        delete dt;
        return ret;
      }
    }
    return WS_ERR;
  }
  _need_save = True;
  _current_data = NULL;
  return _save(&_data_list,type,name,data);
}

long WSDserialize::saveData(char* type,char* name,void* data){
  _need_save = True;
  return _save(&_current_data->_children,type,name,data);
}

long WSDserialize::_read_data(WSCserializeData* dt,char* type,void* data, long items){
  if (type[0] == '#'){
    if (!strcmp(type,WS_DcRString)){
      //TEST  //array は未対応
      strcpy((char*)data,(char*)dt->_data);
    }else
    if (!strcmp(type,WS_DcRShort)){
      long i;
      char* dat = (char*)dt->_data;
      short* outd = (short*)data;
      for(i=0; i < items; i++){
        WSGIbinType()->memscan2b((short*)&outd[i],&dat[2*i]);
      }
    }else
    if (!strcmp(type,WS_DcRUShort)){
      long i;
      char* dat = (char*)dt->_data;
      WSCushort* outd = (WSCushort*)data;
      for(i=0; i < items; i++){
        WSGIbinType()->memscan2b((short*)&outd[i],&dat[2*i]);
      }
    }else
    if (!strcmp(type,WS_DcRChar)){
      memcpy(data,dt->_data,items);
    }else
    if (!strcmp(type,WS_DcRLong)){
      long i;
      char* dat = (char*)dt->_data;
      long* outd = (long*)data;
      for(i=0; i < items; i++){
        WSGIbinType()->memscan4b(&outd[i],&dat[4*i]);
      }
    }else
    if (!strcmp(type,WS_DcRUChar)){
      memcpy(data,dt->_data,items);
    }else
    if (!strcmp(type,WS_DcRULong)){
      long i;
      char* dat = (char*)dt->_data;
      long* outd = (long*)data;
      for(i=0; i < items; i++){
        WSGIbinType()->memscan4b(&outd[i],&dat[4*i]);
      }
    }else
    if (!strcmp(type,WS_DcRInt) ){
      long i;
      char* dat = (char*)dt->_data;
      long* outd = (long*)data;
      for(i=0; i < items; i++){
        WSGIbinType()->memscan4b(&outd[i],&dat[4*i]);
      }
    }else
    if (!strcmp(type,WS_DcRUInt)){
      long i;
      char* dat = (char*)dt->_data;
      long* outd = (long*)data;
      for(i=0; i < items; i++){
        WSGIbinType()->memscan4b(&outd[i],&dat[4*i]);
      }
    }else
    if (!strcmp(type,WS_DcRFloat)){
      long i;
      char* dat = (char*)dt->_data;
      float* outd = (float*)data;
      for(i=0; i < items; i++){
        WSGIbinType()->memscan4b((long*)&outd[i],&dat[4*i]);
      }
    }else
    if (!strcmp(type,WS_DcRDouble)){
      long i;
      char* dat = (char*)dt->_data;
      double* outd = (double*)data;
      for(i=0; i < items; i++){
        WSGIbinType()->memscan8b(&outd[i],&dat[8*i]);
      }
    }
  }else{
    //DEVELOP//XXXXXXXXXXXXXXX   あとでここも配列対応にする。
    WSCtypeServer* sv = WSGIconductor()->searchTypeServer(dt->_type_name);
    if (sv == NULL){
      return WS_ERR_NOTYPE;
    }

    //DEVELOP//XXXXXXXXXXXXXXX   ここの型変換は配列でない
    long num = sv->getParentClassNum();
    long i;
    for(i=0; i< num; i++){
      char* ptype = sv->getParentClassName(i);
      void* pptr = sv->getParentClassPtr(ptype,data);
      if (ptype[0] == '#'){
        _read_data(dt, ptype, pptr, items);
      }else{
        _read_sub_class(dt, ptype, pptr, items);
      }
    }

    void (*lvh)(WSDserialize*,void*);
    lvh = (void (*)(WSDserialize*,void*))sv->getLoadHandler();
    WSCserializeData* bk = _current_data;
    _current_data = dt;
    lvh(this,data); //ハンドラでロード
    _current_data = bk;
  }
  return WS_NO_ERR;
}

long WSDserialize::_read_sub_class(WSCserializeData* dt,char* type,void* data,long items){

  WSCtypeServer* sv = WSGIconductor()->searchTypeServer(type);
  if (sv == NULL){
    return WS_ERR_NOTYPE;
  }

  //DEVELOP//XXXXXXXXXXXXXXX   ここの型変換は配列でない
  long num = sv->getParentClassNum();
  long i;
  for(i=0; i< num; i++){
    char* ptype = sv->getParentClassName(i);
    void* pptr = sv->getParentClassPtr(ptype,data);
    if (ptype[0] == '#'){
      _read_data(dt, ptype, pptr, items);
    }else{
      _read_sub_class(dt, ptype, pptr,items);
    }
  }

  void (*lvh)(WSDserialize*,void*);
  lvh = (void (*)(WSDserialize*,void*))sv->getLoadHandler();
  WSCserializeData* bk = _current_data;
  _current_data = dt;
  lvh(this,data); //ハンドラでロード
  _current_data = bk;
  return WS_NO_ERR;
}


long WSDserialize::_load(WSCserializeData* pdt,WSClistData* dt_list,char* type,char* name,void* data){
  long num = dt_list->getNum();
//printf("here0..num=%d\n",num);
  long i;
  if (pdt != NULL && pdt->_cache_ptr < (WSCulong)num){
    //前回検索した場所から検索する
    //なぜかというと、普通は順番にデータを読み出すので
    //検索するより該当する確率きわめて高い
    for( i= pdt->_cache_ptr; i< num; i++){ 
      WSCserializeData* dt = (WSCserializeData*)dt_list->getData(i);
      if (dt->_data_name == NULL){
        continue;
      }
      if ((dt->_data_name[0] == name[0] && !strcmp(dt->_data_name,name)) ||
          (name[0] == '*' && name[1] == 0 )){
        pdt->_cache_ptr++;
//printf("here1..\n");
        _read_data(dt,type,data,1);
        return WS_NO_ERR;
      }
    }
  }

  for(i=0; i< num; i++){
    WSCserializeData* dt = (WSCserializeData*)dt_list->getData(i);
    if (dt->_data_name == NULL){
      continue;
    }
//printf("dt->_data_name=#%s# #%s#\n",dt->_data_name,name);
    if ((dt->_data_name[0] == name[0] && !strcmp(dt->_data_name,name)) ||
          (name[0] == '*' && name[1] == 0 )){
//    if (!strcmp(dt->data_name,name) || !strcmp(name,"*")){
      if (pdt != NULL){
        pdt->_cache_ptr = i+1;
      }
      _read_data(dt,type,data,1);
      return WS_NO_ERR;
    }
  }

  return WS_ERR_NOOBJ;
}

long WSDserialize::load(char* type,char* name,void* data){
  if (_use_socket){
    _current_data = NULL;
    WSCserializeData* dt = new WSCserializeData();
    dt->read(this);
//printf("WSDserialize::load call dt->read type=#%s#\n",type);
    WSClistData tmp_list;
    tmp_list.add((void*)dt);

    long ret = _load(NULL,&tmp_list,type,name,data);
    delete dt;
    return ret;
  }

  _current_data = NULL;
  return _load(NULL,&_data_list,type,name,data);
}

long WSDserialize::loadData(char* type,char* name,void* data){
  return _load(_current_data,&_current_data->_children,type,name,data);
}

long WSDserialize::_load_alloc(WSCserializeData* pdt,WSClistData* dt_list,char* type,char* name,void** ptr,void* construct_data){
  long num = dt_list->getNum();
  long i;
  WSCulong cpoint = 0;
  if (pdt != NULL && pdt->_cache_ptr < (WSCulong)num){
    //前回検索した場所から検索する
    //なぜかというと、普通は順番にデータを読み出すので
    //検索するより該当する確率きわめて高い
    cpoint = 0;
  }

  for( i= cpoint; i< num; i++){ 
    WSCserializeData* dt = (WSCserializeData*)dt_list->getData(i);
    if (dt->_data_name == 0){
      continue;
    }
    if ((dt->_data_name[0] == name[0] && !strcmp(dt->_data_name,name)) ||
          (name[0] == '*' && name[1] == 0 )){
//    if (!strcmp(_dt->data_name,name) || !strcmp(name,"*") ){
      char* target_type = dt->_type_name;
      if (target_type == NULL){
        switch(dt->_type){
          case WS_DcInt:    target_type = "#int";break;
          case WS_DcShort:  target_type = "#sht";break;
          case WS_DcLong:   target_type = "#lng";break;
          case WS_DcChar:   target_type = "#chr";break;
          case WS_DcString: target_type = "#str";break;
          case WS_DcFloat:  target_type = "#flt";break;
          case WS_DcDouble: target_type = "#dbl";break;
          default: return WS_ERR_NOTYPE;
        }
      }

      if (!strcmp(type,target_type)){ //型が同じであれば
        if (type[0] == '#'){   //デフォルトの型であれば
          if (!strcmp(type,WS_DcRString)){
              *ptr = new char[strlen((char*)dt->_data)+1];
              strcpy((char*)*ptr,(char*)dt->_data);
              return WS_NO_ERR;
          }else if (!strcmp(type,WS_DcRShort)){
              *ptr = new char[2];
              char* dat = (char*)dt->_data;
              short* outd = (short*)*ptr;
              WSGIbinType()->memscan2b(outd,dat);
              return WS_NO_ERR;
          }else if (!strcmp(type,WS_DcRChar)){
              *ptr = new char[1];
              *((char*)*ptr) = *((char*)dt->_data);
              return WS_NO_ERR;
          }else if (!strcmp(type,WS_DcRLong) || !strcmp(type,WS_DcRInt) || !strcmp(type,WS_DcRFloat)){
              *ptr = new char[4];
              char* dat = (char*)dt->_data;
              long* outd = (long*)*ptr;
              WSGIbinType()->memscan4b(outd,dat);
              return WS_NO_ERR;

          }else if (!strcmp(type,WS_DcRDouble)){
            *ptr = new char[8];
            char* dat = (char*)dt->_data;
            WSGIbinType()->memscan8b(*ptr,dat);
            return WS_NO_ERR;
          }
          if (pdt != NULL){
            pdt->_cache_ptr = i+1;
          }
          _read_data(dt,target_type,*ptr,1);
          return WS_NO_ERR;
        }else{ //ユーザ定義の型であれば
          WSCtypeServer* sv = WSGIconductor()->searchTypeServer(target_type);
          if (sv == NULL){
            return WS_ERR_NOTYPE;
          }
          *ptr = sv->createInstance(construct_data);
          if (*ptr == NULL){
            return WS_ERR_NOTYPE;
          }
          if (pdt != NULL){
            pdt->_cache_ptr = i+1;
          }
          _read_data(dt,target_type,*ptr,1);
          return WS_NO_ERR;
        }
      }else{
        if (type[0] == '#'){   //デフォルトの型であればあきらめる(型が違う)
          *ptr = NULL;
          return WS_ERR_INVALID_DATA;
        }

        WSCtypeServer* sv = WSGIconductor()->searchTypeServer(target_type);
        if (sv == NULL){
          return WS_ERR_NOTYPE;
        }
        void* tmp = sv->createInstance(construct_data);
        if (tmp == NULL){
          return WS_ERR_NOTYPE;
        }
        if (pdt != NULL){
          pdt->_cache_ptr = i+1;
        }
        _read_data(dt,target_type,tmp,1);
        *ptr = sv->getParentClassPtr(type,tmp); //型が違うのでコンバート
        if (*ptr == NULL){
//          delete tmp;
          sv->deleteInstance(tmp);
          return WS_ERR_INVALID_DATA;
        }
        return WS_NO_ERR;
      }
    }
  }

  //最初から検索しても見つからなかった。
  if (pdt == NULL || cpoint == 0){
    return WS_ERR_NOOBJ;
  }

  //改めて検索しなおし。
  pdt->_cache_ptr = 0;
  return _load_alloc(pdt,dt_list, type, name, ptr, construct_data);
}

long WSDserialize::loadAlloc(char* type,char* name,void** ptr,void* construct_data){
  if (_use_socket){
    _current_data = NULL;
    WSCserializeData* dt = new WSCserializeData();
//printf("WSDserialize::loadAlloc call dt->read type=#%s#\n",type);
    dt->read(this);

    WSClistData tmp_list;
    tmp_list.add((void*)dt);

    long ret = _load_alloc(NULL,&tmp_list,type,name,ptr,construct_data);
    delete dt;
    return ret;
  }

  _current_data = NULL;
  return _load_alloc(NULL,&_data_list,type,name,ptr,construct_data);
}

long WSDserialize::loadAllocData(char* type,char* name,void** ptr,void* construct_data){
  return _load_alloc(_current_data,&_current_data->_children,type,name,ptr,construct_data);
}

long WSDserialize::searchInstance(char* type,char mode,char*** otype,char*** onames,long* num){
  _current_data = NULL;
  return _search_instance(&_data_list,type,mode,otype,onames,num);
}

long WSDserialize::searchInstanceData(char* type,char mode,char*** otype,char*** onames,long* num){
  return _search_instance(&_current_data->_children,type,mode,otype,onames,num);
}

long WSDserialize::_search_instance(WSClistData* dt_list,char* type,char mode,char*** otype,char*** onames,long* num){
  long n = dt_list->getNum();
  long i;
  WSClistData nlist;
  WSClistData clist;


  //DEVEOP//高速化をするよちがある XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  for(i=0; i< n; i++){
    WSCserializeData* dt = (WSCserializeData*)dt_list->getData(i);
    char* target_type = dt->_type_name;
    if (target_type == NULL){
      switch(dt->_type){
        case WS_DcInt:    target_type = "#int";break;
        case WS_DcShort:  target_type = "#sht";break;
        case WS_DcLong:   target_type = "#lng";break;
        case WS_DcChar:   target_type = "#chr";break;
        case WS_DcString: target_type = "#str";break;
        case WS_DcFloat:  target_type = "#flt";break;
        case WS_DcDouble: target_type = "#dbl";break;
        default:   continue;
      }
    }
    if ( !strcmp(type,target_type)){ 
    //型が同じであれば
       nlist.add(type);
       clist.add(dt->_data_name);
    }else if ( target_type[0] == '#' ){ 
    //型がC++ スタンダードの型ならばあきらめる
       continue;

    }else if ( mode == WS_SEARCH_INHERIT ){
       //継承関係の検証を行ってみる
       WSCtypeServer* sv = WSGIconductor()->searchTypeServer(target_type);
       if (sv == NULL){
          continue;
       }
       if (sv->isParentClass(type) != False){
       //継承関係だったら
         clist.add(target_type);
         nlist.add(dt->_data_name);
       }
    }
  }
  n = nlist.getNum();
  *num = n;

  if (n != 0){
    char** otypelist = *otype  = new char*[n];
    char** onamelist = *onames = new char*[n];

    for(i=0; i < n; i++){
      otypelist[i] = (char*)clist.getData(i);
      onamelist[i] = (char*)nlist.getData(i);
    }
    return WS_NO_ERR;
  }else{
    *otype  = 0;
    *onames = 0;
    return WS_ERR_NOOBJ;
  }
}

WSCbool WSDserialize::underTransaction(){
  return _transact;
}

void WSDserialize::setUnderTransaction(WSCbool fl){
  if (fl != False){
    _transact = True;
  }else{
    _transact = False;
  }
}

long WSDserialize::beginTransaction(char* field){
  _field.setString(field);
  long ret = _open(field,WS_RW);
  if (ret != WS_NO_ERR){
    return ret;
  }

  setUnderTransaction(True);

  char tmp[4];
  long num = 0;
  ret = _read(tmp,sizeof(char)*4);
  if (ret == 0){
    return WS_NO_ERR;
  }

  WSGIbinType()->memscan4b(&num,tmp);
  long i;
  for(i=0; i< num; i++){
    WSCserializeData* dt = new WSCserializeData();
    _data_list.add(dt);
    dt->read(this);
  }

  return WS_NO_ERR;
}

long WSDserialize::endTransaction(){
  if (_need_save == False){
    return WS_NO_ERR;
  }
  _need_save = False;
  _seek(0);
  long num = _data_list.getNum();
  char tmp[4];
  WSGIbinType()->memcpy4b(tmp,num);
  _write(tmp,sizeof(char)*4);

  setUnderTransaction(False);

  long i;
  for(i=0; i< num; i++){
    WSCserializeData* dt = (WSCserializeData*)_data_list.getData(i);
    dt->write(this);
  }
  for(i=0; i< num; i++){
    WSCserializeData* dt = (WSCserializeData*)_data_list.getData(i);
    delete dt;
  }
  _data_list.clear();
  _close();
  return WS_NO_ERR;
}

