mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 19:08:55 -04:00
362 lines
9.9 KiB
C++
362 lines
9.9 KiB
C++
// Filename: xFile.cxx
|
|
// Created by: drose (03Oct04)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "xFile.h"
|
|
#include "xParserDefs.h"
|
|
#include "xLexerDefs.h"
|
|
#include "config_xfile.h"
|
|
#include "config_express.h"
|
|
#include "virtualFileSystem.h"
|
|
|
|
TypeHandle XFile::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
XFile::
|
|
XFile() : XFileNode("xfile") {
|
|
_major_version = 1;
|
|
_minor_version = 1;
|
|
_format_type = FT_text;
|
|
_float_size = FS_64;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::Destructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
XFile::
|
|
~XFile() {
|
|
clear();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::add_child
|
|
// Access: Public, Virtual
|
|
// Description: Adds the indicated node as a child of this node.
|
|
////////////////////////////////////////////////////////////////////
|
|
void XFile::
|
|
add_child(XFileNode *node) {
|
|
XFileNode::add_child(node);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::clear
|
|
// Access: Public, Virtual
|
|
// Description: Removes all of the classes defined within the XFile
|
|
// and prepares it for reading a new file.
|
|
////////////////////////////////////////////////////////////////////
|
|
void XFile::
|
|
clear() {
|
|
XFileNode::clear();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::read
|
|
// Access: Public
|
|
// Description: Opens and reads the indicated .x file by name. The
|
|
// nodes and templates defined in the file will be
|
|
// appended to the set of nodes already recorded, if
|
|
// any.
|
|
//
|
|
// Returns true if the file is successfully read, false
|
|
// if there was an error (in which case the file might
|
|
// have been partially read).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFile::
|
|
read(Filename filename) {
|
|
ifstream in;
|
|
|
|
filename.set_text();
|
|
if (use_vfs) {
|
|
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
|
istream *in = vfs->open_read_file(filename);
|
|
if (in == (istream *)NULL) {
|
|
xfile_cat.error()
|
|
<< "Cannot open " << filename << " for reading.\n";
|
|
return false;
|
|
}
|
|
bool okflag = read(*in, filename);
|
|
delete in;
|
|
return okflag;
|
|
|
|
} else {
|
|
filename.open_read(in);
|
|
|
|
if (!in) {
|
|
xfile_cat.error()
|
|
<< "Cannot open " << filename << " for reading.\n";
|
|
return false;
|
|
}
|
|
|
|
return read(in, filename);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::read
|
|
// Access: Public
|
|
// Description: Parses the already-opened input stream for
|
|
// distributed class descriptions. The filename
|
|
// parameter is optional and is only used when reporting
|
|
// errors.
|
|
//
|
|
// The distributed classes defined in the file will be
|
|
// appended to the set of distributed classes already
|
|
// recorded, if any.
|
|
//
|
|
// Returns true if the file is successfully read, false
|
|
// if there was an error (in which case the file might
|
|
// have been partially read).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFile::
|
|
read(istream &in, const string &filename) {
|
|
if (!read_header(in)) {
|
|
return false;
|
|
}
|
|
|
|
if (_format_type != FT_text) {
|
|
// Does anyone actually use the binary format? It wouldn't be too
|
|
// hard to support it if there were any reason at all to do so.
|
|
xfile_cat.error()
|
|
<< "Cannot read binary .x files at this time.\n";
|
|
return false;
|
|
}
|
|
|
|
x_init_parser(in, filename, *this);
|
|
xyyparse();
|
|
x_cleanup_parser();
|
|
|
|
return (x_error_count() == 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::write
|
|
// Access: Public
|
|
// Description: Opens the indicated filename for output and writes a
|
|
// parseable description of all the known distributed
|
|
// classes to the file.
|
|
//
|
|
// Returns true if the description is successfully
|
|
// written, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFile::
|
|
write(Filename filename) const {
|
|
ofstream out;
|
|
|
|
// We actually open the file to write in binary mode, to avoid the
|
|
// MS-DOS newline characters (since Windows seems to do this too).
|
|
filename.set_binary();
|
|
filename.open_write(out);
|
|
|
|
if (!out) {
|
|
xfile_cat.error()
|
|
<< "Can't open " << filename << " for output.\n";
|
|
return false;
|
|
}
|
|
|
|
return write(out);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// function: XFile::write
|
|
// Access: Public
|
|
// Description: Writes a parseable description of all the known
|
|
// nodes and templates to the stream.
|
|
//
|
|
// Returns true if the description is successfully
|
|
// written, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFile::
|
|
write(ostream &out) const {
|
|
if (!write_header(out)) {
|
|
return false;
|
|
}
|
|
|
|
write_text(out, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::write_text
|
|
// Access: Public, Virtual
|
|
// Description: Writes a suitable representation of this node to an
|
|
// .x file in text mode.
|
|
////////////////////////////////////////////////////////////////////
|
|
void XFile::
|
|
write_text(ostream &out, int indent_level) const {
|
|
Children::const_iterator ci;
|
|
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
|
(*ci)->write_text(out, indent_level);
|
|
out << "\n";
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::read_header
|
|
// Access: Private
|
|
// Description: Reads the header and magic number associated with the
|
|
// file. Returns true on success, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFile::
|
|
read_header(istream &in) {
|
|
char magic[4];
|
|
if (!in.read(magic, 4)) {
|
|
xfile_cat.error()
|
|
<< "Empty file.\n";
|
|
return false;
|
|
}
|
|
|
|
if (memcmp(magic, "xof ", 4) != 0) {
|
|
xfile_cat.error()
|
|
<< "Not a DirectX file.\n";
|
|
return false;
|
|
}
|
|
|
|
char version[4];
|
|
if (!in.read(version, 4)) {
|
|
xfile_cat.error()
|
|
<< "Truncated file.\n";
|
|
return false;
|
|
}
|
|
_major_version = (version[0] - '0') * 10 + (version[1] - '0');
|
|
_minor_version = (version[2] - '0') * 10 + (version[3] - '0');
|
|
|
|
char format[4];
|
|
if (!in.read(format, 4)) {
|
|
xfile_cat.error()
|
|
<< "Truncated file.\n";
|
|
return false;
|
|
}
|
|
|
|
if (memcmp(format, "txt ", 4) == 0) {
|
|
_format_type = FT_text;
|
|
|
|
} else if (memcmp(format, "bin ", 4) == 0) {
|
|
_format_type = FT_binary;
|
|
|
|
} else if (memcmp(format, "com ", 4) == 0) {
|
|
_format_type = FT_compressed;
|
|
|
|
} else {
|
|
xfile_cat.error()
|
|
<< "Unknown format type: " << string(format, 4) << "\n";
|
|
return false;
|
|
}
|
|
|
|
if (_format_type == FT_compressed) {
|
|
// Read and ignore the compression type, since we don't support
|
|
// compression anyway.
|
|
char compression_type[4];
|
|
in.read(compression_type, 4);
|
|
}
|
|
|
|
char float_size[4];
|
|
if (!in.read(float_size, 4)) {
|
|
xfile_cat.error()
|
|
<< "Truncated file.\n";
|
|
return false;
|
|
}
|
|
|
|
if (memcmp(float_size, "0032", 4) == 0) {
|
|
_float_size = FS_32;
|
|
|
|
} else if (memcmp(float_size, "0064", 4) == 0) {
|
|
_float_size = FS_64;
|
|
|
|
} else {
|
|
xfile_cat.error()
|
|
<< "Unknown float size: " << string(float_size, 4) << "\n";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: XFile::write_header
|
|
// Access: Private
|
|
// Description: Writes the header and magic number associated with the
|
|
// file. Returns true on success, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool XFile::
|
|
write_header(ostream &out) const {
|
|
out.write("xof ", 4);
|
|
|
|
char buffer[128];
|
|
sprintf(buffer, "%02d%02d", _major_version, _minor_version);
|
|
if (strlen(buffer) != 4) {
|
|
xfile_cat.error()
|
|
<< "Invalid version: " << _major_version << "." << _minor_version
|
|
<< "\n";
|
|
return false;
|
|
}
|
|
|
|
out.write(buffer, 4);
|
|
|
|
switch (_format_type) {
|
|
case FT_text:
|
|
out.write("txt ", 4);
|
|
break;
|
|
|
|
case FT_binary:
|
|
out.write("bin ", 4);
|
|
break;
|
|
|
|
case FT_compressed:
|
|
out.write("cmp ", 4);
|
|
break;
|
|
|
|
default:
|
|
xfile_cat.error()
|
|
<< "Invalid format type: " << _format_type << "\n";
|
|
return false;
|
|
}
|
|
|
|
if (_format_type == FT_compressed) {
|
|
// Write a bogus compression type, just so we have a valid header.
|
|
out.write("xxx ", 4);
|
|
}
|
|
|
|
switch (_float_size) {
|
|
case FS_32:
|
|
out.write("0032", 4);
|
|
break;
|
|
|
|
case FS_64:
|
|
out.write("0064", 4);
|
|
break;
|
|
|
|
default:
|
|
xfile_cat.error()
|
|
<< "Invalid float size: " << _float_size << "\n";
|
|
return false;
|
|
}
|
|
|
|
if (_format_type == FT_text) {
|
|
// If it's a text format, we can now write a newline.
|
|
out << "\n";
|
|
}
|
|
|
|
return true;
|
|
}
|