home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 4799 / source.7z / main.cpp next >
Encoding:
C/C++ Source or Header  |  2011-10-21  |  39.1 KB  |  1,227 lines

  1. #include "stdafx.h"
  2.  
  3. bool extract_TGP(const char* filename);
  4. bool process_MDL(const char* filename);
  5. bool parse(const char* data, deque<string>& list);
  6. string strip(const string& data, char c);
  7. string strip_trailing_spaces(const string& data);
  8.  
  9. class Exporter {
  10.  private :
  11.   struct Material {
  12.    string name;
  13.    string type;
  14.    deque<unsigned int> diffuse_texture_index;
  15.    float ambient[3];
  16.    float diffuse[3];
  17.    float specular[3];
  18.    float emissive[3];
  19.    float bump[3];
  20.    float opacity;
  21.    float shininess;
  22.    float reflectivity;
  23.   };
  24.   struct Texture {
  25.    string name;
  26.    string type;
  27.    string filename;
  28.   };
  29.   struct Skeleton {
  30.    string parent;
  31.    string type;
  32.    string order;
  33.    float translation[3];
  34.    float rotation[3];
  35.    float scale[3];
  36.   };
  37.   struct Polygon {
  38.    deque<unsigned int> material_index;
  39.    unsigned int face_index[3];
  40.    unsigned int uv_index[3];
  41.    unsigned int color[3];
  42.   };
  43.   struct Weight {
  44.    size_t index;
  45.    float value;
  46.   };
  47.   struct WeightMap {
  48.    size_t size;
  49.    string name;
  50.    deque<Weight> data;
  51.   };
  52.   struct Mesh {
  53.    string name;
  54.    deque<Polygon> polygon_list;
  55.    deque<vector3D<float>> vertex_list;
  56.    deque<WeightMap> weight_list;
  57.    deque<vector3D<float>> normal_list;
  58.    deque<vector2D<float>> uv_list;
  59.    deque<unsigned int> material_index_list;
  60.   };
  61.  private :
  62.   deque<string> line_list;
  63.   size_t curr_line;
  64.  private :
  65.   deque<Material> material_list;
  66.   deque<Texture> texture_list;
  67.   map<string, Skeleton> skeleton_list;
  68.   deque<Mesh> mesh_list;
  69.  private :
  70.   void clear(void);
  71.  public :
  72.   bool ProcessMaterialList(size_t n_materials);
  73.   bool ProcessMaterial(void);
  74.  public :
  75.   bool ProcessSkeletonList(size_t n_nodes);
  76.   bool ProcessSkeleton(void);
  77.  public :
  78.   bool ProcessMeshList(size_t n_meshes);
  79.   bool ProcessMesh(void);
  80.   bool ProcessPolygonList(size_t n_polygons, Mesh& mesh);
  81.   bool ProcessPolygon(Mesh& mesh);
  82.   bool ProcessVertexList(size_t n_points, Mesh& mesh);
  83.   bool ProcessWeightList(size_t n_weights, Mesh& mesh);
  84.   bool ProcessWeight(Mesh& mesh);
  85.   bool ProcessNormalList(size_t n_normals, Mesh& mesh);
  86.   bool ProcessUVList(size_t n_points, Mesh& mesh);
  87.   bool ProcessMaterialIndexList(size_t n_items, Mesh& mesh);
  88.  public :
  89.   bool ProcessTextureList(size_t n_textures);
  90.   bool ProcessTexture(void);
  91.  public :
  92.   bool process(const char* filename, const char* savename, const char* editname);
  93.  public :
  94.   Exporter();
  95.  ~Exporter();
  96.  private :
  97.   Exporter(const Exporter&);
  98.   void operator =(const Exporter&);
  99. };
  100.  
  101. int main()
  102. {
  103.  // create namelist
  104.  deque<string> namelist;
  105.  if(get_filename_list(namelist, "tgp")) {
  106.     for(size_t i = 0; i < namelist.size(); i++)
  107.         extract_TGP(namelist[i].c_str());
  108.    }
  109.  
  110.  // create model namelist
  111.  deque<string> filelist;
  112.  deque<string> savelist;
  113.  deque<string> editlist;
  114.  
  115.  if(!get_filename_list(filelist, "mdl"))
  116.     return -1;
  117.  
  118.  for(size_t i = 0; i < filelist.size(); i++)
  119.     {
  120.      // extract filename parameters
  121.      char param1[MAX_PATH];
  122.      char param2[MAX_PATH];
  123.      char param3[MAX_PATH];
  124.      char param4[MAX_PATH];
  125.      _splitpath(filelist[i].c_str(), param1, param2, param3, param4);
  126.  
  127.      // change extension
  128.      string savename(param1);
  129.      savename += param2;
  130.      savename += param3;
  131.      savename += ".ls";
  132.      savelist.push_back(savename);
  133.  
  134.      // change extension
  135.      string editname(param1);
  136.      editname += param2;
  137.      editname += param3;
  138.      editname += ".txt";
  139.      editlist.push_back(editname);
  140.     }
  141.  
  142.  // process model files
  143.  for(size_t i = 0; i < filelist.size(); i++) {
  144.      cout << "Processing " << filelist[i].c_str() << "..." << endl;
  145.      Exporter e;
  146.      e.process(filelist[i].c_str(), savelist[i].c_str(), editlist[i].c_str());
  147.     }
  148.  
  149.  return -1;
  150. }
  151.  
  152. Exporter::Exporter()
  153. {
  154. }
  155.  
  156. Exporter::~Exporter()
  157. {
  158. }
  159.  
  160. void Exporter::clear(void)
  161. {
  162.  // clear data
  163.  material_list.clear();
  164.  texture_list.clear();
  165.  skeleton_list.clear();
  166.  mesh_list.clear();
  167.  
  168.  // clear file data
  169.  line_list.clear();
  170.  curr_line = 0;
  171. }
  172.  
  173. bool Exporter::process(const char* filename, const char* savename, const char* editname)
  174. {
  175.  // clear data
  176.  clear();
  177.  
  178.  // open file
  179.  ifstream ifile(filename, ios::binary);
  180.  if(!ifile) return error("Cannot open file.");
  181.  
  182.  // edit file
  183.  ofstream efile(editname);
  184.  if(!ifile) return error("Cannot open file.");
  185.  
  186.  // load data line-by-line
  187.  for(;;)
  188.     {
  189.      // read line
  190.      char buffer[2048];
  191.      ifile.getline(buffer, 2048);
  192.      if(ifile.fail()) break;
  193.  
  194.      // must have data
  195.      string data(buffer);
  196.      if(data.length() == 0) continue;
  197.      if(data.length() == 1 && data[0] == 0x0A) continue;
  198.      if(data.length() == 1 && data[0] == 0x0D) continue;
  199.  
  200.      // remove comments
  201.      size_t position = data.find('#');
  202.      if(position == 0) continue;
  203.      if(position != string::npos) data = data.substr(0, position);
  204.      if(!data.length()) continue;
  205.  
  206.      // remove beginning spaces
  207.      size_t j = 0;
  208.      for(size_t i = 0; i < data.length(); i++) {
  209.          if(data[i] != 0x09) break;
  210.          else j++;
  211.         }
  212.      data = data.substr(j);
  213.      if(data.length() == 0) continue;
  214.      if(data.length() == 1 && data[0] == 0x0A) continue;
  215.      if(data.length() == 1 && data[0] == 0x0D) continue;
  216.  
  217.      // remove trailing spaces
  218.      data = strip_trailing_spaces(data);
  219.  
  220.      // insert line
  221.      line_list.push_back(data);
  222.      efile << data.c_str() << endl;
  223.     }
  224.  
  225.  // process data line-by-line
  226.  curr_line = 0;
  227.  do {
  228.     // parse line
  229.     deque<string> list;
  230.     if(parse(line_list[curr_line].c_str(), list) == false) break;
  231.  
  232.     // process root nodes
  233.     if(list[0] == "TGL Model Format Text Ver 0.8") curr_line++;
  234.     else if(list[0] == "MaterialList") {
  235.        if(list.size() < 2) return error("<MaterialList>: Expecting at least two arguments.");
  236.        cout << " <MaterialList>" << endl;
  237.        ProcessMaterialList(stoi(list[1].c_str()));
  238.       }
  239.     else if(list[0] == "MeshList") {
  240.        cout << " <MeshList>" << endl;
  241.        if(list.size() < 2) return error("<MeshList>: Expecting at least two arguments.");
  242.        ProcessMeshList(stoi(list[1].c_str()));
  243.       }
  244.     else if(list[0] == "SkeltonList") {
  245.        cout << " <SkeltonList>" << endl;
  246.        if(list.size() < 2) return error("<SkeletonList>: Expecting at least two arguments.");
  247.        ProcessSkeletonList(stoi(list[1].c_str()));
  248.       }
  249.     else if(list[0] == "TextureList") {
  250.        cout << " <TextureList>" << endl;
  251.        if(list.size() < 2) return error("<TextureList>: Expecting at least two arguments.");
  252.        ProcessTextureList(stoi(list[1].c_str()));
  253.       }
  254.     else curr_line++;
  255.  }
  256.  while(curr_line < line_list.size());
  257.  
  258.  // create lscript file
  259.  ofstream ofile(savename);
  260.  ofile << "main" << endl;
  261.  ofile << "{" << endl;
  262.  ofile << " editbegin();" << endl;
  263.  
  264.  // for each mesh
  265.  for(size_t i = 0; i < mesh_list.size(); i++)
  266.     {
  267.      // store texture
  268.      ofile << " editbegin();" << endl;
  269.      ofile << " uvmap = VMap(\"texture\", " << mesh_list[i].name << ", 2);" << endl;
  270.      ofile << " editend();" << endl;
  271.  
  272.      // set layer and surface
  273.      ofile << " lyrsetfg(" << (i + 1) << ");" << endl;
  274.      ofile << " setsurface(" << mesh_list[i].name  << ");" << endl;
  275.  
  276.      // save triangles
  277.      ofile << " editbegin();" << endl;
  278.      size_t point_index = 1;
  279.      for(size_t j = 0; j < mesh_list[i].polygon_list.size(); j++)
  280.         {
  281.          // point indeces
  282.          size_t a_index = point_index++;
  283.          size_t b_index = point_index++;
  284.          size_t c_index = point_index++;
  285.  
  286.          // get vertex index
  287.          unsigned short a_vertex_index = mesh_list[i].polygon_list[j].face_index[0];
  288.          unsigned short b_vertex_index = mesh_list[i].polygon_list[j].face_index[1];
  289.          unsigned short c_vertex_index = mesh_list[i].polygon_list[j].face_index[2];
  290.  
  291.          // get vertex value
  292.          vector3D<float> a_vertex = mesh_list[i].vertex_list[a_vertex_index];
  293.          vector3D<float> b_vertex = mesh_list[i].vertex_list[b_vertex_index];
  294.          vector3D<float> c_vertex = mesh_list[i].vertex_list[c_vertex_index];
  295.  
  296.          // get uv index
  297.          unsigned short a_uv_index = mesh_list[i].polygon_list[j].uv_index[0];
  298.          unsigned short b_uv_index = mesh_list[i].polygon_list[j].uv_index[1];
  299.          unsigned short c_uv_index = mesh_list[i].polygon_list[j].uv_index[2];
  300.  
  301.          // get uv value
  302.          vector2D<float> a_uv_value = mesh_list[i].uv_list[a_uv_index];
  303.          vector2D<float> b_uv_value = mesh_list[i].uv_list[b_uv_index];
  304.          vector2D<float> c_uv_value = mesh_list[i].uv_list[c_uv_index];
  305.  
  306.          // save points
  307.          ofile << " pointlist[" << a_index << "]" << " = " << "addpoint(" << a_vertex[0] << "," << a_vertex[1] << "," << a_vertex[2] << ");" << endl;
  308.          ofile << " pointlist[" << b_index << "]" << " = " << "addpoint(" << b_vertex[0] << "," << b_vertex[1] << "," << b_vertex[2] << ");" << endl;
  309.          ofile << " pointlist[" << c_index << "]" << " = " << "addpoint(" << c_vertex[0] << "," << c_vertex[1] << "," << c_vertex[2] << ");" << endl;
  310.  
  311.          // save uv map
  312.          ofile << " uvmap.setValue(pointlist[" << a_index << "]," << "@" << a_uv_value[0] << "," << -a_uv_value[1] << "@);" << endl;
  313.          ofile << " uvmap.setValue(pointlist[" << b_index << "]," << "@" << b_uv_value[0] << "," << -b_uv_value[1] << "@);" << endl;
  314.          ofile << " uvmap.setValue(pointlist[" << c_index << "]," << "@" << c_uv_value[0] << "," << -c_uv_value[1] << "@);" << endl;
  315.  
  316.          // save triangle
  317.          ofile << " addtriangle(pointlist[" << a_index << "], pointlist[" << b_index << "], pointlist[" << c_index << "]);" << endl;
  318.         }
  319.      ofile << " editend();" << endl;
  320.     }
  321.  
  322.  // finish lscript file
  323.  ofile << " editend();" << endl;
  324.  ofile << "}" << endl;
  325.  
  326.  return true;
  327. }
  328.  
  329. bool Exporter::ProcessMaterialList(size_t n_materials)
  330. {
  331.  // parse line
  332.  deque<string> parse_list;
  333.  
  334.  // line should be '{'
  335.  curr_line++;
  336.  parse_list.clear();
  337.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<MaterialList>: Empty token list.");
  338.  if(parse_list[0] != "{") return error("<MaterialList>: Expecting '{' token.");
  339.  
  340.  // process textures
  341.  for(size_t i = 0; i < n_materials; i++)
  342.      if(!ProcessMaterial()) return false;
  343.  
  344.  // line should be ''
  345.  curr_line++;
  346.  parse_list.clear();
  347.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<MaterialList>: Empty token list.");
  348.  if(parse_list[0] != "}") return error("<MaterialList>: Expecting '}' token.");
  349.  
  350.  // success
  351.  return true;
  352. }
  353.  
  354. bool Exporter::ProcessMaterial(void)
  355. {
  356.  // variables
  357.  deque<string> parse_list;
  358.  Material material;
  359.  
  360.  // line should be 'Material "name"'
  361.  curr_line++;
  362.  parse_list.clear();
  363.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Material>: Empty token list.");
  364.  if(parse_list.size() < 2) return error("<Material>: Expecting <Material> <name>.");
  365.  material.name = parse_list[1];
  366.  
  367.  // line should be '{'
  368.  curr_line++;
  369.  parse_list.clear();
  370.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Material>: Empty token list.");
  371.  if(parse_list[0] != "{") return error("<Material>: Expecting '{' token.");
  372.  
  373.  // process lines
  374.  for(;;)
  375.     {
  376.      // parse line
  377.      curr_line++;
  378.      parse_list.clear();
  379.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Material>: Empty token list.");
  380.  
  381.      // process tokens
  382.      if(parse_list.size() == 1) {
  383.         if(parse_list[0] == "}") break;
  384.         else return error("<Material>: Unexpected token.");
  385.        }
  386.      else if(parse_list.size() == 2) {
  387.         if(parse_list[0] == "type") material.type = parse_list[1];
  388.         else if(parse_list[0] == "Opacity") {
  389.            parse_list[1] = strip(parse_list[1], '(');
  390.            parse_list[1] = strip(parse_list[1], ')');
  391.            material.opacity = stof(parse_list[1]);
  392.           }
  393.         else if(parse_list[0] == "Shininess") {
  394.            parse_list[1] = strip(parse_list[1], '(');
  395.            parse_list[1] = strip(parse_list[1], ')');
  396.            material.shininess = stof(parse_list[1]);
  397.           }
  398.         else if(parse_list[0] == "Reflectivity") {
  399.            parse_list[1] = strip(parse_list[1], '(');
  400.            parse_list[1] = strip(parse_list[1], ')');
  401.            material.reflectivity = stof(parse_list[1]);
  402.           }
  403.         else if(parse_list[0] == "DiffuseTextureIndex")
  404.           {
  405.            // number of indices
  406.            size_t n_indices = stoi(parse_list[1].c_str());
  407.  
  408.            // line should be '{'
  409.            curr_line++;
  410.            parse_list.clear();
  411.            if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<DiffuseTextureIndex>: Empty token list.");
  412.            if(parse_list[0] != "{") return error("<DiffuseTextureIndex>: Expecting '{' token.");
  413.  
  414.            // process indicies
  415.            for(size_t i = 0; i < n_indices; i++) {
  416.                curr_line++;
  417.                parse_list.clear();
  418.                if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<DiffuseTextureIndex>: Empty token list.");
  419.                material.diffuse_texture_index.push_back(stoi(parse_list[0].c_str()));
  420.               }
  421.  
  422.            // line should be '}'
  423.            curr_line++;
  424.            parse_list.clear();
  425.            if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<DiffuseTextureIndex>: Empty token list.");
  426.            if(parse_list[0] != "}") return error("<DiffuseTextureIndex>: Expecting '}' token.");
  427.           }
  428.         else return error("<Material>: Unexpected token.");
  429.        }
  430.      else if(parse_list.size() == 4) {
  431.         if(parse_list[0] == "Ambient") {
  432.            parse_list[1] = strip(parse_list[1], '(');
  433.            parse_list[3] = strip(parse_list[3], ')');
  434.            material.ambient[0] = stof(parse_list[1]);
  435.            material.ambient[1] = stof(parse_list[2]);
  436.            material.ambient[2] = stof(parse_list[3]);
  437.           }
  438.         else if(parse_list[0] == "Diffuse") {
  439.            parse_list[1] = strip(parse_list[1], '(');
  440.            parse_list[3] = strip(parse_list[3], ')');
  441.            material.diffuse[0] = stof(parse_list[1]);
  442.            material.diffuse[1] = stof(parse_list[2]);
  443.            material.diffuse[2] = stof(parse_list[3]);
  444.           }
  445.         else if(parse_list[0] == "Specular") {
  446.            parse_list[1] = strip(parse_list[1], '(');
  447.            parse_list[3] = strip(parse_list[3], ')');
  448.            material.specular[0] = stof(parse_list[1]);
  449.            material.specular[1] = stof(parse_list[2]);
  450.            material.specular[2] = stof(parse_list[3]);
  451.           }
  452.         else if(parse_list[0] == "Emissive") {
  453.            parse_list[1] = strip(parse_list[1], '(');
  454.            parse_list[3] = strip(parse_list[3], ')');
  455.            material.emissive[0] = stof(parse_list[1]);
  456.            material.emissive[1] = stof(parse_list[2]);
  457.            material.emissive[2] = stof(parse_list[3]);
  458.           }
  459.         else if(parse_list[0] == "Bump") {
  460.            parse_list[1] = strip(parse_list[1], '(');
  461.            parse_list[3] = strip(parse_list[3], ')');
  462.            material.bump[0] = stof(parse_list[1]);
  463.            material.bump[1] = stof(parse_list[2]);
  464.            material.bump[2] = stof(parse_list[3]);
  465.           }
  466.         else return error("<Material>: Unexpected token.");
  467.        }
  468.     }
  469.  
  470.  // debug
  471.  //cout << "MATERIAL" << endl;
  472.  //cout << " name = " << material.name << endl;
  473.  //cout << " type = " << material.type << endl;
  474.  //cout << " ambient = " << material.ambient[0] << "," << material.ambient[1] << "," << material.ambient[2] << endl;
  475.  //cout << " diffuse = " << material.diffuse[0] << "," << material.diffuse[1] << "," << material.diffuse[2] << endl;
  476.  //cout << " specular = " << material.specular[0] << "," << material.specular[1] << "," << material.specular[2] << endl;
  477.  //cout << " emissive = " << material.emissive[0] << "," << material.emissive[1] << "," << material.emissive[2] << endl;
  478.  //cout << " bump = " << material.bump[0] << "," << material.bump[1] << "," << material.bump[2] << endl;
  479.  //cout << " opacity = " << material.opacity << endl;
  480.  //cout << " shininess = " << material.shininess << endl;
  481.  //cout << " reflectivity = " << material.reflectivity << endl;
  482.  
  483.  // insert texture
  484.  material_list.push_back(material);
  485.  return true;
  486. }
  487.  
  488. bool Exporter::ProcessSkeletonList(size_t n_nodes)
  489. {
  490.  // parse line
  491.  deque<string> parse_list;
  492.  
  493.  // line should be '{'
  494.  curr_line++;
  495.  parse_list.clear();
  496.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<SkeletonList>: Empty token list.");
  497.  if(parse_list[0] != "{") return error("<SkeletonList>: Expecting '{' token.");
  498.  
  499.  // process textures
  500.  for(size_t i = 0; i < n_nodes; i++)
  501.      if(!ProcessSkeleton()) return false;
  502.  
  503.  // line should be ''
  504.  curr_line++;
  505.  parse_list.clear();
  506.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<SkeletonList>: Empty token list.");
  507.  if(parse_list[0] != "}") return error("<SkeletonList>: Expecting '}' token.");
  508.  
  509.  // success
  510.  return true;
  511. }
  512.  
  513. bool Exporter::ProcessSkeleton(void)
  514. {
  515.  // variables
  516.  deque<string> parse_list;
  517.  Skeleton skeleton;
  518.  
  519.  // line should be 'Texture "name"'
  520.  curr_line++;
  521.  parse_list.clear();
  522.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Skeleton>: Empty token list.");
  523.  if(parse_list.size() < 2) return error("<Skeleton>: Expecting <Skeleton> <name>.");
  524.  string skeleton_name = parse_list[1];
  525.  
  526.  // line should be '{'
  527.  curr_line++;
  528.  parse_list.clear();
  529.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Skeleton>: Empty token list.");
  530.  if(parse_list[0] != "{") return error("<Skeleton>: Expecting '{' token.");
  531.  
  532.  // process lines
  533.  for(;;)
  534.     {
  535.      // parse line
  536.      curr_line++;
  537.      parse_list.clear();
  538.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Skeleton>: Empty token list.");
  539.  
  540.      // process tokens
  541.      if(parse_list.size() == 1) {
  542.         if(parse_list[0] == "}") break;
  543.         else return error("<Skeleton>: Unexpected token.");
  544.        }
  545.      else if(parse_list.size() == 2) {
  546.         if(parse_list[0] == "Parent") skeleton.parent = parse_list[1];
  547.         else if(parse_list[0] == "Type") skeleton.type = parse_list[1];
  548.         else if(parse_list[0] == "RotationOrder") skeleton.order = parse_list[1];
  549.         else return error("<Skeleton>: Unexpected token.");
  550.        }
  551.      else if(parse_list.size() == 4) {
  552.         if(parse_list[0] == "Trans") {
  553.            parse_list[1] = strip(parse_list[1], '(');
  554.            parse_list[3] = strip(parse_list[3], ')');
  555.            skeleton.translation[0] = stof(parse_list[1]);
  556.            skeleton.translation[1] = stof(parse_list[2]);
  557.            skeleton.translation[2] = stof(parse_list[3]);
  558.           }
  559.         else if(parse_list[0] == "Rotate") {
  560.            parse_list[1] = strip(parse_list[1], '(');
  561.            parse_list[3] = strip(parse_list[3], ')');
  562.            skeleton.rotation[0] = stof(parse_list[1]);
  563.            skeleton.rotation[1] = stof(parse_list[2]);
  564.            skeleton.rotation[2] = stof(parse_list[3]);
  565.           }
  566.         else if(parse_list[0] == "Scale") {
  567.            parse_list[1] = strip(parse_list[1], '(');
  568.            parse_list[3] = strip(parse_list[3], ')');
  569.            skeleton.scale[0] = stof(parse_list[1]);
  570.            skeleton.scale[1] = stof(parse_list[2]);
  571.            skeleton.scale[2] = stof(parse_list[3]);
  572.           }
  573.         else return error("<Skeleton>: Unexpected token.");
  574.        }
  575.      else return error("<Skeleton>: Unexpected number of tokens.");
  576.     }
  577.  
  578.  // insert texture
  579.  typedef map<string, Skeleton>::value_type value_type;
  580.  skeleton_list.insert(value_type(skeleton_name, skeleton));
  581.  
  582.  // debug
  583.  //cout << "SKELETON" << endl;
  584.  //cout << " parent = " << skeleton.parent << endl;
  585.  //cout << " type = " << skeleton.type << endl;
  586.  //cout << " order = " << skeleton.order << endl;
  587.  //cout << " translation = " << skeleton.translation[0] << "," << skeleton.translation[1] << "," << skeleton.translation[2] << endl;
  588.  //cout << " rotation = " << skeleton.rotation[0] << "," << skeleton.rotation[1] << "," << skeleton.rotation[2] << endl;
  589.  //cout << " scale = " << skeleton.scale[0] << "," << skeleton.scale[1] << "," << skeleton.scale[2] << endl;
  590.  //cout << endl;
  591.  
  592.  return true;
  593. }
  594.  
  595. bool Exporter::ProcessMeshList(size_t n_meshes)
  596. {
  597.  // parse line
  598.  deque<string> parse_list;
  599.  
  600.  // line should be '{'
  601.  curr_line++;
  602.  parse_list.clear();
  603.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<MeshList>: Empty token list.");
  604.  if(parse_list[0] != "{") return error("<MeshList>: Expecting '{' token.");
  605.  
  606.  // process textures
  607.  for(size_t i = 0; i < n_meshes; i++)
  608.      if(!ProcessMesh()) return false;
  609.  
  610.  // line should be '}'
  611.  curr_line++;
  612.  parse_list.clear();
  613.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<MeshList>: Empty token list.");
  614.  if(parse_list[0] != "}") return error("<MeshList>: Expecting '}' token.");
  615.  
  616.  // success
  617.  return true;
  618. }
  619.  
  620. bool Exporter::ProcessMesh(void)
  621. {
  622.  // variables
  623.  deque<string> parse_list;
  624.  Mesh mesh;
  625.  
  626.  // line should be 'Mesh "name"'
  627.  curr_line++;
  628.  parse_list.clear();
  629.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Mesh>: Empty token list.");
  630.  if(parse_list.size() < 2) return error("<Mesh>: Expecting <Mesh> <name>.");
  631.  mesh.name = parse_list[1];
  632.  
  633.  // line should be '{'
  634.  curr_line++;
  635.  parse_list.clear();
  636.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Mesh>: Empty token list.");
  637.  if(parse_list[0] != "{") return error("<Mesh>: Expecting '{' token.");
  638.  
  639.  // process lines
  640.  for(;;)
  641.     {
  642.      // parse line
  643.      curr_line++;
  644.      parse_list.clear();
  645.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Mesh>: Empty token list.");
  646.  
  647.      // process tokens
  648.      if(parse_list.size() == 1) {
  649.         if(parse_list[0] == "}") break;
  650.         else return error("<Mesh>: Unexpected token.");
  651.        }
  652.      else if(parse_list.size() == 2) {
  653.         if(parse_list[0] == "PolygonList") {
  654.            if(!ProcessPolygonList(stoi(parse_list[1]), mesh))
  655.               return false;
  656.           }
  657.         else if(parse_list[0] == "VertexList") {
  658.            if(!ProcessVertexList(stoi(parse_list[1]), mesh))
  659.               return false;
  660.           }
  661.         else if(parse_list[0] == "WeightList") {
  662.            if(!ProcessWeightList(stoi(parse_list[1]), mesh))
  663.               return false;
  664.           }
  665.         else if(parse_list[0] == "NormalList") {
  666.            if(!ProcessNormalList(stoi(parse_list[1]), mesh))
  667.               return false;
  668.           }
  669.         else if(parse_list[0] == "UVList") {
  670.            if(!ProcessUVList(stoi(parse_list[1]), mesh))
  671.               return false;
  672.           }
  673.         else if(parse_list[0] == "MaterialIndexList") {
  674.            if(!ProcessMaterialIndexList(stoi(parse_list[1]), mesh))
  675.               return false;
  676.           }
  677.         else return error("<Mesh>: Unexpected token.");
  678.        }
  679.     }
  680.  
  681.  // debug
  682.  //cout << "Mesh" << endl;
  683.  
  684.  // insert texture
  685.  mesh_list.push_back(mesh);
  686.  return true;
  687. }
  688.  
  689. bool Exporter::ProcessPolygonList(size_t n_polygons, Mesh& mesh)
  690. {
  691.  // parse line
  692.  deque<string> parse_list;
  693.  
  694.  // line should be '{'
  695.  curr_line++;
  696.  parse_list.clear();
  697.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<PolygonList>: Empty token list.");
  698.  if(parse_list[0] != "{") return error("<PolygonList>: Expecting '{' token.");
  699.  
  700.  // process textures
  701.  for(size_t i = 0; i < n_polygons; i++)
  702.      if(!ProcessPolygon(mesh)) return false;
  703.  
  704.  // line should be '}'
  705.  curr_line++;
  706.  parse_list.clear();
  707.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<PolygonList>: Empty token list.");
  708.  if(parse_list[0] != "}") return error("<PolygonList>: Expecting '}' token.");
  709.  
  710.  // success
  711.  return true;
  712. }
  713.  
  714. bool Exporter::ProcessPolygon(Mesh& mesh)
  715. {
  716.  // variables
  717.  deque<string> parse_list;
  718.  Polygon polygon;
  719.  
  720.  // line should be <Polygon> <n>
  721.  curr_line++;
  722.  parse_list.clear();
  723.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Polygon>: Empty token list.");
  724.  if(parse_list.size() < 2) return error("<Polygon>: Expecting <Polygon> <n>.");
  725.  
  726.  // line should be '{'
  727.  curr_line++;
  728.  parse_list.clear();
  729.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Polygon>: Empty token list.");
  730.  if(parse_list[0] != "{") return error("<Polygon>: Expecting '{' token.");
  731.  
  732.  // process lines
  733.  for(;;)
  734.     {
  735.      // parse line
  736.      curr_line++;
  737.      parse_list.clear();
  738.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Polygon>: Empty token list.");
  739.  
  740.      // process tokens
  741.      if(parse_list[0] == "}") break;
  742.      else if(parse_list[0] == "Material")
  743.        {
  744.         size_t n_indices = stoi(parse_list[1]);
  745.  
  746.         // line should be '{'
  747.         curr_line++;
  748.         parse_list.clear();
  749.         if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Polygon>: Empty token list.");
  750.         if(parse_list[0] != "{") return error("<Polygon>: Expecting '{' token.");
  751.  
  752.         // read indices
  753.         for(size_t i = 0; i < n_indices; i++) {
  754.             curr_line++;
  755.             parse_list.clear();
  756.             if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Polygon>: Empty token list.");
  757.             polygon.material_index.push_back(stoi(parse_list[0].c_str()));
  758.            }
  759.  
  760.         // line should be '}'
  761.         curr_line++;
  762.         parse_list.clear();
  763.         if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Polygon>: Empty token list.");
  764.         if(parse_list[0] != "}") return error("<Polygon>: Expecting '}' token.");
  765.        }
  766.      else if(parse_list[0] == "Face")
  767.        {
  768.         parse_list[2] = strip(parse_list[2], '(');
  769.         parse_list[4] = strip(parse_list[4], ')');
  770.         polygon.face_index[0] = stoi(parse_list[2]);
  771.         polygon.face_index[1] = stoi(parse_list[3]);
  772.         polygon.face_index[2] = stoi(parse_list[4]);
  773.        }
  774.      else if(parse_list[0] == "UV")
  775.        {
  776.         parse_list[2] = strip(parse_list[2], '(');
  777.         parse_list[4] = strip(parse_list[4], ')');
  778.         polygon.uv_index[0] = stoi(parse_list[2]);
  779.         polygon.uv_index[1] = stoi(parse_list[3]);
  780.         polygon.uv_index[2] = stoi(parse_list[4]);
  781.        }
  782.      else if(parse_list[0] == "Color")
  783.        {
  784.         parse_list[2] = strip(parse_list[2], '(');
  785.         parse_list[4] = strip(parse_list[4], ')');
  786.         polygon.color[0] = stoul(parse_list[2]); // careful here! crashes for stoi
  787.         polygon.color[1] = stoul(parse_list[3]); // careful here! crashes for stoi
  788.         polygon.color[2] = stoul(parse_list[4]); // careful here! crashes for stoi
  789.        }
  790.      else
  791.         return error("<Polygon>: Unexpected token.");
  792.     }
  793.  
  794.  // insert texture
  795.  mesh.polygon_list.push_back(polygon);
  796.  return true;
  797. }
  798.  
  799. bool Exporter::ProcessVertexList(size_t n_points, Mesh& mesh)
  800. {
  801.  // parse line
  802.  deque<string> parse_list;
  803.  
  804.  // line should be '{'
  805.  curr_line++;
  806.  parse_list.clear();
  807.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<VertexList>: Empty token list.");
  808.  if(parse_list[0] != "{") return error("<VertexList>: Expecting '{' token.");
  809.  
  810.  // process points
  811.  for(size_t i = 0; i < n_points; i++)
  812.     {
  813.      // parse line
  814.      curr_line++;
  815.      parse_list.clear();
  816.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<VertexList>: Empty token list.");
  817.      if(parse_list.size() != 3) return error("<VertexList>: Invalid vertex.");
  818.  
  819.      // add vertex
  820.      vector3D<float> v;
  821.      v[0] = stof(parse_list[0]);
  822.      v[1] = stof(parse_list[1]);
  823.      v[2] = stof(parse_list[2]);
  824.      mesh.vertex_list.push_back(v);
  825.     }
  826.  
  827.  // line should be '}'
  828.  curr_line++;
  829.  parse_list.clear();
  830.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<VertexList>: Empty token list.");
  831.  if(parse_list[0] != "}") return error("<VertexList>: Expecting '}' token.");
  832.  
  833.  // success
  834.  return true;
  835. }
  836.  
  837. bool Exporter::ProcessWeightList(size_t n_weights, Mesh& mesh)
  838. {
  839.  // parse line
  840.  deque<string> parse_list;
  841.  
  842.  // line should be '{'
  843.  curr_line++;
  844.  parse_list.clear();
  845.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<WeightList>: Empty token list.");
  846.  if(parse_list[0] != "{") return error("<WeightList>: Expecting '{' token.");
  847.  
  848.  // process points
  849.  for(size_t i = 0; i < n_weights; i++)
  850.      ProcessWeight(mesh);
  851.  
  852.  // line should be '}'
  853.  curr_line++;
  854.  parse_list.clear();
  855.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<WeightList>: Empty token list.");
  856.  if(parse_list[0] != "}") return error("<WeightList>: Expecting '}' token.");
  857.  
  858.  // success
  859.  return true;
  860. }
  861.  
  862. bool Exporter::ProcessWeight(Mesh& mesh)
  863. {
  864.  // variables
  865.  deque<string> parse_list;
  866.  WeightMap wmap;
  867.  
  868.  // line should be <Weight> <n> <name>
  869.  curr_line++;
  870.  parse_list.clear();
  871.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Weight>: Empty token list.");
  872.  if(parse_list.size() != 3) return error("<Weight>: Expecting <Weight> <n> <name>.");
  873.  
  874.  wmap.size = stoi(parse_list[1]);
  875.  wmap.name = parse_list[2];
  876.  
  877.  // line should be '{'
  878.  curr_line++;
  879.  parse_list.clear();
  880.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Weight>: Empty token list.");
  881.  if(parse_list[0] != "{") return error("<Weight>: Expecting '{' token.");
  882.  
  883.  // process weights
  884.  for(size_t i = 0; i < wmap.size; i++)
  885.     {
  886.      // parse line
  887.      curr_line++;
  888.      parse_list.clear();
  889.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Weight>: Empty token list.");
  890.  
  891.      // insert weight
  892.      Weight w;
  893.      w.index = stoi(parse_list[0].c_str());
  894.      w.value = stof(parse_list[0].c_str());
  895.      wmap.data.push_back(w);
  896.     }
  897.  
  898.  // line should be '}'
  899.  curr_line++;
  900.  parse_list.clear();
  901.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Weight>: Empty token list.");
  902.  if(parse_list[0] != "}") return error("<Weight>: Expecting '}' token.");
  903.  
  904.  // insert texture
  905.  mesh.weight_list.push_back(wmap);
  906.  return true;
  907. }
  908.  
  909. bool Exporter::ProcessNormalList(size_t n_normals, Mesh& mesh)
  910. {
  911.  // parse line
  912.  deque<string> parse_list;
  913.  
  914.  // line should be '{'
  915.  curr_line++;
  916.  parse_list.clear();
  917.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<NormalList>: Empty token list.");
  918.  if(parse_list[0] != "{") return error("<NormalList>: Expecting '{' token.");
  919.  
  920.  // process points
  921.  for(size_t i = 0; i < n_normals; i++)
  922.     {
  923.      // parse line
  924.      curr_line++;
  925.      parse_list.clear();
  926.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<NormalList>: Empty token list.");
  927.      if(parse_list.size() != 3) return error("<NormalList>: Invalid vertex.");
  928.  
  929.      // add vertex
  930.      vector3D<float> v;
  931.      v[0] = stof(parse_list[0]);
  932.      v[1] = stof(parse_list[1]);
  933.      v[2] = stof(parse_list[2]);
  934.      mesh.normal_list.push_back(v);
  935.     }
  936.  
  937.  // line should be '}'
  938.  curr_line++;
  939.  parse_list.clear();
  940.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<NormalList>: Empty token list.");
  941.  if(parse_list[0] != "}") return error("<NormalList>: Expecting '}' token.");
  942.  
  943.  // success
  944.  return true;
  945. }
  946.  
  947. bool Exporter::ProcessUVList(size_t n_points, Mesh& mesh)
  948. {
  949.  // parse line
  950.  deque<string> parse_list;
  951.  
  952.  // line should be '{'
  953.  curr_line++;
  954.  parse_list.clear();
  955.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<UVList>: Empty token list.");
  956.  if(parse_list[0] != "{") return error("<UVList>: Expecting '{' token.");
  957.  
  958.  // process points
  959.  for(size_t i = 0; i < n_points; i++)
  960.     {
  961.      // parse line
  962.      curr_line++;
  963.      parse_list.clear();
  964.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<UVList>: Empty token list.");
  965.      if(parse_list.size() != 2) return error("<UVList>: Invalid vertex.");
  966.  
  967.      // add vertex
  968.      vector2D<float> v;
  969.      v[0] = stof(parse_list[0]);
  970.      v[1] = stof(parse_list[1]);
  971.      mesh.uv_list.push_back(v);
  972.     }
  973.  
  974.  // line should be '}'
  975.  curr_line++;
  976.  parse_list.clear();
  977.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<UVList>: Empty token list.");
  978.  if(parse_list[0] != "}") return error("<UVList>: Expecting '}' token.");
  979.  
  980.  // success
  981.  return true;
  982. }
  983.  
  984. bool Exporter::ProcessMaterialIndexList(size_t n_items, Mesh& mesh)
  985. {
  986.  // parse line
  987.  deque<string> parse_list;
  988.  
  989.  // line should be '{'
  990.  curr_line++;
  991.  parse_list.clear();
  992.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<MaterialIndexList>: Empty token list.");
  993.  if(parse_list[0] != "{") return error("<MaterialIndexList>: Expecting '{' token.");
  994.  
  995.  // process material indices
  996.  for(size_t i = 0; i < n_items; i++)
  997.     {
  998.      // parse line
  999.      curr_line++;
  1000.      parse_list.clear();
  1001.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<MaterialIndexList>: Empty token list.");
  1002.      if(parse_list.size() != 1) return error("<MaterialIndexList>: Invalid index.");
  1003.  
  1004.      // add material index
  1005.      mesh.material_index_list.push_back(stoi(parse_list[0].c_str()));
  1006.     }
  1007.  
  1008.  // line should be '}'
  1009.  curr_line++;
  1010.  parse_list.clear();
  1011.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<MaterialIndexList>: Empty token list.");
  1012.  if(parse_list[0] != "}") return error("<MaterialIndexList>: Expecting '}' token.");
  1013.  
  1014.  // success
  1015.  return true;
  1016. }
  1017.  
  1018. bool Exporter::ProcessTextureList(size_t n_textures)
  1019. {
  1020.  // parse line
  1021.  deque<string> parse_list;
  1022.  
  1023.  // line should be '{'
  1024.  curr_line++;
  1025.  parse_list.clear();
  1026.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<TextureList>: Empty token list.");
  1027.  if(parse_list[0] != "{") return error("<TextureList>: Expecting '{' token.");
  1028.  
  1029.  // process textures
  1030.  for(size_t i = 0; i < n_textures; i++)
  1031.      if(!ProcessTexture()) return false;
  1032.  
  1033.  // line should be '}'
  1034.  curr_line++;
  1035.  parse_list.clear();
  1036.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<TextureList>: Empty token list.");
  1037.  if(parse_list[0] != "}") return error("<TextureList>: Expecting '}' token.");
  1038.  
  1039.  // success
  1040.  return true;
  1041. }
  1042.  
  1043. bool Exporter::ProcessTexture(void)
  1044. {
  1045.  // variables
  1046.  deque<string> parse_list;
  1047.  Texture texture;
  1048.  
  1049.  // line should be 'Texture "name"'
  1050.  curr_line++;
  1051.  parse_list.clear();
  1052.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Texture>: Empty token list.");
  1053.  if(parse_list.size() < 2) return error("<Texture>: Expecting <Texture> <name>.");
  1054.  texture.name = parse_list[1];
  1055.  
  1056.  // line should be '{'
  1057.  curr_line++;
  1058.  parse_list.clear();
  1059.  if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Texture>: Empty token list.");
  1060.  if(parse_list[0] != "{") return error("<Texture>: Expecting '{' token.");
  1061.  
  1062.  // process lines
  1063.  for(;;)
  1064.     {
  1065.      // parse line
  1066.      curr_line++;
  1067.      parse_list.clear();
  1068.      if(parse(line_list[curr_line].c_str(), parse_list) == false) return error("<Texture>: Empty token list.");
  1069.  
  1070.      // process tokens
  1071.      if(parse_list.size() == 1) {
  1072.         if(parse_list[0] == "}") break;
  1073.         else return error("<Texture>: Unexpected token.");
  1074.        }
  1075.      else if(parse_list.size() == 2) {
  1076.         if(parse_list[0] == "type") texture.type = parse_list[1];
  1077.         else if(parse_list[0] == "file") texture.filename = parse_list[1];
  1078.         else return error("<Texture>: Unexpected token.");
  1079.        }
  1080.     }
  1081.  
  1082.  // insert texture
  1083.  texture_list.push_back(texture);
  1084.  return true;
  1085. }
  1086.  
  1087. bool extract_TGP(const char* filename)
  1088. {
  1089.  ifstream ifile(filename, ios::binary);
  1090.  if(!ifile) return error("Cannot open file.");
  1091.  
  1092.  unsigned int h01 = LE_read_uint32(ifile); // magic
  1093.  unsigned int h02 = LE_read_uint32(ifile); // 1
  1094.  unsigned int h03 = LE_read_uint32(ifile); // 0
  1095.  unsigned int h04 = LE_read_uint32(ifile); // offset to data
  1096.  
  1097.  // read filelist
  1098.  struct filedata {
  1099.   string name;
  1100.   unsigned int offset;
  1101.   unsigned int length;
  1102.  };
  1103.  deque<filedata> filelist;
  1104.  for(size_t i = 0; i < h04; i++)
  1105.     {
  1106.      // read filename
  1107.      char buffer[1024];
  1108.      ifile.read(&buffer[0], 0x60);
  1109.  
  1110.      // read offsets
  1111.      unsigned int o1, waste01;
  1112.      unsigned int o2, waste02;
  1113.      ifile.read((char*)&o1, sizeof(o1));
  1114.      ifile.read((char*)&waste01, sizeof(waste01));
  1115.      ifile.read((char*)&o2, sizeof(o2));
  1116.      ifile.read((char*)&waste02, sizeof(waste02));
  1117.  
  1118.      // add item
  1119.      filedata fd = { buffer, o1, o2 };
  1120.      filelist.push_back(fd);
  1121.     }
  1122.  
  1123.  // get full path filename
  1124.  char full_filename[1024];
  1125.  GetFullPathNameA(filename, 1024, full_filename, NULL);
  1126.  cout << full_filename << endl;
  1127.  
  1128.  // get full path
  1129.  char drive[1024];
  1130.  char dir[1024];
  1131.  _splitpath(full_filename, drive, dir, NULL, NULL);
  1132.  string full_pathname = drive;
  1133.  full_pathname += dir;
  1134.  cout << full_pathname.c_str() << endl;
  1135.  
  1136.  for(size_t i = 0; i < filelist.size(); i++)
  1137.     {
  1138.      // get full path filename
  1139.      string fname = full_pathname;
  1140.      fname += filelist[i].name;
  1141.  
  1142.      // get full path
  1143.      char drive[1024];
  1144.      char dir[1024];
  1145.      _splitpath(fname.c_str(), drive, dir, NULL, NULL);
  1146.      string fpath = drive;
  1147.      fpath += dir;
  1148.  
  1149.      // create path if not already created
  1150.      SHCreateDirectoryEx(NULL, fpath.c_str(), NULL);
  1151.  
  1152.      // create file
  1153.      ofstream ofile(fname, ios::binary);
  1154.      if(!ofile) return error("Could not create file.");
  1155.      cout << "Processing " << filelist[i].name.c_str() << "..." << endl;
  1156.  
  1157.      // move to offset and read data
  1158.      ifile.seekg(filelist[i].offset);
  1159.      char* data = new char[filelist[i].length];
  1160.      ifile.read(data, filelist[i].length);
  1161.  
  1162.      // save data
  1163.      ofile.write(data, filelist[i].length);
  1164.  
  1165.      // delete data
  1166.      delete[] data;
  1167.      data = 0;
  1168.     }
  1169.  
  1170.  return true;
  1171. }
  1172.  
  1173. bool parse(const char* data, deque<string>& list)
  1174. {
  1175.  // must have data
  1176.  size_t size = strlen(data);
  1177.  if(size == 0) return false;
  1178.  
  1179.  // count spaces
  1180.  size_t spaces = 0;
  1181.  for(size_t i = 0; i < size; i++) if(data[i] == ' ') spaces++;
  1182.  if(spaces == size) return false;
  1183.  
  1184.  // parse
  1185.  size_t i = 0;
  1186.  while(i < size)
  1187.       {
  1188.        // find first non-whitespace character
  1189.        while(data[i] == ' ') i++;
  1190.        if(i == size) return true;
  1191.        
  1192.        // find next whitespace character
  1193.        size_t j = i + 1;
  1194.        while(data[j] != '\0' && data[j] != ' ') j++;
  1195.        
  1196.        // add string
  1197.        string temp(data);
  1198.        list.push_back(temp.substr(i, j - i));
  1199.  
  1200.        // increment
  1201.        i = j + 1;
  1202.       }
  1203.  
  1204.  return true;
  1205. }
  1206.  
  1207. string strip(const string& data, char c)
  1208. {
  1209.  string retval = "";
  1210.  for(size_t i = 0; i < data.length(); i++) {
  1211.      if(data[i] == c) continue;
  1212.      else retval += data[i];
  1213.     }
  1214.  return retval;
  1215. }
  1216.  
  1217. string strip_trailing_spaces(const string& data)
  1218. {
  1219.  string retval = "";
  1220.  for(size_t i = 0; i < data.length(); i++) {
  1221.      size_t j = (data.length() - 1) - i;
  1222.      if(data[j] == 0x09 || data[j] == 0x0A || data[j] == 0x0D) continue;
  1223.      else retval.push_back(data[j]);
  1224.     }
  1225.  std::reverse(retval.begin(), retval.end());
  1226.  return retval;
  1227. }