00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "xFile.h"
00016 #include "xParserDefs.h"
00017 #include "xLexerDefs.h"
00018 #include "xFileTemplate.h"
00019 #include "xFileDataNodeTemplate.h"
00020 #include "config_xfile.h"
00021 #include "standard_templates.h"
00022 #include "zStream.h"
00023 #include "virtualFileSystem.h"
00024 #include "dcast.h"
00025
00026 TypeHandle XFile::_type_handle;
00027 PT(XFile) XFile::_standard_templates;
00028
00029
00030
00031
00032
00033
00034 XFile::
00035 XFile(bool keep_names) : XFileNode(this, "") {
00036 _major_version = 3;
00037 _minor_version = 2;
00038 _format_type = FT_text;
00039 _float_size = FS_64;
00040 _keep_names = keep_names;
00041 }
00042
00043
00044
00045
00046
00047
00048 XFile::
00049 ~XFile() {
00050 clear();
00051 }
00052
00053
00054
00055
00056
00057
00058
00059 void XFile::
00060 clear() {
00061 XFileNode::clear();
00062
00063 _nodes_by_guid.clear();
00064 }
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 bool XFile::
00079 read(Filename filename) {
00080 filename.set_text();
00081 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00082 istream *in = vfs->open_read_file(filename, true);
00083 if (in == (istream *)NULL) {
00084 xfile_cat.error()
00085 << "Cannot open " << filename << " for reading.\n";
00086 return false;
00087 }
00088 bool okflag = read(*in, filename);
00089 vfs->close_read_file(in);
00090 return okflag;
00091 }
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 bool XFile::
00110 read(istream &in, const string &filename) {
00111 if (!read_header(in)) {
00112 return false;
00113 }
00114
00115 if (_format_type != FT_text) {
00116
00117
00118 xfile_cat.error()
00119 << "Cannot read binary .x files at this time.\n";
00120 return false;
00121 }
00122
00123
00124
00125
00126 get_standard_templates();
00127
00128 x_init_parser(in, filename, *this);
00129 xyyparse();
00130 x_cleanup_parser();
00131
00132 return (x_error_count() == 0);
00133 }
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 bool XFile::
00146 write(Filename filename) const {
00147 ofstream out;
00148
00149
00150
00151 filename.set_binary();
00152 filename.open_write(out);
00153
00154 if (!out) {
00155 xfile_cat.error()
00156 << "Can't open " << filename << " for output.\n";
00157 return false;
00158 }
00159
00160 #ifdef HAVE_ZLIB
00161 if (filename.get_extension() == "pz") {
00162
00163
00164 OCompressStream compressor(&out, false);
00165 return write(compressor);
00166 }
00167 #endif // HAVE_ZLIB
00168
00169 return write(out);
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181 bool XFile::
00182 write(ostream &out) const {
00183 if (!write_header(out)) {
00184 return false;
00185 }
00186
00187 write_text(out, 0);
00188
00189 return true;
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 XFileTemplate *XFile::
00199 find_template(const string &name) const {
00200 XFileTemplate *standard = (XFileTemplate *)NULL;
00201 const XFile *standard_templates = get_standard_templates();
00202 if (standard_templates != this) {
00203 standard = standard_templates->find_template(name);
00204 }
00205
00206 XFileNode *child = find_child(name);
00207 if (child != (XFileNode *)NULL &&
00208 child->is_of_type(XFileTemplate::get_class_type())) {
00209 XFileTemplate *xtemplate = DCAST(XFileTemplate, child);
00210 if (standard != (XFileTemplate *)NULL && xtemplate->matches(standard)) {
00211
00212
00213
00214
00215 return standard;
00216 }
00217 return xtemplate;
00218 }
00219
00220 return standard;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229 XFileTemplate *XFile::
00230 find_template(const WindowsGuid &guid) const {
00231 XFileTemplate *standard = (XFileTemplate *)NULL;
00232 const XFile *standard_templates = get_standard_templates();
00233 if (standard_templates != this) {
00234 standard = standard_templates->find_template(guid);
00235 }
00236
00237 NodesByGuid::const_iterator gi;
00238 gi = _nodes_by_guid.find(guid);
00239 if (gi != _nodes_by_guid.end() &&
00240 (*gi).second->is_of_type(XFileTemplate::get_class_type())) {
00241 XFileTemplate *xtemplate = DCAST(XFileTemplate, (*gi).second);
00242 if (standard != (XFileTemplate *)NULL && xtemplate->matches(standard)) {
00243
00244
00245
00246
00247 return standard;
00248 }
00249 return xtemplate;
00250 }
00251
00252 return standard;
00253 }
00254
00255
00256
00257
00258
00259
00260
00261 XFileTemplate *XFile::
00262 find_standard_template(const string &name) {
00263 const XFile *standard_templates = get_standard_templates();
00264 return standard_templates->find_template(name);
00265 }
00266
00267
00268
00269
00270
00271
00272
00273 XFileTemplate *XFile::
00274 find_standard_template(const WindowsGuid &guid) {
00275 const XFile *standard_templates = get_standard_templates();
00276 return standard_templates->find_template(guid);
00277 }
00278
00279
00280
00281
00282
00283
00284
00285 XFileDataNodeTemplate *XFile::
00286 find_data_object(const string &name) const {
00287 XFileNode *child = find_descendent(name);
00288 if (child != (XFileNode *)NULL &&
00289 child->is_of_type(XFileDataNodeTemplate::get_class_type())) {
00290 return DCAST(XFileDataNodeTemplate, child);
00291 }
00292
00293 return NULL;
00294 }
00295
00296
00297
00298
00299
00300
00301
00302 XFileDataNodeTemplate *XFile::
00303 find_data_object(const WindowsGuid &guid) const {
00304 NodesByGuid::const_iterator gi;
00305 gi = _nodes_by_guid.find(guid);
00306 if (gi != _nodes_by_guid.end() &&
00307 (*gi).second->is_of_type(XFileDataNodeTemplate::get_class_type())) {
00308 return DCAST(XFileDataNodeTemplate, (*gi).second);
00309 }
00310
00311 return NULL;
00312 }
00313
00314
00315
00316
00317
00318
00319
00320 void XFile::
00321 write_text(ostream &out, int indent_level) const {
00322 Children::const_iterator ci;
00323 for (ci = _children.begin(); ci != _children.end(); ++ci) {
00324 (*ci)->write_text(out, indent_level);
00325 out << "\n";
00326 }
00327 }
00328
00329
00330
00331
00332
00333
00334
00335 bool XFile::
00336 read_header(istream &in) {
00337 char magic[4];
00338 if (!in.read(magic, 4)) {
00339 xfile_cat.error()
00340 << "Empty file.\n";
00341 return false;
00342 }
00343
00344 if (memcmp(magic, "xof ", 4) != 0) {
00345 xfile_cat.error()
00346 << "Not a DirectX file.\n";
00347 return false;
00348 }
00349
00350 char version[4];
00351 if (!in.read(version, 4)) {
00352 xfile_cat.error()
00353 << "Truncated file.\n";
00354 return false;
00355 }
00356 _major_version = (version[0] - '0') * 10 + (version[1] - '0');
00357 _minor_version = (version[2] - '0') * 10 + (version[3] - '0');
00358
00359 char format[4];
00360 if (!in.read(format, 4)) {
00361 xfile_cat.error()
00362 << "Truncated file.\n";
00363 return false;
00364 }
00365
00366 if (memcmp(format, "txt ", 4) == 0) {
00367 _format_type = FT_text;
00368
00369 } else if (memcmp(format, "bin ", 4) == 0) {
00370 _format_type = FT_binary;
00371
00372 } else if (memcmp(format, "com ", 4) == 0) {
00373 _format_type = FT_compressed;
00374
00375 } else {
00376 xfile_cat.error()
00377 << "Unknown format type: " << string(format, 4) << "\n";
00378 return false;
00379 }
00380
00381 if (_format_type == FT_compressed) {
00382
00383
00384 char compression_type[4];
00385 in.read(compression_type, 4);
00386 }
00387
00388 char float_size[4];
00389 if (!in.read(float_size, 4)) {
00390 xfile_cat.error()
00391 << "Truncated file.\n";
00392 return false;
00393 }
00394
00395 if (memcmp(float_size, "0032", 4) == 0) {
00396 _float_size = FS_32;
00397
00398 } else if (memcmp(float_size, "0064", 4) == 0) {
00399 _float_size = FS_64;
00400
00401 } else {
00402 xfile_cat.error()
00403 << "Unknown float size: " << string(float_size, 4) << "\n";
00404 return false;
00405 }
00406
00407 return true;
00408 }
00409
00410
00411
00412
00413
00414
00415
00416 bool XFile::
00417 write_header(ostream &out) const {
00418 out.write("xof ", 4);
00419
00420 char buffer[128];
00421 sprintf(buffer, "%02d%02d", _major_version, _minor_version);
00422 if (strlen(buffer) != 4) {
00423 xfile_cat.error()
00424 << "Invalid version: " << _major_version << "." << _minor_version
00425 << "\n";
00426 return false;
00427 }
00428
00429 out.write(buffer, 4);
00430
00431 switch (_format_type) {
00432 case FT_text:
00433 out.write("txt ", 4);
00434 break;
00435
00436 case FT_binary:
00437 out.write("bin ", 4);
00438 break;
00439
00440 case FT_compressed:
00441 out.write("cmp ", 4);
00442 break;
00443
00444 default:
00445 xfile_cat.error()
00446 << "Invalid format type: " << _format_type << "\n";
00447 return false;
00448 }
00449
00450 if (_format_type == FT_compressed) {
00451
00452 out.write("xxx ", 4);
00453 }
00454
00455 switch (_float_size) {
00456 case FS_32:
00457 out.write("0032", 4);
00458 break;
00459
00460 case FS_64:
00461 out.write("0064", 4);
00462 break;
00463
00464 default:
00465 xfile_cat.error()
00466 << "Invalid float size: " << _float_size << "\n";
00467 return false;
00468 }
00469
00470 if (_format_type == FT_text) {
00471
00472 out << "\n";
00473 }
00474
00475 return true;
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485 const XFile *XFile::
00486 get_standard_templates() {
00487 if (_standard_templates == (XFile *)NULL) {
00488
00489
00490
00491 string data((const char *)standard_templates_data, standard_templates_data_len);
00492
00493 #ifdef HAVE_ZLIB
00494
00495 istringstream inz(data);
00496 IDecompressStream in(&inz, false);
00497
00498 #else
00499
00500 istringstream in(data);
00501 #endif // HAVE_ZLIB
00502
00503 _standard_templates = new XFile;
00504 if (!_standard_templates->read(in, "standardTemplates.x")) {
00505 xfile_cat.error()
00506 << "Internal error: Unable to parse built-in standardTemplates.x!\n";
00507 }
00508
00509
00510 for (int i = 0; i < _standard_templates->get_num_children(); i++) {
00511 XFileNode *child = _standard_templates->get_child(i);
00512 if (child->is_of_type(XFileTemplate::get_class_type())) {
00513 XFileTemplate *xtemplate = DCAST(XFileTemplate, child);
00514 xtemplate->_is_standard = true;
00515 }
00516 }
00517 }
00518
00519 return _standard_templates;
00520 }