diff --git a/dataobj/tabfile.cc b/dataobj/tabfile.cc index d352255f4..c4d5a734d 100644 --- a/dataobj/tabfile.cc +++ b/dataobj/tabfile.cc @@ -17,7 +17,7 @@ #include "../descriptor/image.h" #include "koord.h" #include "tabfile.h" - +#include "../tpl/vector_tpl.h" #define LINEBUFFER_SIZE (4096) @@ -856,3 +856,69 @@ void tabfile_t::format_key(char *key) } *t = '\0'; } + +void CSV_file_t::clear(){ + for(auto const & i : header) { + free(const_cast(i.key)); + } + header.clear(); + for(uint16 i = 0; i < data.get_data_count(); i++){ + koord dummypos; + const char *value; + data.get_nonzero(i,dummypos,value); + free(const_cast(value)); + } + data.reset(); +} + +void CSV_file_t::add_obj(const tabfileobj_t &obj){ + uint16 row=data.add_row(10)-1; + uint16 col; + for(auto it = obj.get_begin(); it != obj.get_end(); ++it){ + if(it->value.str==0){ + continue; + } + if(header.is_contained(it->key)){ + col=header.get(it->key); + }else{ + col=data.add_col()-1; + header.put(strdup(it->key),col); + } + data.set(col,row,strdup(it->value.str)); + } +} + +bool CSV_file_t::save_file(const char *filename){ + FILE* file; + if(filename){ + file=dr_fopen(filename,"w"); + }else{ + file=stdout; + } + if(!file) return false; + vector_tpl indexes; + for(auto it = header.begin(); it != header.end(); ++it){ + indexes.append(it->value); + fprintf(file,"%s",it->key); + if(indexes.get_count()!=header.get_count()){ + fprintf(file,","); + } + } + fprintf(file,"\n"); + + for(uint16 j = 0; j < data.get_size().y; j++){ + for(uint16 i = 0; i < indexes.get_count(); i++){ + if(data.get(indexes[i],j) && data.get(indexes[i],j)[0]){ + fprintf(file,"\"%s\"",data.get(indexes[i],j)); + } + if(i+1!=indexes.get_count()){ + fprintf(file,","); + } + } + fprintf(file,"\n"); + } + if(filename){ + fclose(file); + } + return true; +} diff --git a/dataobj/tabfile.h b/dataobj/tabfile.h index 9458444ec..9d58d0835 100644 --- a/dataobj/tabfile.h +++ b/dataobj/tabfile.h @@ -11,6 +11,7 @@ #include "../simcolor.h" #include "../tpl/stringhashtable_tpl.h" +#include "../tpl/sparse_tpl.h" class tabfileobj_t; class koord; @@ -27,6 +28,8 @@ public: obj_info_t(bool b, const char *s ) { retrieved=b; str=s; } }; + + /** * This class can be used instead of FILE to read a game definition file, * usually with extension .tab in simutrans. @@ -123,6 +126,14 @@ public: tabfileobj_t() { } ~tabfileobj_t() { clear(); } + stringhashtable_tpl::const_iterator get_begin() const { + return objinfo.begin(); + } + + stringhashtable_tpl::const_iterator get_end() const { + return objinfo.end(); + } + /** * prints all unused options lines in the file which do not start with a character from exclude_start_chars */ @@ -192,4 +203,19 @@ public: sint64 *get_sint64s(const char *key); }; +class CSV_file_t +{ +public: + CSV_file_t() {} + ~CSV_file_t() {clear();} + +public: + void clear(); + void add_obj(const tabfileobj_t& obj); + bool save_file(const char *filename); +private: + stringhashtable_tpl header; + sparse_tpl data; +}; + #endif diff --git a/descriptor/writer/root_writer.cc b/descriptor/writer/root_writer.cc index ebc640f66..ec0d947be 100644 --- a/descriptor/writer/root_writer.cc +++ b/descriptor/writer/root_writer.cc @@ -16,6 +16,8 @@ using std::string; string root_writer_t::inpath; +const koord koord::invalid(-1, -1); //needed for sparce_tpl.h + void root_writer_t::write_header(FILE* fp) { fprintf(fp, @@ -122,6 +124,49 @@ void root_writer_t::write(const char* filename, int argc, char* argv[]) } } +void root_writer_t::write_CSV(const char *filename, int argc, char *argv[]){ + searchfolder_t find; + FILE* outfp = NULL; + obj_node_t* node = NULL; + bool separate = false; + + CSV_file_t csv; + + for( int i=0; i==0 || i= log_t::LEVEL_WARN) { + printf(" Reading file %s\n", i); + } + + inpath = arg; + string::size_type n = inpath.rfind('/'); + + if(n!=string::npos) { + inpath = inpath.substr(0, n + 1); + } + else { + inpath = ""; + } + + while(infile.read(obj)) { + csv.add_obj(obj); + } + } + else { + dbg->warning( "Write pak", "Cannot read %s", i); + } + } + } + csv.save_file(filename); +} void root_writer_t::write_obj_node_info_t(FILE* outfp, const obj_node_info_t &root) { diff --git a/descriptor/writer/root_writer.h b/descriptor/writer/root_writer.h index 5b18437f8..ddc45d280 100644 --- a/descriptor/writer/root_writer.h +++ b/descriptor/writer/root_writer.h @@ -37,6 +37,7 @@ class root_writer_t : public obj_writer_t { void dump(int argc, char* argv[]); void list(int argc, char* argv[]); void copy(const char* name, int argc, char* argv[]); + void write_CSV(const char* name, int argc, char* argv[]); /** * @brief Expands makeobj pre-processor stuff diff --git a/makeobj/makeobj.cc b/makeobj/makeobj.cc index 3a85e482a..a5af4e51a 100644 --- a/makeobj/makeobj.cc +++ b/makeobj/makeobj.cc @@ -115,6 +115,27 @@ int main(int argc, char* argv[]) } } + if (argc && !STRICMP(argv[0], "tocsv")) { + argv++; argc--; + + try { + const char* dest; + if (argc) { + dest = argv[0]; + argv++; argc--; + } + else { + dest = 0; + } + root_writer_t::instance()->write_CSV(dest, argc, argv); + } + catch (const obj_pak_exception_t& e) { + dbg->error( e.get_class(), e.get_info() ); + return 1; + } + return 0; + } + if (argc && !STRICMP(argv[0], "expand")) { argv++; argc--; diff --git a/tpl/sparse_tpl.h b/tpl/sparse_tpl.h index 24be62c9c..c480b5fde 100644 --- a/tpl/sparse_tpl.h +++ b/tpl/sparse_tpl.h @@ -34,7 +34,19 @@ class sparse_tpl uint16 data_size; uint16 data_count; + uint16 row_size; + public: + sparse_tpl (){ + size = koord(0,0); + data_size=0; + data_count=0; + data = NULL; + col_ind = NULL; + row_ptr = NULL; + row_size=0; + } + sparse_tpl( koord _size ) { size = _size; data_size = 0; @@ -45,15 +57,46 @@ class sparse_tpl for( uint16 i = 0; i < size.y + 1; i++ ) { row_ptr[i] = 0; } + row_size = size.y + 1; } ~sparse_tpl() { - delete[] data; - data = NULL; - delete[] col_ind; - col_ind = NULL; - delete[] row_ptr; - row_ptr = NULL; + if(data){ + delete[] data; + } + if(col_ind){ + delete[] col_ind; + } + if(row_ptr){ + delete[] row_ptr; + } + } + + uint16 add_col(){ size.x++; return size.x; } + + uint16 add_row(uint16 prefetch=0){ + size.y+=1; + if(row_size < size.y+1){ + if(row_size==0){ + row_size = size.y + 1 + prefetch; + row_ptr = new uint16 [row_size]; + for(uint16 i = 0; i < size.y+1; i++){ + row_ptr[i] = 0; + } + }else{ + row_size = size.y + 1 + prefetch; + uint16* new_rows = new uint16 [row_size]; + for(uint16 i = 0; i< size.y; i++){ + new_rows[i]=row_ptr[i]; + } + new_rows[size.y]=new_rows[size.y-1]; + delete[] row_ptr; + row_ptr=new_rows; + } + }else{ + row_ptr[size.y]=row_ptr[size.y-1]; + } + return size.y; } void clear() { @@ -64,6 +107,13 @@ class sparse_tpl resize_data(0); } + void reset(){ + data_count = 0; + delete [] row_ptr; + row_ptr=NULL; + size = koord(0,0); + } + const koord& get_size() const { return size; }