mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-05 19:19:39 -06:00
First draft of file format conversion ready for testing
This commit is contained in:
@@ -70,7 +70,7 @@ public:
|
||||
};
|
||||
|
||||
static const size_t FileHeaderVersionLength = 5;
|
||||
static constexpr char FileHeaderVersion[] = "00.85";
|
||||
char FileHeaderVersion[FileHeaderVersionLength+1] = "01.00";
|
||||
static const char DataFormatAsciiTag = 'A';
|
||||
static const char DataFormatBinaryTag = 'B';
|
||||
static const size_t keyframeHeaderSize_bytes = 33;
|
||||
@@ -455,10 +455,21 @@ public:
|
||||
* (will determine the file format conversion to convert from based on the file's
|
||||
* header version number).
|
||||
*
|
||||
* \param filename name of the file to convert
|
||||
* \param root (optional) the 5-character version string that represents the version
|
||||
* of the original file to convert (before recursion started)
|
||||
*/
|
||||
static bool convertFile(std::string filename);
|
||||
bool convertFile(std::string filename, std::string root = "root");
|
||||
|
||||
private:
|
||||
/**
|
||||
* Returns pointer to SessionRecording object that is the previous legacy version
|
||||
* of the current version.
|
||||
*
|
||||
* \return Pointer to the previous version of the SessionRecording
|
||||
*/
|
||||
SessionRecording* getLegacy();
|
||||
|
||||
protected:
|
||||
properties::BoolProperty _renderPlaybackInformation;
|
||||
|
||||
enum class RecordedType {
|
||||
@@ -532,15 +543,18 @@ private:
|
||||
double getNextTimestamp();
|
||||
double getPrevTimestamp();
|
||||
void cleanUpPlayback();
|
||||
static bool convertEntries(std::string& inFilename, std::ifstream& inFile,
|
||||
bool convertEntries(std::string& inFilename, std::ifstream& inFile,
|
||||
DataMode mode, int lineNum, std::ofstream& outFile);
|
||||
static bool convertCamera(std::ifstream& inFile, DataMode mode, int lineNum,
|
||||
virtual bool convertCamera(std::ifstream& inFile, DataMode mode, int lineNum,
|
||||
std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
|
||||
static bool convertTimeChange(std::ifstream& inFile, DataMode mode, int lineNum,
|
||||
virtual bool convertTimeChange(std::ifstream& inFile, DataMode mode, int lineNum,
|
||||
std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
|
||||
static bool convertScript(std::ifstream& inFile, DataMode mode, int lineNum,
|
||||
virtual bool convertScript(std::ifstream& inFile, DataMode mode, int lineNum,
|
||||
std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
|
||||
static std::string determineConversionOutFilename(const std::string filename);
|
||||
std::string determineConversionOutFilename(const std::string filename);
|
||||
void readPlaybackFileHeader(const std::string filename,
|
||||
std::string& conversionInFilename, std::ifstream& conversionInFile,
|
||||
std::string& version, DataMode& mode);
|
||||
|
||||
static void writeToFileBuffer(unsigned char* buf, size_t& idx, double src);
|
||||
static void writeToFileBuffer(unsigned char* buf, size_t& idx, std::vector<char>& cv);
|
||||
@@ -592,8 +606,10 @@ private:
|
||||
int _conversionLineNum = 1;
|
||||
};
|
||||
|
||||
class SessionRecording_legacy_0085 : SessionRecording {
|
||||
struct ScriptMessage_legacy_0085 : datamessagestructures::ScriptMessage {
|
||||
class SessionRecording_legacy_0085 : public SessionRecording {
|
||||
char FileHeaderVersion[FileHeaderVersionLength+1] = "00.85";
|
||||
|
||||
struct ScriptMessage_legacy_0085 : public datamessagestructures::ScriptMessage {
|
||||
void read(std::istream* in) {
|
||||
size_t strLen;
|
||||
//Read string length from file
|
||||
@@ -608,9 +624,8 @@ class SessionRecording_legacy_0085 : SessionRecording {
|
||||
};
|
||||
};
|
||||
|
||||
void convertUp(std::string header, std::string fileToConvert);
|
||||
|
||||
static constexpr char FileHeaderVersion[] = "01.00";
|
||||
bool convertScript(std::ifstream& inFile, DataMode mode, int lineNum,
|
||||
std::string& inputLine, std::ofstream& outFile, unsigned char* buffer);
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -59,6 +59,7 @@ private:
|
||||
std::ifstream _iFile;
|
||||
std::ofstream _oFile;
|
||||
SessionRecording::DataMode _fileFormatType;
|
||||
std::string _version;
|
||||
|
||||
std::string _valueFunctionLua;
|
||||
};
|
||||
|
||||
@@ -67,6 +67,10 @@ namespace {
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
ConversionError::ConversionError(std::string msg)
|
||||
: ghoul::RuntimeError(std::move(msg), "conversionError")
|
||||
{}
|
||||
|
||||
SessionRecording::SessionRecording()
|
||||
: properties::PropertyOwner({ "SessionRecording", "Session Recording" })
|
||||
, _renderPlaybackInformation(RenderPlaybackInfo, false)
|
||||
@@ -74,10 +78,15 @@ SessionRecording::SessionRecording()
|
||||
auto fTask = FactoryManager::ref().factory<Task>();
|
||||
ghoul_assert(fTask, "No task factory existed");
|
||||
fTask->registerClass<ConvertRecFormatTask>("ConvertRecFormatTask");
|
||||
fTask->registerClass<ConvertRecFormatTask>("ConvertRecFileVersionTask");
|
||||
addProperty(_renderPlaybackInformation);
|
||||
}
|
||||
|
||||
SessionRecording::~SessionRecording() {} // NOLINT
|
||||
SessionRecording::~SessionRecording() { // NOLINT
|
||||
if (legacyVersion != nullptr) {
|
||||
delete legacyVersion;
|
||||
}
|
||||
}
|
||||
|
||||
void SessionRecording::deinitialize() {
|
||||
stopRecording();
|
||||
@@ -1619,7 +1628,7 @@ void SessionRecording::saveKeyframeToFileBinary(unsigned char* buffer,
|
||||
size_t size,
|
||||
std::ofstream& file)
|
||||
{
|
||||
file.write(reinterpret_cast<unsigned char*>(buffer), size);
|
||||
file.write(reinterpret_cast<const char*>(buffer), size);
|
||||
}
|
||||
|
||||
void SessionRecording::saveKeyframeToFile(std::string entry, std::ofstream& file) {
|
||||
@@ -1664,140 +1673,82 @@ std::vector<std::string> SessionRecording::playbackList() const {
|
||||
return fileList;
|
||||
}
|
||||
|
||||
scripting::LuaLibrary SessionRecording::luaLibrary() {
|
||||
return {
|
||||
"sessionRecording",
|
||||
{
|
||||
{
|
||||
"startRecording",
|
||||
&luascriptfunctions::startRecording,
|
||||
{},
|
||||
"string",
|
||||
"Starts a recording session. The string argument is the filename used "
|
||||
"for the file where the recorded keyframes are saved. "
|
||||
"The file data format is binary."
|
||||
},
|
||||
{
|
||||
"startRecordingAscii",
|
||||
&luascriptfunctions::startRecordingAscii,
|
||||
{},
|
||||
"string",
|
||||
"Starts a recording session. The string argument is the filename used "
|
||||
"for the file where the recorded keyframes are saved. "
|
||||
"The file data format is ASCII."
|
||||
},
|
||||
{
|
||||
"stopRecording",
|
||||
&luascriptfunctions::stopRecording,
|
||||
{},
|
||||
"void",
|
||||
"Stops a recording session"
|
||||
},
|
||||
{
|
||||
"startPlayback",
|
||||
&luascriptfunctions::startPlaybackDefault,
|
||||
{},
|
||||
"string",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"the time since the recording was started (the same relative time "
|
||||
"applies to the playback). When playback starts, the simulation time "
|
||||
"is automatically set to what it was at recording time. The string "
|
||||
"argument is the filename to pull playback keyframes from."
|
||||
},
|
||||
{
|
||||
"startPlaybackApplicationTime",
|
||||
&luascriptfunctions::startPlaybackApplicationTime,
|
||||
{},
|
||||
"string",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"application time (seconds since OpenSpace application started). "
|
||||
"The string argument is the filename to pull playback keyframes from."
|
||||
},
|
||||
{
|
||||
"startPlaybackRecordedTime",
|
||||
&luascriptfunctions::startPlaybackRecordedTime,
|
||||
{},
|
||||
"string",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"the time since the recording was started (the same relative time "
|
||||
"applies to the playback). The string argument is the filename to pull "
|
||||
"playback keyframes from."
|
||||
},
|
||||
{
|
||||
"startPlaybackSimulationTime",
|
||||
&luascriptfunctions::startPlaybackSimulationTime,
|
||||
{},
|
||||
"string",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"the simulated date & time. The string argument is the filename to pull "
|
||||
"playback keyframes from."
|
||||
},
|
||||
{
|
||||
"stopPlayback",
|
||||
&luascriptfunctions::stopPlayback,
|
||||
{},
|
||||
"void",
|
||||
"Stops a playback session before playback of all keyframes is complete"
|
||||
},
|
||||
{
|
||||
"enableTakeScreenShotDuringPlayback",
|
||||
&luascriptfunctions::enableTakeScreenShotDuringPlayback,
|
||||
{},
|
||||
"[int]",
|
||||
"Enables that rendered frames should be saved during playback. The "
|
||||
"parameter determines the number of frames that are exported per second "
|
||||
"if this value is not provided, 60 frames per second will be exported."
|
||||
},
|
||||
{
|
||||
"disableTakeScreenShotDuringPlayback",
|
||||
&luascriptfunctions::disableTakeScreenShotDuringPlayback,
|
||||
{},
|
||||
"void",
|
||||
"Used to disable that renderings are saved during playback"
|
||||
}
|
||||
}
|
||||
};
|
||||
void SessionRecording::readPlaybackFileHeader(const std::string filename,
|
||||
std::string& conversionInFilename,
|
||||
std::ifstream& conversionInFile,
|
||||
std::string& version,
|
||||
DataMode& mode)
|
||||
{
|
||||
if (filename.find("/") != std::string::npos) {
|
||||
throw ConversionError("Playback filename musn't contain path (/) elements");
|
||||
}
|
||||
conversionInFilename = absPath("${RECORDINGS}/" + filename);
|
||||
if (!FileSys.fileExists(conversionInFilename)) {
|
||||
throw ConversionError("Cannot find the specified playback file to convert.");
|
||||
}
|
||||
|
||||
|
||||
// Open in ASCII first
|
||||
conversionInFile.open(conversionInFilename, std::ifstream::in);
|
||||
// Read header
|
||||
std::string readBackHeaderString = readHeaderElement(
|
||||
conversionInFile,
|
||||
FileHeaderTitle.length()
|
||||
);
|
||||
|
||||
if (readBackHeaderString != FileHeaderTitle) {
|
||||
throw ConversionError("File to convert does not contain expected header.");
|
||||
}
|
||||
version = readHeaderElement(conversionInFile, FileHeaderVersionLength);
|
||||
std::string readDataMode = readHeaderElement(conversionInFile, 1);
|
||||
if (readDataMode[0] == DataFormatAsciiTag) {
|
||||
mode = DataMode::Ascii;
|
||||
}
|
||||
else if (readDataMode[0] == DataFormatBinaryTag) {
|
||||
mode = DataMode::Binary;
|
||||
}
|
||||
else {
|
||||
throw ConversionError("Unknown data type in header (needs Ascii or Binary)");
|
||||
}
|
||||
}
|
||||
|
||||
bool SessionRecording::convertFile(std::string filename) {
|
||||
bool SessionRecording::convertFile(std::string filename, std::string version) {
|
||||
bool success = true;
|
||||
std::string conversionInFilename;
|
||||
std::ifstream conversionInFile;
|
||||
DataMode mode;
|
||||
bool preRecursion = (version == "root") ? true : false;
|
||||
std::string throwOut;
|
||||
|
||||
try {
|
||||
if (filename.find("/") != std::string::npos) {
|
||||
throw ConversionError("Playback filename musn't contain path (/) elements");
|
||||
}
|
||||
std::string conversionInFilename = absPath("${RECORDINGS}/" + filename);
|
||||
if (!FileSys.fileExists(conversionInFilename)) {
|
||||
throw ConversionError("Cannot find the specified playback file to convert.");
|
||||
}
|
||||
|
||||
int conversionLineNum = 1;
|
||||
// Open in ASCII first
|
||||
std::ifstream conversionInFile;
|
||||
conversionInFile.open(conversionInFilename, std::ifstream::in);
|
||||
// Read header
|
||||
std::string readBackHeaderString = readHeaderElement(
|
||||
conversionInFile,
|
||||
FileHeaderTitle.length()
|
||||
readPlaybackFileHeader(
|
||||
filename,
|
||||
conversionInFilename,
|
||||
conversionInFile,
|
||||
preRecursion ? version : throwOut,
|
||||
mode
|
||||
);
|
||||
int conversionLineNum = 1;
|
||||
LINFO(fmt::format(
|
||||
"Starting conversion on rec file {}, version {} in {} mode.",
|
||||
filename, version, (mode == DataMode::Ascii) ? "ascii" : "binary"
|
||||
));
|
||||
|
||||
if (readBackHeaderString != FileHeaderTitle) {
|
||||
throw ConversionError("File to convert does not contain expected header.");
|
||||
}
|
||||
if (readBackHeaderString != FileHeaderTitle) {
|
||||
throw ConversionError("File to convert does not contain expected header.");
|
||||
}
|
||||
readHeaderElement(conversionInFile, FileHeaderVersionLength);
|
||||
std::string readDataMode = readHeaderElement(conversionInFile, 1);
|
||||
DataMode mode;
|
||||
if (readDataMode[0] == DataFormatAsciiTag) {
|
||||
mode = DataMode::Ascii;
|
||||
}
|
||||
else if (readDataMode[0] == DataFormatBinaryTag) {
|
||||
mode = DataMode::Binary;
|
||||
}
|
||||
else {
|
||||
throw ConversionError("Unknown data type in header (needs Ascii or Binary)");
|
||||
//If this instance of the SessionRecording class isn't the instance with the
|
||||
// correct version of the file to be converted, then call getLegacy() to recurse
|
||||
// to the next level down in the legacy subclasses until we get the right
|
||||
// version, then proceed with conversion from there.
|
||||
if (version.compare(FileHeaderVersion) != 0) {
|
||||
conversionInFile.close();
|
||||
SessionRecording* old = getLegacy();
|
||||
old->convertFile(filename, version);
|
||||
readPlaybackFileHeader(
|
||||
filename,
|
||||
conversionInFilename,
|
||||
conversionInFile,
|
||||
version,
|
||||
mode
|
||||
);
|
||||
}
|
||||
|
||||
if (!conversionInFile.is_open() || !conversionInFile.good()) {
|
||||
@@ -1829,6 +1780,8 @@ bool SessionRecording::convertFile(std::string filename) {
|
||||
conversionLineNum,
|
||||
conversionOutFile
|
||||
);
|
||||
conversionInFile.close();
|
||||
conversionOutFile.close();
|
||||
}
|
||||
catch (ConversionError& c) {
|
||||
LERROR(c.message);
|
||||
@@ -1843,7 +1796,8 @@ bool SessionRecording::convertEntries(std::string& inFilename, std::ifstream& in
|
||||
{
|
||||
bool conversionStatusOk = true;
|
||||
std::string lineParsing;
|
||||
std::shared_ptr<char[]> buffer(new char[_saveBufferMaxSize_bytes]);
|
||||
//std::shared_ptr<unsigned char[]> buffer(new unsigned char[_saveBufferMaxSize_bytes]);
|
||||
unsigned char* buffer = new unsigned char[_saveBufferMaxSize_bytes];
|
||||
|
||||
if (mode == DataMode::Binary) {
|
||||
unsigned char frameType;
|
||||
@@ -1867,7 +1821,7 @@ bool SessionRecording::convertEntries(std::string& inFilename, std::ifstream& in
|
||||
lineNum,
|
||||
lineParsing,
|
||||
outFile,
|
||||
buffer
|
||||
reinterpret_cast<unsigned char*>(buffer)
|
||||
);
|
||||
}
|
||||
else if (frameType == HeaderTimeBinary) {
|
||||
@@ -1962,9 +1916,16 @@ bool SessionRecording::convertEntries(std::string& inFilename, std::ifstream& in
|
||||
lineNum, inFilename
|
||||
));
|
||||
}
|
||||
if (buffer != nullptr) {
|
||||
delete buffer;
|
||||
}
|
||||
return conversionStatusOk;
|
||||
}
|
||||
|
||||
SessionRecording* SessionRecording::getLegacy() {
|
||||
legacyVersion = new SessionRecording_legacy_0085();
|
||||
}
|
||||
|
||||
std::string SessionRecording::determineConversionOutFilename(const std::string filename) {
|
||||
std::string conversionOutFilename;
|
||||
if (filename.substr(filename.find_last_of(".")) == FileExtensionBinary) {
|
||||
@@ -1981,14 +1942,135 @@ std::string SessionRecording::determineConversionOutFilename(const std::string f
|
||||
return absPath("${RECORDINGS}/convert/" + conversionOutFilename);
|
||||
}
|
||||
|
||||
void SessionRecording_legacy_0085::convertUp(std::string header, std::string fileToConvert)
|
||||
bool SessionRecording_legacy_0085::convertScript(std::ifstream& inFile, DataMode mode,
|
||||
int lineNum, std::string& inputLine,
|
||||
std::ofstream& outFile,
|
||||
unsigned char* buffer)
|
||||
{
|
||||
if (strcmp(legacyVersion->FileHeaderVersion, FileHeaderVersion) == 0) {
|
||||
convertFile(fileToConvert);
|
||||
}
|
||||
else {
|
||||
//Oldest known version
|
||||
Timestamps times;
|
||||
ScriptMessage_legacy_0085 kf;
|
||||
|
||||
bool success = readSingleKeyframeScript(
|
||||
kf,
|
||||
times,
|
||||
mode,
|
||||
inFile,
|
||||
inputLine,
|
||||
lineNum
|
||||
);
|
||||
if (success) {
|
||||
saveSingleKeyframeScript(
|
||||
kf,
|
||||
times,
|
||||
mode,
|
||||
outFile,
|
||||
buffer
|
||||
);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
scripting::LuaLibrary SessionRecording::luaLibrary() {
|
||||
return {
|
||||
"sessionRecording",
|
||||
{
|
||||
{
|
||||
"startRecording",
|
||||
&luascriptfunctions::startRecording,
|
||||
{},
|
||||
"string",
|
||||
"Starts a recording session. The string argument is the filename used "
|
||||
"for the file where the recorded keyframes are saved. "
|
||||
"The file data format is binary."
|
||||
},
|
||||
{
|
||||
"startRecordingAscii",
|
||||
&luascriptfunctions::startRecordingAscii,
|
||||
{},
|
||||
"string",
|
||||
"Starts a recording session. The string argument is the filename used "
|
||||
"for the file where the recorded keyframes are saved. "
|
||||
"The file data format is ASCII."
|
||||
},
|
||||
{
|
||||
"stopRecording",
|
||||
&luascriptfunctions::stopRecording,
|
||||
{},
|
||||
"void",
|
||||
"Stops a recording session"
|
||||
},
|
||||
{
|
||||
"startPlayback",
|
||||
&luascriptfunctions::startPlaybackDefault,
|
||||
{},
|
||||
"string",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"the time since the recording was started (the same relative time "
|
||||
"applies to the playback). When playback starts, the simulation time "
|
||||
"is automatically set to what it was at recording time. The string "
|
||||
"argument is the filename to pull playback keyframes from."
|
||||
},
|
||||
{
|
||||
"startPlaybackApplicationTime",
|
||||
&luascriptfunctions::startPlaybackApplicationTime,
|
||||
{},
|
||||
"string",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"application time (seconds since OpenSpace application started). "
|
||||
"The string argument is the filename to pull playback keyframes from."
|
||||
},
|
||||
{
|
||||
"startPlaybackRecordedTime",
|
||||
&luascriptfunctions::startPlaybackRecordedTime,
|
||||
{},
|
||||
"string",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"the time since the recording was started (the same relative time "
|
||||
"applies to the playback). The string argument is the filename to pull "
|
||||
"playback keyframes from."
|
||||
},
|
||||
{
|
||||
"startPlaybackSimulationTime",
|
||||
&luascriptfunctions::startPlaybackSimulationTime,
|
||||
{},
|
||||
"string",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"the simulated date & time. The string argument is the filename to pull "
|
||||
"playback keyframes from."
|
||||
},
|
||||
{
|
||||
"stopPlayback",
|
||||
&luascriptfunctions::stopPlayback,
|
||||
{},
|
||||
"void",
|
||||
"Stops a playback session before playback of all keyframes is complete"
|
||||
},
|
||||
{
|
||||
"enableTakeScreenShotDuringPlayback",
|
||||
&luascriptfunctions::enableTakeScreenShotDuringPlayback,
|
||||
{},
|
||||
"[int]",
|
||||
"Enables that rendered frames should be saved during playback. The "
|
||||
"parameter determines the number of frames that are exported per second "
|
||||
"if this value is not provided, 60 frames per second will be exported."
|
||||
},
|
||||
{
|
||||
"disableTakeScreenShotDuringPlayback",
|
||||
&luascriptfunctions::disableTakeScreenShotDuringPlayback,
|
||||
{},
|
||||
"void",
|
||||
"Used to disable that renderings are saved during playback"
|
||||
},
|
||||
{
|
||||
"fileFormatConversion",
|
||||
&luascriptfunctions::fileFormatConversion,
|
||||
{},
|
||||
"string",
|
||||
"Performs a conversion of the specified file to the most most recent "
|
||||
"file format, creating a copy of the recording file."
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
@@ -167,4 +167,23 @@ int disableTakeScreenShotDuringPlayback(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fileFormatConversion(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
const std::string convertFilePath = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
|
||||
if (convertFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
global::sessionRecording.convertFile(convertFilePath);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openspace::luascriptfunctions
|
||||
|
||||
@@ -128,10 +128,7 @@ void ConvertRecFormatTask::convert() {
|
||||
SessionRecording::FileHeaderTitle.c_str(),
|
||||
SessionRecording::FileHeaderTitle.length()
|
||||
);
|
||||
_oFile.write(
|
||||
SessionRecording::FileHeaderVersion,
|
||||
SessionRecording::FileHeaderVersionLength
|
||||
);
|
||||
_oFile.write(_version.c_str(), SessionRecording::FileHeaderVersionLength);
|
||||
_oFile.close();
|
||||
|
||||
if (_fileFormatType == SessionRecording::DataMode::Ascii) {
|
||||
@@ -161,7 +158,7 @@ void ConvertRecFormatTask::determineFormatType() {
|
||||
}
|
||||
else {
|
||||
//Read version string and throw it away (and also line feed character at end)
|
||||
SessionRecording::readHeaderElement(_iFile,
|
||||
_version = SessionRecording::readHeaderElement(_iFile,
|
||||
SessionRecording::FileHeaderVersionLength);
|
||||
line = SessionRecording::readHeaderElement(_iFile, 1);
|
||||
SessionRecording::readHeaderElement(_iFile, 1);
|
||||
|
||||
Reference in New Issue
Block a user