0

For my game, I want to use PhysFs to extract music files that are in a zip file

I created a custom class MusicStream that inherits from sf::InputStream that I use as an sf::Music's stream.

This is my basic program:

#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "musicstream.h"
#include "physfs.h"

int main() {
  PHYSFS_init(0);
  PHYSFS_addToSearchPath("data.zip", 0);

  std::string musicFile = "music.ogg";
  if (PHYSFS_exists(musicFile.c_str()) == 0) {
    PHYSFS_deinit();
    return EXIT_FAILURE;
  }

  sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
  sf::Music myMusic;
  MusicStream myStream(musicFile.c_str());
  if (!myStream.getError()) {
    myMusic.openFromStream(myStream);
    myMusic.play();
  }
  while (window.isOpen()) { 
    sf::Event event; 
    while (window.pollEvent(event)) { 
      if (event.type == sf::Event::Closed) window.close(); 
    }
  }

  myMusic.stop();

  PHYSFS_deinit();
  return 0;
}

This works flawlessly, except for one thing:

When I close the window and the program exits, I'm getting a runtime error R6025 pure virtual function call and the program crashes.

So apparently a pure virtual function is called (sf::InputStream's dtor??), but I implemented all of sf::InputStream's functions and it doesn't make sense to me.

Also, I'm not really sure if the code is relevant but in case it is, this is the custom class:

musicstream.h

#ifndef MUSIC_STREAM_H_INCLUDED
#define MUSIC_STREAM_H_INCLUDED

#include <SFML/System.hpp>
#include "physfs.h"

class MusicStream : public sf::InputStream {
 public:
  MusicStream();
  MusicStream(const char *fileName);
  virtual ~MusicStream() override;

  sf::Int64 read(void *data, sf::Int64) override;
  sf::Int64 seek(sf::Int64 position) override;
  sf::Int64 tell() override;
  sf::Int64 getSize() override;

  bool getError() const;

 private:
  PHYSFS_File *file_;
  bool error_;

};

#endif

musicstream.cpp

#include "musicstream.h"

MusicStream::MusicStream() :
  error_(true)
{
}

MusicStream::MusicStream(const char *filename) :
  error_(false)
{
  file_ = PHYSFS_openRead(filename);
  if (file_ == nullptr) {
    error_ = true;
  }
}

MusicStream::~MusicStream() {
  if (error_) { return; }
  PHYSFS_close(file_);
}

sf::Int64 MusicStream::read(void *data, sf::Int64 size) {
  if (error_) { return 0; }
  sf::Int64 fileRead = PHYSFS_read(file_, data, 1, size);
  if (fileRead == -1) {
    return 0;
  }
  return fileRead;
}

sf::Int64 MusicStream::seek(sf::Int64 position) {
  if (error_)  { return -1; }
  if (PHYSFS_seek(file_, position) == 0) {
    return -1;
  }
  return position;
}

sf::Int64 MusicStream::tell() {
  if (error_) { return -1; }
  sf::Int64 position = PHYSFS_tell(file_);
  return position;
}

sf::Int64 MusicStream::getSize() {
  if (error_) { return -1; }
  sf::Int64 size = PHYSFS_fileLength(file_);
  return size;
}

bool MusicStream::getError() const {
  return error_;
}
A. D.
  • 728
  • 1
  • 9
  • 27

1 Answers1

0

The problem were these two lines:

sf::Music myMusic;
MusicStream myStream(musicFile.c_str());

I swapped them and got rid of the error. It's because music is played in its own thread. It tried reading from the stream after it was destroyed. Now the music is destroyed before the stream is.

A. D.
  • 728
  • 1
  • 9
  • 27