Having trouble with vectored structures

Started by
13 comments, last by Zahlman 16 years, 9 months ago
Quick way to isolate the problem:

for(uint32_t i=0;i< 5; ++i){   Resource r;   in.read(r.file_offset.c,sizeof(uint32_t));   in.read(r.resource_size.c,sizeof(uint32_t));   in.get(sbuff,'\0');   r.resource_name = sbuff.str();   resc_list.push_back(r);}


Just for testing, change the loop for i < 5.

This will tell you weather or not r has data in it, or if resource.u is a correct number (1 or higher)
Black Sky A Star Control 2/Elite like game
Advertisement
@phil_t: As sure as I can be. When I tried it with id[4], it kept coming back with the first 3 digits, but when I used 5,it got the word ("BIG4") right.
Woohoo! I got it to work!! here's the final function;

void BIGFile::Load()
{
in.open(file.c_str());
if(in.is_open())
{
std::cout << "file name: " << file << std::endl;
BIG4Header b4h={0};
in.read((char*)&b4h,sizeof(BIG4Header));

char_2_ui32 cu32;
cu32.u = b4h.resource_count;
char temp_ch;
temp_ch = cu32.c[0];
cu32.c[0] = cu32.c[3];
cu32.c[3] = temp_ch;
temp_ch = cu32.c[1];
cu32.c[1] = cu32.c[2];
cu32.c[2] = temp_ch;
resource_count=cu32.u;


if(b4h.id[0]=='B' && b4h.id[1]=='I' && b4h.id[2]=='G' && b4h.id[3]=='4')
{
std::cout << "file type: " << b4h.id[0] << b4h.id[1] << b4h.id[2] << b4h.id[3] << std::endl;
std::cout << "number of resources in file: " << resource_count <<std::endl;

Resource r;
char_2_ui32 c232;

for(uint32_t i=0;i<resource_count;++i)
{
std::stringbuf sbuff;
in.read(c232.c,sizeof(std::streampos));
r.file_offset=c232.u;
std::cout << "file offset: " << r.file_offset <<std::endl;

in.read(c232.c,sizeof(uint32_t));
r.resource_size=c232.u;
std::cout << "resource size: " << r.resource_size<<std::endl;

in.get(sbuff,'\0');
r.resource_name = sbuff.str();
std::cout << "resource name: " << r.resource_name << std::endl << std::endl;

resc_list.push_back(r);
}
}
else
{
std::cout << "File type not recognized: " << b4h.id[0] << b4h.id[1] << b4h.id[2] << b4h.id[3] << std::endl;
}
}
else
{
std::cout << "Couldn't open file: " << file << std::endl;
}
}
[\source]
It is quite a bit longer, but it now has slight error checking (yes, the so-called "printf" error checking :P ) and produces a pretty output XD

Note a new header;

struct BIG4Header{
char id[4];//must contain 'BIG4'
uint32_t x1;
uint32_t resource_count;
uint32_t x2;
};

Quote:Original post by webwraith
I'm not conversant with the MingW debugger

Well, there's your problem then. Trying to debug without a debugger is a waste of time. Take the time to learn how to use your debugger.

Yeah, mixing .read() operations with operator>> is a pretty good sign of doing something wrong. The former implies unformatted, binary data, while the latter implies formatted, "text" (i.e. human-readable) data. It's unusual for a file to mix those.

That said:

- It looks like you're using some kind of union to reinterpret integers as byte arrays. Don't do that. That's what reinterpret_cast is for.

- You don't need to initialize the header before you read into it, because the reading-in is going to initialize it for you. Unless you're worried that file reading will fail *and* the uninitialized header happens to contain "BIG4" in the right spot - a valid concern, but if the file reading fails, everything's going to abort *anyway*.

- Use a helper function to read the integers, since you do it often. I have a templated one that I reproduce commonly in forum posts :/

- A bigger, design problem: Don't write 'load' functions. That work properly belongs in the constructor; that's what constructors are for. Also, don't hold on to the stream object within the BIGFile (you don't need it after you're done loading; or at least, you can reopen it via the saved file name) nor the resource_count or associated getter (it's redundant). And what's the 'dest' currently for?

- Oh, and don't make things 'protected' without a good reason. Private is private. "protected" exists for the sake of derived classes. Why would you have derived classes of BIGFile?

- Prefer to pass strings (and other class instances) by const reference.

- Are you *really* sure that you need to endian-swap the resource_count, but NOT any of the other ints in the file?

- Don't use std::string::compare() in "normal" code. The class is defined to make comparison operators work the way you expect, and it's much more readable that way. .compare() exists for when you have to do 3-way comparison and you have a slick way of using the resulting return value.

class BIGFile {  struct Resource {    std::streampos file_offset;    uint32_t resource_size;    std::string resource_name;  };  struct BIG4Header {    char id[4]; // must contain 'BIG4'    uint32_t x1;    uint32_t resource_count;    uint32_t x2;  };  std::vector<Resource> resc_list;  std::string filename;  public:  BIGFile(const std::string& filename);  // From what I've seen so far, you probably don't need a destructor.  uint32_t GetCount() { return resc_list.size(); }  std::string GetNames();  void Extract(const std::string&, const std::string&);};// Read into existing T. Return whether successful (unless the stream// is configured to throw an exception on failure).template <typename T>bool readPrimitive(istream& is, T& result) {  is.read(reinterpret_cast<char *>(&result), sizeof(T));  return is;}// Read a new T. Return default T on failure (unless the stream// is configured to throw an exception on failure).template <typename T>T readPrimitive(istream& is) {  T result;  readPrimitive(is, result);  return result;}BIGFile::BIGFile(const std::string& filename) : filename(filename) {  ifstream in;  // Bail out immediately if anything goes wrong, automatically cleaning things  // up due to RAII  in.exceptions(ios::bad_bit | ios::fail_bit | ios::eof_bit);  in.open(file.c_str());  BIG4Header b4h = readPrimitive<BIG4Header>(in);  char* resource_count_swapper = reinterpret_cast<char *>(&b4h.resource_count);  std::swap(resource_count_swapper[0], resource_count_swapper[3]);  std::swap(resource_count_swapper[1], resource_count_swapper[2]);  // construct a string from the header ID, explicitly specifying the range of  // bytes to use, so as to avoid problems with the lack of a null terminator.  std::string type(b4h.id, b4h.id + 4);  if (type != "BIG4") {    throw ios::failure("File type not recognized: " + type);  }  Resource r;  for (uint32_t i=0; i<resource_count; ++i) {    readPrimitive(in, r.file_offset);    readPrimitive(in, r.resource_size);    std::stringbuf sbuff;    in.get(sbuff,'\0');    r.resource_name = sbuff.str();    resc_list.push_back(r);  }}

This topic is closed to new replies.

Advertisement