Add an unpack option to the data tool
[libs/datafile.git] / tool / tool.cpp
1 #include <msp/core/getopt.h>
2 #include <msp/io/buffered.h>
3 #include <msp/io/console.h>
4 #include <msp/io/file.h>
5 #include <msp/datafile/packsource.h>
6 #include <msp/datafile/parser.h>
7 #include <msp/datafile/statement.h>
8 #include "compiler.h"
9 #include "packer.h"
10 #include "tool.h"
11
12 using namespace std;
13 using namespace Msp;
14
15 DataTool::DataTool(int argc, char **argv):
16         out_fn("-"),
17         binary(false),
18         compile(false),
19         float_size(0),
20         compress(false),
21         pack(false),
22         unpack(false),
23         debug(false)
24 {
25         GetOpt getopt;
26         getopt.add_option('b', "binary", binary, GetOpt::NO_ARG).set_help("Produce a binary datafile");
27         getopt.add_option('c', "compile", compile, GetOpt::NO_ARG).set_help("Create a collection based on a template file");
28         getopt.add_option('f', "float-size", float_size, GetOpt::REQUIRED_ARG).set_help("Floating-point precision", "BITS");
29         getopt.add_option('g', "debug", debug, GetOpt::NO_ARG).set_help("Display control statements");
30         getopt.add_option('o', "output", out_fn, GetOpt::REQUIRED_ARG).set_help("Output to a file instead of stdout", "FILE");
31         getopt.add_option('p', "pack", pack, GetOpt::NO_ARG).set_help("Create a pack from multiple files");
32         getopt.add_option('u', "unpack", unpack, GetOpt::NO_ARG).set_help("Unpacks files from packs into the current directory");
33         getopt.add_option('z', "compress", compress, GetOpt::NO_ARG).set_help("Produce a compressed datafile");
34         getopt.add_argument("infile", in_fns, GetOpt::OPTIONAL_ARG).set_help("Files to process");
35         getopt(argc, argv);
36
37         if(compile+pack+unpack>1)
38                 throw usage_error("Only one of -c, -p and -u may be specified");
39
40         if(pack && out_fn=="-")
41                 throw usage_error("Can't write pack to stdout");
42
43         if(in_fns.empty())
44                 in_fns.push_back("-");
45
46         if(unpack)
47         {
48                 for(list<string>::const_iterator i=in_fns.begin(); i!=in_fns.end(); ++i)
49                         if(*i=="-")
50                                 throw usage_error("Can't unpack from stdout");
51         }
52 }
53
54 int DataTool::main()
55 {
56         if(pack)
57                 do_pack();
58         else if(unpack)
59                 do_unpack();
60         else if(compile)
61                 do_compile();
62         else
63                 do_transfer();
64
65         return 0;
66 }
67
68 void DataTool::do_transfer()
69 {
70         IO::Base *out = open_output(out_fn);
71         DataFile::Writer *writer = create_writer(*out);
72
73         for(list<string>::const_iterator i=in_fns.begin(); i!=in_fns.end(); ++i)
74         {
75                 IO::Base *in = open_input(*i);
76                 DataFile::Parser parser(*in, *i);
77
78                 while(parser)
79                 {
80                         DataFile::Statement st = parser.parse(true);
81                         if(st.valid && (!st.control || st.keyword=="__src" || debug))
82                                 writer->write(st);
83                 }
84
85                 delete in;
86         }
87
88         delete writer;
89         delete out;
90 }
91
92 void DataTool::do_compile()
93 {
94         IO::Base *out = open_output(out_fn);
95         DataFile::Writer *writer = create_writer(*out);
96
97         Compiler compiler(*writer);
98         for(list<string>::const_iterator i=in_fns.begin(); i!=in_fns.end(); ++i)
99         {
100                 IO::Base *in = open_input(*i);
101                 DataFile::Parser parser(*in, *i);
102                 compiler.load(parser);
103                 delete in;
104         }
105
106         delete writer;
107         delete out;
108 }
109
110 void DataTool::do_pack()
111 {
112         Packer packer(*this);
113         for(list<string>::const_iterator i=in_fns.begin(); i!=in_fns.end(); ++i)
114                 packer.pack_file(*i);
115         packer.create_pack(out_fn);
116 }
117
118 void DataTool::do_unpack()
119 {
120         DataFile::PackSource source;
121         for(list<string>::const_iterator i=in_fns.begin(); i!=in_fns.end(); ++i)
122                 source.add_pack_file(*i);
123
124         list<DataFile::PackSource::FileInfo> files = source.list_files();
125         for(list<DataFile::PackSource::FileInfo>::const_iterator i=files.begin(); i!=files.end(); ++i)
126         {
127                 IO::Seekable *in = source.open(i->name);
128                 IO::Base *out = open_output(i->name);
129                 char buf[16384];
130                 while(1)
131                 {
132                         unsigned len = in->read(buf, sizeof(buf));
133                         out->write(buf, len);
134                         if(len<sizeof(buf))
135                                 break;
136                 }
137                 delete in;
138                 delete out;
139         }
140 }
141
142 IO::Base *DataTool::open_output(const string &fn)
143 {
144         if(fn=="-")
145                 return new IO::Buffered(IO::cout);
146         else
147                 return new IO::BufferedFile(fn, IO::M_WRITE);
148 }
149
150 IO::Base *DataTool::open_input(const string &fn)
151 {
152         if(fn=="-")
153                 return new IO::Buffered(IO::cin);
154         else
155                 return new IO::BufferedFile(fn, IO::M_READ);
156 }
157
158 DataFile::Writer *DataTool::create_writer(IO::Base &out)
159 {
160         DataFile::Writer *writer = new DataFile::Writer(out);
161         if(compress)
162                 writer->set_compressed();
163         if(binary)
164                 writer->set_binary(true);
165         if(float_size)
166                 writer->set_float_precision(float_size);
167         return writer;
168 }