Jump to content

Convering DBC to CSV. Script, but malfunctioning.


Guest Peec

Recommended Posts

I was surfing around trying to find a source for a DBCtoCSV extractor. I found this source, it works...

Usage: main.exe DBCfile.dbc

It will print the DBC as CSV to the commandline...

However, it doesn't support STRINGS in the DBC file, it outputs everything as an integer.

Anyone know how to fix this?

I also wanted to rewrite this to PHP version, but my knowledge of streams and working with bytes and files is limited in PHP. But for now i will use exec("main.exe", $op) ...

Example error:

It outputs :

1,12,1,4140,49,50,1,1065353216,7,7,15007,1096,4,81,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16712191,10,17,10,0

Instead of exampleways:

1,12,1,4140,49,50,1,1065353216,7,7,15007,1096,4,81,4,0,0,0,0,"WARRIOR","Warrior",0,0,0,0,0,0,0,0,0,16712191,10,17,10,0

Here's the C++ script. Compilable on windows atleast:

#include <cassert>
#include <cstdio>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;

const int MAXFIELDS = 256;
char DELIMITER = ',';

struct header {
   char id[4];
   size_t nRecords, nFields, recordSize, textSize;
};

union field {
   float fval;
   int ival;
};

enum types {
   T_INT,
   T_FLOAT,
   T_STR
};

int gInt[MAXFIELDS], gFloat[MAXFIELDS], gStr[MAXFIELDS];

void analyzeRow(header &h, FILE *f, char *text)
{
   field x;

   for (int i=0; i<h.nFields; i++) {
       fread(&x, 4, 1, f);

       if ((x.fval<-0.1f && x.fval > -10000.0f) || (x.fval>0.1f && x.fval < 10000.0f)) {
           gFloat[i]++;
       } else {
           if ((x.ival>10) && (x.ival<h.textSize) && (text[x.ival-1]==0)) {
               gStr[i]+=5;

           } else {
               gInt[i]++;
           }
       }

   }

}

int types[MAXFIELDS];



void printTypes(header &h)
{
   for (int i=0; i<h.nFields; i++) {
       if (i!=0) cout << DELIMITER;
       string s;
       switch (types[i]) {
           case T_INT: s = "INT"; break;
           case T_FLOAT: s = "FLOAT"; break;
           case T_STR: s = "STRING"; break;
       }
       cout << s;
   }
   cout << endl;
}

void printRow(header &h, FILE *f, char *text)
{
   field x[MAXFIELDS];
   fread(&x, h.nFields, 4, f);

   for (int i=0; i<h.nFields; i++) {
       if (i!=0) cout << DELIMITER;
       string s;
       switch (types[i]) {
           case T_INT:
               cout << x[i].ival;
               break;
           case T_FLOAT:
               cout << x[i].fval;
               break;
           case T_STR:
               s = string(text + x[i].ival);
               bool delim = false;
               for (int k=0; k<s.length(); k++) {
                   if (s[k]==DELIMITER) {
                       delim = true;
                       break;
                   }
               }
               if (delim) cout << "\\"";
               cout << s;
               if (delim) cout << "\\"";
               break;
       }
   }
   cout << endl;
}

void convert(const char *fname)
{
   string fn = fname;
   int l = fn.length();
   if (l<5) return;
   fn[l-4] = '.';
   fn[l-3] = 'c';
   fn[l-2] = 's';
   fn[l-1] = 'v';

   FILE *f = fopen(fname, "r");
   header h;
   fread(&h, 5, 4, f);

   assert(h.nFields <= MAXFIELDS);

   char *text;
   text = new char[h.textSize];

   fseek(f, h.nRecords * h.recordSize, SEEK_CUR);
   fread(text, h.textSize, 1, f);
   fseek(f, 0x14, SEEK_SET);

   // analyze first 300 or so rows
   int nr = 300;
   if (nr > h.nRecords) nr = h.nRecords;

   for (int i=0; i<MAXFIELDS; i++) gInt[i] = gFloat[i] = gStr[i] = 0;

   for (int i=0; i<nr; i++) analyzeRow(h, f, text);

   int val[MAXFIELDS];
   for (int i=0; i<MAXFIELDS; i++) {
       types[i] = T_INT;
       val[i] = gInt[i];

       if (gFloat[i] > val[i]) {
           types[i] = T_FLOAT;
           val[i] = gFloat[i];
       }

       if (gStr[i] > val[i]) {
           types[i] = T_STR;
       }
   }

   // output
   fseek(f, 0x14, SEEK_SET);


   printTypes(h);

   for (int i=0; i<h.nRecords; i++) {
       printRow(h, f, text);
   }



   delete[] text;
}

int main(int argc, char *argv[])
{
   for (int i=1; i<argc; i++) {
       if (!strcmp(argv[i],"-d") && i<argc-2) {
           DELIMITER = argv[i+1][0];
       }
       convert(argv[i]);
   }
   return 0;
}

Link to comment
Share on other sites

I don't think anyone will debug some code you found who knows where...

This code seems to guess the field type, and guesses wrong. Or it just screws up on the file format, you didn't give much information on what it actually does.

I'd suggest the same as darkstalker, use mangos' code, it works for extracting all fields with known meaning, and then some...

Link to comment
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use