diff --git a/lib/dtsc.cpp b/lib/dtsc.cpp index 31018e18..624e99bf 100644 --- a/lib/dtsc.cpp +++ b/lib/dtsc.cpp @@ -2,9 +2,9 @@ /// Holds all code for DDVTECH Stream Container parsing/generation. #include "dtsc.h" +#include #include //for memcmp #include //for htonl/ntohl -#include //for fprint, stderr char DTSC::Magic_Header[] = "DTSC"; char DTSC::Magic_Packet[] = "DTPD"; @@ -477,3 +477,100 @@ DTSC::DTMI DTSC::parseDTMI(const unsigned char * data, unsigned int len){ DTSC::DTMI DTSC::parseDTMI(std::string data){ return parseDTMI((const unsigned char*)data.c_str(), data.size()); }//parse + +/// Open a filename for DTSC reading/writing. +/// If create is true and file does not exist, attempt to create. +DTSC::File::File(std::string filename, bool create){ + if (create){ + F = fopen(filename.c_str(), "w+b"); + }else{ + F = fopen(filename.c_str(), "r+b"); + } + if (!F){ + fprintf(stderr, "Could not open file %s\n", filename.c_str()); + return; + } + + //if first 4 bytes not available, assume empty file, write header + if (fread(buffer, 4, 1, F) != 1){ + fseek(F, 0, SEEK_SET); + fwrite(DTSC::Magic_Header, 4, 1, F); + }else{ + if (memcmp(buffer, DTSC::Magic_Header, 4) != 0){ + fprintf(stderr, "Not a DTSC file - aborting: %s\n", filename.c_str()); + fclose(F); + F = 0; + return; + } + } + //we now know the first 4 bytes are DTSC::Magic_Header and we have a valid file + fseek(F, 4, SEEK_SET); + if (fread(buffer, 4, 1, F) != 1){ + fseek(F, 4, SEEK_SET); + memset(buffer, 0, 4); + fwrite(buffer, 4, 1, F);//write 4 zero-bytes + headerSize = 0; + }else{ + headerSize = ntohl(((uint32_t *)buffer)[0]); + } + fseek(F, 8+headerSize, SEEK_SET); +} + +/// Returns the header metadata for this file as a std::string. +/// Sets the file pointer to the first packet. +std::string & DTSC::File::getHeader(){ + fseek(F, 8, SEEK_SET); + strbuffer.reserve(headerSize); + fread((void*)strbuffer.c_str(), headerSize, 1, F); + fseek(F, 8+headerSize, SEEK_SET); +} + +/// (Re)writes the given string to the header area if the size is the same as the existing header. +/// Forces a write if force is set to true. +bool DTSC::File::writeHeader(std::string & header, bool force){ + if (headerSize != header.size() && !force){ + fprintf(stderr, "Could not overwrite header - not equal size\n"); + return false; + } + headerSize = header.size() - 8; + fseek(F, 0, SEEK_SET); + int ret = fwrite(header.c_str(), 8+headerSize, 1, F); + fseek(F, 8+headerSize, SEEK_SET); + return (ret == 1); +} + +/// Reads the packet available at the current file position, returning it as a std::string. +/// If the packet could not be read for any reason, the reason is printed to stderr and an empty string returned. +std::string & DTSC::File::getPacket(){ + if (fread(buffer, 4, 1, F) != 1){ + fprintf(stderr, "Could not read header\n"); + strbuffer = ""; + return strbuffer; + } + if (memcmp(buffer, DTSC::Magic_Packet, 4) != 0){ + fprintf(stderr, "Could not overwrite header - not equal size\n"); + strbuffer = ""; + return strbuffer; + } + if (fread(buffer, 4, 1, F) != 1){ + fprintf(stderr, "Could not read size\n"); + strbuffer = ""; + return strbuffer; + } + long packSize = ntohl(((uint32_t *)buffer)[0]); + strbuffer.reserve(packSize); + if (fread((void*)strbuffer.c_str(), packSize, 1, F)){ + fprintf(stderr, "Could not read packet\n"); + strbuffer = ""; + return strbuffer; + } + return strbuffer; +} + +/// Close the file if open +DTSC::File::~File(){ + if (F){ + fclose(F); + F = 0; + } +} diff --git a/lib/dtsc.h b/lib/dtsc.h index 428a445e..c9205952 100644 --- a/lib/dtsc.h +++ b/lib/dtsc.h @@ -8,6 +8,7 @@ #include #include #include +#include //for FILE @@ -102,6 +103,22 @@ namespace DTSC{ extern char Magic_Header[]; ///< The magic bytes for a DTSC header extern char Magic_Packet[]; ///< The magic bytes for a DTSC packet + /// A simple wrapper class that will open a file and allow easy reading/writing of DTSC data from/to it. + class File{ + public: + File(std::string filename, bool create = false); + ~File(); + std::string & getHeader(); + bool writeHeader(std::string & header, bool force = false); + std::string & getPacket(); + private: + std::string strbuffer; + FILE * F; + long headerSize; + char buffer[4]; + };//FileWriter + + /// A part from the DTSC::Stream ringbuffer. /// Holds information about a buffer that will stay consistent class Ring {