Implemented DTSC::Scan for more efficient use of system memory.
This commit is contained in:
parent
180ac5eb9e
commit
9a19cf2e20
3 changed files with 450 additions and 123 deletions
63
lib/dtsc.h
63
lib/dtsc.h
|
@ -13,6 +13,12 @@
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
|
|
||||||
|
#define DTSC_INT 0x01
|
||||||
|
#define DTSC_STR 0x02
|
||||||
|
#define DTSC_OBJ 0xE0
|
||||||
|
#define DTSC_ARR 0x0A
|
||||||
|
#define DTSC_CON 0xFF
|
||||||
|
|
||||||
namespace DTSC {
|
namespace DTSC {
|
||||||
bool isFixed(JSON::Value & metadata);
|
bool isFixed(JSON::Value & metadata);
|
||||||
|
|
||||||
|
@ -59,6 +65,26 @@ namespace DTSC {
|
||||||
DTSC_V2
|
DTSC_V2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This class allows scanning through raw binary format DTSC data.
|
||||||
|
/// It can be used as an iterator or as a direct accessor.
|
||||||
|
class Scan{
|
||||||
|
public:
|
||||||
|
Scan();
|
||||||
|
Scan(char * pointer, size_t len);
|
||||||
|
std::string toPrettyString(unsigned int indent = 0);
|
||||||
|
Scan getMember(std::string indice);
|
||||||
|
Scan getIndice(unsigned int num);
|
||||||
|
|
||||||
|
char getType();
|
||||||
|
bool asBool();
|
||||||
|
long long asInt();
|
||||||
|
std::string asString();
|
||||||
|
void getString(char *& result, unsigned int & len);
|
||||||
|
private:
|
||||||
|
char * p;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
/// DTSC::Packets can currently be three types:
|
/// DTSC::Packets can currently be three types:
|
||||||
/// DTSC_HEAD packets are the "DTSC" header string, followed by 4 bytes len and packed content.
|
/// DTSC_HEAD packets are the "DTSC" header string, followed by 4 bytes len and packed content.
|
||||||
/// DTSC_V1 packets are "DTPD", followed by 4 bytes len and packed content.
|
/// DTSC_V1 packets are "DTPD", followed by 4 bytes len and packed content.
|
||||||
|
@ -73,30 +99,31 @@ namespace DTSC {
|
||||||
void null();
|
void null();
|
||||||
void operator = (const Packet & rhs);
|
void operator = (const Packet & rhs);
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
packType getVersion();
|
packType getVersion() const;
|
||||||
void reInit(const char * data_, unsigned int len, bool noCopy = false);
|
void reInit(const char * data_, unsigned int len, bool noCopy = false);
|
||||||
void getString(const char * identifier, char *& result, int & len);
|
void getString(const char * identifier, char *& result, unsigned int & len) const;
|
||||||
void getString(const char * identifier, std::string & result);
|
void getString(const char * identifier, std::string & result) const;
|
||||||
void getInt(const char * identifier, int & result);
|
void getInt(const char * identifier, int & result) const;
|
||||||
int getInt(const char * identifier);
|
int getInt(const char * identifier) const;
|
||||||
void getFlag(const char * identifier, bool & result);
|
void getFlag(const char * identifier, bool & result) const;
|
||||||
bool getFlag(const char * identifier);
|
bool getFlag(const char * identifier) const;
|
||||||
bool hasMember(const char * identifier);
|
bool hasMember(const char * identifier) const;
|
||||||
long long unsigned int getTime();
|
long long unsigned int getTime() const;
|
||||||
long int getTrackId();
|
long int getTrackId() const;
|
||||||
char * getData();
|
char * getData() const;
|
||||||
int getDataLen();
|
int getDataLen() const;
|
||||||
JSON::Value toJSON();
|
int getPayloadLen() const;
|
||||||
|
JSON::Value toJSON() const;
|
||||||
|
Scan getScan() const;
|
||||||
protected:
|
protected:
|
||||||
bool master;
|
bool master;
|
||||||
packType version;
|
packType version;
|
||||||
char * findIdentifier(const char * identifier);
|
|
||||||
void resize(unsigned int size);
|
void resize(unsigned int size);
|
||||||
char * data;
|
char * data;
|
||||||
unsigned int bufferLen;
|
unsigned int bufferLen;
|
||||||
unsigned int dataLen;
|
unsigned int dataLen;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A simple structure used for ordering byte seek positions.
|
/// A simple structure used for ordering byte seek positions.
|
||||||
struct livePos {
|
struct livePos {
|
||||||
livePos() {
|
livePos() {
|
||||||
|
@ -255,6 +282,7 @@ namespace DTSC {
|
||||||
Track();
|
Track();
|
||||||
Track(const readOnlyTrack & rhs);
|
Track(const readOnlyTrack & rhs);
|
||||||
Track(JSON::Value & trackRef);
|
Track(JSON::Value & trackRef);
|
||||||
|
Track(Scan & trackRef);
|
||||||
inline operator bool() const {
|
inline operator bool() const {
|
||||||
return parts.size();
|
return parts.size();
|
||||||
}
|
}
|
||||||
|
@ -298,9 +326,10 @@ namespace DTSC {
|
||||||
class Meta : public readOnlyMeta {
|
class Meta : public readOnlyMeta {
|
||||||
public:
|
public:
|
||||||
Meta();
|
Meta();
|
||||||
|
Meta(const DTSC::Packet & source);
|
||||||
Meta(const readOnlyMeta & meta);
|
Meta(const readOnlyMeta & meta);
|
||||||
Meta(JSON::Value & meta);
|
Meta(JSON::Value & meta);
|
||||||
std::map<int, Track> tracks;
|
void reinit(const DTSC::Packet & source);
|
||||||
void update(DTSC::Packet & pack);
|
void update(DTSC::Packet & pack);
|
||||||
void update(JSON::Value & pack);
|
void update(JSON::Value & pack);
|
||||||
unsigned int getSendLen();
|
unsigned int getSendLen();
|
||||||
|
@ -310,6 +339,8 @@ namespace DTSC {
|
||||||
void reset();
|
void reset();
|
||||||
bool isFixed();
|
bool isFixed();
|
||||||
void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0);
|
void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0);
|
||||||
|
//members:
|
||||||
|
std::map<int, Track> tracks;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A simple wrapper class that will open a file and allow easy reading/writing of DTSC data from/to it.
|
/// A simple wrapper class that will open a file and allow easy reading/writing of DTSC data from/to it.
|
||||||
|
|
500
lib/dtscmeta.cpp
500
lib/dtscmeta.cpp
|
@ -4,7 +4,6 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
|
||||||
/// Retrieves a short in network order from the pointer p.
|
/// Retrieves a short in network order from the pointer p.
|
||||||
static short btohs(char * p) {
|
static short btohs(char * p) {
|
||||||
return (p[0] << 8) + p[1];
|
return (p[0] << 8) + p[1];
|
||||||
|
@ -96,7 +95,7 @@ namespace DTSC {
|
||||||
|
|
||||||
/// Returns the recognized packet type.
|
/// Returns the recognized packet type.
|
||||||
/// This type is set by reInit and all constructors, and then just referenced from there on.
|
/// This type is set by reInit and all constructors, and then just referenced from there on.
|
||||||
packType Packet::getVersion(){
|
packType Packet::getVersion() const{
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,132 +182,78 @@ namespace DTSC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function for findIdentifier
|
/// Helper function for skipping over whole DTSC parts
|
||||||
static char * findInside(const char * identifier, char *& p, char * max){
|
static char * skipDTSC(char * p, char * max){
|
||||||
if (p+1 >= max || p[0] == 0x00){
|
if (p+1 >= max || p[0] == 0x00){
|
||||||
return (char*)1;//out of packet! 1 == error
|
return 0;//out of packet! 1 == error
|
||||||
}
|
}
|
||||||
if (p[0] == 0x01){
|
if (p[0] == DTSC_INT){
|
||||||
//int, skip 9 bytes to next value
|
//int, skip 9 bytes to next value
|
||||||
p+=9;
|
return p+9;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (p[0] == 0x02){
|
if (p[0] == DTSC_STR){
|
||||||
if (p+4 >= max){
|
if (p+4 >= max){
|
||||||
return (char*)1;//out of packet! 1 == error
|
return 0;//out of packet!
|
||||||
}
|
}
|
||||||
//string, read size and skip to next value
|
return p + 5 + p[1] * 256 * 256 * 256 + p[2] * 256 * 256 + p[3] * 256 + p[4];
|
||||||
unsigned int tmpi = p[1] * 256 * 256 * 256 + p[2] * 256 * 256 + p[3] * 256 + p[4];
|
|
||||||
p += tmpi + 5;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (p[0] == 0xE0 || p[0] == 0xFF){
|
if (p[0] == DTSC_OBJ || p[0] == DTSC_CON){
|
||||||
p++;
|
p++;
|
||||||
unsigned int id_len = strlen(identifier);
|
|
||||||
//object, scan contents
|
//object, scan contents
|
||||||
while (p[0] + p[1] != 0 && p < max){ //while not encountering 0x0000 (we assume 0x0000EE)
|
while (p[0] + p[1] != 0 && p < max){ //while not encountering 0x0000 (we assume 0x0000EE)
|
||||||
if (p+2 >= max){
|
if (p+2 >= max){
|
||||||
return (char*)1;//out of packet! 1 == error
|
return 0;//out of packet!
|
||||||
}
|
}
|
||||||
unsigned int tmpi = p[0] * 256 + p[1]; //set tmpi to the UTF-8 length
|
p += 2 + (p[0] * 256 + p[1]);//skip size
|
||||||
//compare the name, if match, return contents
|
|
||||||
if (tmpi == id_len){
|
|
||||||
if (memcmp(p+2, identifier, tmpi) == 0){
|
|
||||||
return p+2+tmpi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p += 2+tmpi;//skip size
|
|
||||||
//otherwise, search through the contents, if needed, and continue
|
//otherwise, search through the contents, if needed, and continue
|
||||||
char * tmp_ret = findInside(identifier, p, max);
|
p = skipDTSC(p, max);
|
||||||
if (tmp_ret){
|
if (!p){
|
||||||
return tmp_ret;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p += 3;//skip end marker
|
return p+3;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (p[0] == 0x0A){
|
if (p[0] == DTSC_ARR){
|
||||||
p++;
|
p++;
|
||||||
//array, scan contents
|
//array, scan contents
|
||||||
while (p[0] + p[1] != 0 && p < max){ //while not encountering 0x0000 (we assume 0x0000EE)
|
while (p[0] + p[1] != 0 && p < max){ //while not encountering 0x0000 (we assume 0x0000EE)
|
||||||
//search through contents...
|
//search through contents...
|
||||||
char * tmp_ret = findInside(identifier, p, max);
|
p = skipDTSC(p, max);
|
||||||
if (tmp_ret){
|
if (!p){
|
||||||
return tmp_ret;
|
return 0;
|
||||||
}
|
}
|
||||||
//no match, continue search
|
|
||||||
}
|
}
|
||||||
p += 3; //skip end marker
|
return p + 3; //skip end marker
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
DEBUG_MSG(DLVL_FAIL, "Unimplemented DTMI type %hhx, @ %p / %p - returning.", p[0], p, max);
|
return 0;//out of packet! 1 == error
|
||||||
return (char*)1;//out of packet! 1 == error
|
|
||||||
}
|
|
||||||
|
|
||||||
///\brief Locates an identifier within the payload
|
|
||||||
///\param identifier The identifier to find
|
|
||||||
///\return A pointer to the location of the identifier
|
|
||||||
char * Packet::findIdentifier(const char * identifier){
|
|
||||||
char * p = data;
|
|
||||||
if (version == DTSC_V2){
|
|
||||||
p += 20;
|
|
||||||
}else{
|
|
||||||
p += 8;
|
|
||||||
}
|
|
||||||
char * ret = findInside(identifier, p, data+dataLen);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Retrieves a single parameter as a string
|
///\brief Retrieves a single parameter as a string
|
||||||
///\param identifier The name of the parameter
|
///\param identifier The name of the parameter
|
||||||
///\param result A location on which the string will be returned
|
///\param result A location on which the string will be returned
|
||||||
///\param len An integer in which the length of the string will be returned
|
///\param len An integer in which the length of the string will be returned
|
||||||
void Packet::getString(const char * identifier, char *& result, int & len) {
|
void Packet::getString(const char * identifier, char *& result, unsigned int & len) const{
|
||||||
char * pos = findIdentifier(identifier);
|
getScan().getMember(identifier).getString(result, len);
|
||||||
if (pos < (char*)2) {
|
|
||||||
result = NULL;
|
|
||||||
len = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (pos[0] != 0x02) {
|
|
||||||
result = NULL;
|
|
||||||
len = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
result = pos + 5;
|
|
||||||
len = ntohl(((int *)(pos + 1))[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Retrieves a single parameter as a string
|
///\brief Retrieves a single parameter as a string
|
||||||
///\param identifier The name of the parameter
|
///\param identifier The name of the parameter
|
||||||
///\param result The string in which to store the result
|
///\param result The string in which to store the result
|
||||||
void Packet::getString(const char * identifier, std::string & result) {
|
void Packet::getString(const char * identifier, std::string & result) const{
|
||||||
char * data = NULL;
|
result = getScan().getMember(identifier).asString();
|
||||||
int len = 0;
|
|
||||||
getString(identifier, data, len);
|
|
||||||
result = std::string(data, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Retrieves a single parameter as an integer
|
///\brief Retrieves a single parameter as an integer
|
||||||
///\param identifier The name of the parameter
|
///\param identifier The name of the parameter
|
||||||
///\param result The result is stored in this integer
|
///\param result The result is stored in this integer
|
||||||
void Packet::getInt(const char * identifier, int & result) {
|
void Packet::getInt(const char * identifier, int & result) const{
|
||||||
char * pos = findIdentifier(identifier);
|
result = getScan().getMember(identifier).asInt();
|
||||||
if (pos < (char*)2) {
|
|
||||||
result = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (pos[0] != 0x01) {
|
|
||||||
result = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
result = ((long long int)pos[1] << 56) | ((long long int)pos[2] << 48) | ((long long int)pos[3] << 40) | ((long long int)pos[4] << 32) | ((long long int)pos[5] << 24) | ((long long int)pos[6] << 16) | ((long long int)pos[7] << 8) | pos[8];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Retrieves a single parameter as an integer
|
///\brief Retrieves a single parameter as an integer
|
||||||
///\param identifier The name of the parameter
|
///\param identifier The name of the parameter
|
||||||
///\result The requested parameter as an integer
|
///\result The requested parameter as an integer
|
||||||
int Packet::getInt(const char * identifier) {
|
int Packet::getInt(const char * identifier) const{
|
||||||
int result;
|
int result;
|
||||||
getInt(identifier, result);
|
getInt(identifier, result);
|
||||||
return result;
|
return result;
|
||||||
|
@ -317,7 +262,7 @@ namespace DTSC {
|
||||||
///\brief Retrieves a single parameter as a boolean
|
///\brief Retrieves a single parameter as a boolean
|
||||||
///\param identifier The name of the parameter
|
///\param identifier The name of the parameter
|
||||||
///\param result The result is stored in this boolean
|
///\param result The result is stored in this boolean
|
||||||
void Packet::getFlag(const char * identifier, bool & result) {
|
void Packet::getFlag(const char * identifier, bool & result) const{
|
||||||
int result_;
|
int result_;
|
||||||
getInt(identifier, result_);
|
getInt(identifier, result_);
|
||||||
result = (bool)result_;
|
result = (bool)result_;
|
||||||
|
@ -326,7 +271,7 @@ namespace DTSC {
|
||||||
///\brief Retrieves a single parameter as a boolean
|
///\brief Retrieves a single parameter as a boolean
|
||||||
///\param identifier The name of the parameter
|
///\param identifier The name of the parameter
|
||||||
///\result The requested parameter as a boolean
|
///\result The requested parameter as a boolean
|
||||||
bool Packet::getFlag(const char * identifier) {
|
bool Packet::getFlag(const char * identifier) const{
|
||||||
bool result;
|
bool result;
|
||||||
getFlag(identifier, result);
|
getFlag(identifier, result);
|
||||||
return result;
|
return result;
|
||||||
|
@ -335,13 +280,13 @@ namespace DTSC {
|
||||||
///\brief Checks whether a parameter exists
|
///\brief Checks whether a parameter exists
|
||||||
///\param identifier The name of the parameter
|
///\param identifier The name of the parameter
|
||||||
///\result Whether the parameter exists or not
|
///\result Whether the parameter exists or not
|
||||||
bool Packet::hasMember(const char * identifier) {
|
bool Packet::hasMember(const char * identifier) const{
|
||||||
return findIdentifier(identifier) > (char*)2;
|
return getScan().getMember(identifier).getType() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Returns the timestamp of the packet.
|
///\brief Returns the timestamp of the packet.
|
||||||
///\return The timestamp of this packet.
|
///\return The timestamp of this packet.
|
||||||
long long unsigned int Packet::getTime() {
|
long long unsigned int Packet::getTime() const{
|
||||||
if (version != DTSC_V2){
|
if (version != DTSC_V2){
|
||||||
if (!data){return 0;}
|
if (!data){return 0;}
|
||||||
return getInt("time");
|
return getInt("time");
|
||||||
|
@ -351,7 +296,7 @@ namespace DTSC {
|
||||||
|
|
||||||
///\brief Returns the track id of the packet.
|
///\brief Returns the track id of the packet.
|
||||||
///\return The track id of this packet.
|
///\return The track id of this packet.
|
||||||
long int Packet::getTrackId() {
|
long int Packet::getTrackId() const{
|
||||||
if (version != DTSC_V2){
|
if (version != DTSC_V2){
|
||||||
return getInt("trackid");
|
return getInt("trackid");
|
||||||
}
|
}
|
||||||
|
@ -360,20 +305,35 @@ namespace DTSC {
|
||||||
|
|
||||||
///\brief Returns a pointer to the payload of this packet.
|
///\brief Returns a pointer to the payload of this packet.
|
||||||
///\return A pointer to the payload of this packet.
|
///\return A pointer to the payload of this packet.
|
||||||
char * Packet::getData() {
|
char * Packet::getData() const{
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///\brief Returns the size of this packet.
|
||||||
|
///\return The size of this packet.
|
||||||
|
int Packet::getDataLen() const{
|
||||||
|
return dataLen;
|
||||||
|
}
|
||||||
|
|
||||||
///\brief Returns the size of the payload of this packet.
|
///\brief Returns the size of the payload of this packet.
|
||||||
///\return The size of the payload of this packet.
|
///\return The size of the payload of this packet.
|
||||||
int Packet::getDataLen() {
|
int Packet::getPayloadLen() const{
|
||||||
return dataLen;
|
if (version == DTSC_V2){
|
||||||
|
return dataLen-20;
|
||||||
|
}else{
|
||||||
|
return dataLen-8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a DTSC::Scan instance to the contents of this packet.
|
||||||
|
/// May return an invalid instance if this packet is invalid.
|
||||||
|
Scan Packet::getScan() const{
|
||||||
|
return Scan(data+(getDataLen()-getPayloadLen()), getPayloadLen());
|
||||||
|
}
|
||||||
|
|
||||||
///\brief Converts the packet into a JSON value
|
///\brief Converts the packet into a JSON value
|
||||||
///\return A JSON::Value representation of this packet.
|
///\return A JSON::Value representation of this packet.
|
||||||
JSON::Value Packet::toJSON(){
|
JSON::Value Packet::toJSON() const{
|
||||||
JSON::Value result;
|
JSON::Value result;
|
||||||
unsigned int i = 8;
|
unsigned int i = 8;
|
||||||
if (getVersion() == DTSC_V1){
|
if (getVersion() == DTSC_V1){
|
||||||
|
@ -384,6 +344,274 @@ namespace DTSC {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create an invalid DTSC::Scan object by default.
|
||||||
|
Scan::Scan(){
|
||||||
|
p = 0;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Create a DTSC::Scan object from memory pointer.
|
||||||
|
Scan::Scan(char * pointer, size_t length){
|
||||||
|
p = pointer;
|
||||||
|
len = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an object representing the named indice of this object.
|
||||||
|
/// Returns an invalid object if this indice doesn't exist or this isn't an object type.
|
||||||
|
Scan Scan::getMember(std::string indice){
|
||||||
|
if (getType() != DTSC_OBJ && getType() != DTSC_CON){
|
||||||
|
return Scan();
|
||||||
|
}
|
||||||
|
char * i = p+1;
|
||||||
|
//object, scan contents
|
||||||
|
while (i[0] + i[1] != 0 && i < p+len){ //while not encountering 0x0000 (we assume 0x0000EE)
|
||||||
|
if (i+2 >= p+len){
|
||||||
|
return Scan();//out of packet!
|
||||||
|
}
|
||||||
|
unsigned int strlen = i[0] * 256 + i[1];
|
||||||
|
i += 2;
|
||||||
|
if (indice.size() == strlen && strncmp(indice.data(), i, strlen) == 0){
|
||||||
|
return Scan(i+strlen, len-(i-p));
|
||||||
|
}else{
|
||||||
|
i = skipDTSC(i+strlen, p+len);
|
||||||
|
if (!i){
|
||||||
|
return Scan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an object representing the num-th indice of this array.
|
||||||
|
/// If not an array but an object, it returns the num-th member, instead.
|
||||||
|
/// Returns an invalid object if this indice doesn't exist or this isn't an array or object type.
|
||||||
|
Scan Scan::getIndice(unsigned int num){
|
||||||
|
if (getType() == DTSC_ARR){
|
||||||
|
char * i = p+1;
|
||||||
|
unsigned int arr_indice = 0;
|
||||||
|
//array, scan contents
|
||||||
|
while (i[0] + i[1] != 0 && i < p+len){ //while not encountering 0x0000 (we assume 0x0000EE)
|
||||||
|
//search through contents...
|
||||||
|
if (arr_indice == num){
|
||||||
|
return Scan(i, len-(i-p));
|
||||||
|
}else{
|
||||||
|
arr_indice++;
|
||||||
|
i = skipDTSC(i, p+len);
|
||||||
|
if (!i){
|
||||||
|
return Scan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getType() == DTSC_OBJ || getType() == DTSC_CON){
|
||||||
|
char * i = p+1;
|
||||||
|
unsigned int arr_indice = 0;
|
||||||
|
//object, scan contents
|
||||||
|
while (i[0] + i[1] != 0 && i < p+len){ //while not encountering 0x0000 (we assume 0x0000EE)
|
||||||
|
if (i+2 >= p+len){
|
||||||
|
return Scan();//out of packet!
|
||||||
|
}
|
||||||
|
unsigned int strlen = i[0] * 256 + i[1];
|
||||||
|
i += 2;
|
||||||
|
if (arr_indice == num){
|
||||||
|
return Scan(i+strlen, len-(i-p));
|
||||||
|
}else{
|
||||||
|
arr_indice++;
|
||||||
|
i = skipDTSC(i+strlen, p+len);
|
||||||
|
if (!i){
|
||||||
|
return Scan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the first byte of this DTSC value, or 0 on error.
|
||||||
|
char Scan::getType(){
|
||||||
|
if (!p){return 0;}
|
||||||
|
return p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the boolean value of this DTSC value.
|
||||||
|
/// Numbers are compared to 0.
|
||||||
|
/// Strings are checked for non-zero length.
|
||||||
|
/// Objects and arrays are checked for content.
|
||||||
|
/// Returns false on error or in other cases.
|
||||||
|
bool Scan::asBool(){
|
||||||
|
switch (getType()){
|
||||||
|
case DTSC_STR:
|
||||||
|
return (p[1] | p[2] | p[3] | p[4]);
|
||||||
|
case DTSC_INT:
|
||||||
|
return (asInt() != 0);
|
||||||
|
case DTSC_OBJ:
|
||||||
|
case DTSC_CON:
|
||||||
|
case DTSC_ARR:
|
||||||
|
return (p[1] | p[2]);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the long long value of this DTSC number value.
|
||||||
|
/// Will convert string values to numbers, taking octal and hexadecimal types into account.
|
||||||
|
/// Illegal or invalid values return 0.
|
||||||
|
long long Scan::asInt(){
|
||||||
|
switch (getType()){
|
||||||
|
case DTSC_INT:
|
||||||
|
return ((long long int)p[1] << 56) | ((long long int)p[2] << 48) | ((long long int)p[3] << 40) | ((long long int)p[4] << 32) | ((long long int)p[5] << 24) | ((long long int)p[6] << 16) | ((long long int)p[7] << 8) | p[8];
|
||||||
|
case DTSC_STR:
|
||||||
|
char * str;
|
||||||
|
unsigned int strlen;
|
||||||
|
getString(str, strlen);
|
||||||
|
if (!strlen){return 0;}
|
||||||
|
return strtoll(str, 0, 0);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the string value of this DTSC string value.
|
||||||
|
/// Uses getString internally, does no conversion.
|
||||||
|
/// Returns an empty string on error.
|
||||||
|
std::string Scan::asString(){
|
||||||
|
char * str;
|
||||||
|
unsigned int strlen;
|
||||||
|
getString(str, strlen);
|
||||||
|
return std::string(str, strlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets result to a pointer to the string, and strlen to the lenght of it.
|
||||||
|
/// Sets both to zero if this isn't a DTSC string value.
|
||||||
|
/// Attempts absolutely no conversion.
|
||||||
|
void Scan::getString(char *& result, unsigned int & strlen){
|
||||||
|
switch (getType()){
|
||||||
|
case DTSC_STR:
|
||||||
|
result = p+5;
|
||||||
|
strlen = p[1] * 256 * 256 * 256 + p[2] * 256 * 256 + p[3] * 256 + p[4];
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
result = 0;
|
||||||
|
strlen = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \todo Move this function to some generic area. Duplicate from json.cpp
|
||||||
|
static inline char hex2c(char c){
|
||||||
|
if (c < 10){return '0' + c;}
|
||||||
|
if (c < 16){return 'A' + (c - 10);}
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \todo Move this function to some generic area. Duplicate from json.cpp
|
||||||
|
static std::string string_escape(const std::string val){
|
||||||
|
std::stringstream out;
|
||||||
|
out << "\"";
|
||||||
|
for (unsigned int i = 0; i < val.size(); ++i){
|
||||||
|
switch (val.data()[i]){
|
||||||
|
case '"':
|
||||||
|
out << "\\\"";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
out << "\\\\";
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
out << "\\n";
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
out << "\\b";
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
out << "\\f";
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
out << "\\r";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
out << "\\t";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (val.data()[i] < 32 || val.data()[i] > 126){
|
||||||
|
out << "\\u00";
|
||||||
|
out << hex2c((val.data()[i] >> 4) & 0xf);
|
||||||
|
out << hex2c(val.data()[i] & 0xf);
|
||||||
|
}else{
|
||||||
|
out << val.data()[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "\"";
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Scan::toPrettyString(unsigned int indent){
|
||||||
|
switch (getType()){
|
||||||
|
case DTSC_STR:{
|
||||||
|
unsigned int strlen = p[1] * 256 * 256 * 256 + p[2] * 256 * 256 + p[3] * 256 + p[4];
|
||||||
|
if (strlen > 250){
|
||||||
|
std::stringstream ret;
|
||||||
|
ret << "\"" << strlen << " bytes of data\"";
|
||||||
|
return ret.str();
|
||||||
|
}
|
||||||
|
return string_escape(asString());
|
||||||
|
}
|
||||||
|
case DTSC_INT:{
|
||||||
|
std::stringstream ret;
|
||||||
|
ret << asInt();
|
||||||
|
return ret.str();
|
||||||
|
}
|
||||||
|
case DTSC_OBJ:
|
||||||
|
case DTSC_CON:{
|
||||||
|
std::stringstream ret;
|
||||||
|
ret << "{" << std::endl;
|
||||||
|
indent += 2;
|
||||||
|
char * i = p+1;
|
||||||
|
//object, scan contents
|
||||||
|
while (i[0] + i[1] != 0 && i < p+len){ //while not encountering 0x0000 (we assume 0x0000EE)
|
||||||
|
if (i+2 >= p+len){
|
||||||
|
indent -= 2;
|
||||||
|
ret << std::string((size_t)indent, ' ') << "} //walked out of object here";
|
||||||
|
return ret.str();
|
||||||
|
}
|
||||||
|
unsigned int strlen = i[0] * 256 + i[1];
|
||||||
|
i += 2;
|
||||||
|
ret << std::string((size_t)indent, ' ') << "\"" << std::string(i, strlen) << "\": " << Scan(i+strlen, len-(i-p)).toPrettyString(indent) << "," << std::endl;
|
||||||
|
i = skipDTSC(i+strlen, p+len);
|
||||||
|
if (!i){
|
||||||
|
indent -= 2;
|
||||||
|
ret << std::string((size_t)indent, ' ') << "} //could not locate next object";
|
||||||
|
return ret.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indent -= 2;
|
||||||
|
ret << std::string((size_t)indent, ' ') << "}";
|
||||||
|
return ret.str();
|
||||||
|
}
|
||||||
|
case DTSC_ARR:{
|
||||||
|
std::stringstream ret;
|
||||||
|
ret << "[" << std::endl;
|
||||||
|
indent += 2;
|
||||||
|
Scan tmpScan;
|
||||||
|
unsigned int i = 0;
|
||||||
|
do {
|
||||||
|
tmpScan = getIndice(i++);
|
||||||
|
if (tmpScan.getType()){
|
||||||
|
ret << std::string((size_t)indent, ' ') << tmpScan.toPrettyString(indent) << "," << std::endl;
|
||||||
|
}
|
||||||
|
}while(tmpScan.getType());
|
||||||
|
indent -= 2;
|
||||||
|
ret << std::string((size_t)indent, ' ') << "]";
|
||||||
|
return ret.str();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///\brief Returns the payloadsize of a part
|
///\brief Returns the payloadsize of a part
|
||||||
|
@ -698,6 +926,46 @@ namespace DTSC {
|
||||||
commentHeader = trackRef["commentheader"].asStringRef();
|
commentHeader = trackRef["commentheader"].asStringRef();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///\brief Constructs a track from a JSON::Value
|
||||||
|
Track::Track(Scan & trackRef) {
|
||||||
|
if (trackRef.getMember("fragments").getType() == DTSC_STR){
|
||||||
|
char * tmp = 0;
|
||||||
|
unsigned int tmplen = 0;
|
||||||
|
trackRef.getMember("fragments").getString(tmp, tmplen);
|
||||||
|
fragments = std::deque<Fragment>((Fragment *)tmp, ((Fragment *)tmp) + (tmplen / 11));
|
||||||
|
}
|
||||||
|
if (trackRef.getMember("keys").getType() == DTSC_STR){
|
||||||
|
char * tmp = 0;
|
||||||
|
unsigned int tmplen = 0;
|
||||||
|
trackRef.getMember("keys").getString(tmp, tmplen);
|
||||||
|
keys = std::deque<Key>((Key *)tmp, ((Key *)tmp) + (tmplen / 16));
|
||||||
|
}
|
||||||
|
if (trackRef.getMember("parts").getType() == DTSC_STR){
|
||||||
|
char * tmp = 0;
|
||||||
|
unsigned int tmplen = 0;
|
||||||
|
trackRef.getMember("parts").getString(tmp, tmplen);
|
||||||
|
parts = std::deque<Part>((Part *)tmp, ((Part *)tmp) + (tmplen / 9));
|
||||||
|
}
|
||||||
|
trackID = trackRef.getMember("trackid").asInt();
|
||||||
|
firstms = trackRef.getMember("firstms").asInt();
|
||||||
|
lastms = trackRef.getMember("lastms").asInt();
|
||||||
|
bps = trackRef.getMember("bps").asInt();
|
||||||
|
missedFrags = trackRef.getMember("missed_frags").asInt();
|
||||||
|
codec = trackRef.getMember("codec").asString();
|
||||||
|
type = trackRef.getMember("type").asString();
|
||||||
|
init = trackRef.getMember("init").asString();
|
||||||
|
if (type == "audio") {
|
||||||
|
rate = trackRef.getMember("rate").asInt();
|
||||||
|
size = trackRef.getMember("size").asInt();
|
||||||
|
channels = trackRef.getMember("channels").asInt();
|
||||||
|
}
|
||||||
|
if (type == "video") {
|
||||||
|
width = trackRef.getMember("width").asInt();
|
||||||
|
height = trackRef.getMember("height").asInt();
|
||||||
|
fpks = trackRef.getMember("fpks").asInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///\brief Updates a track and its metadata given a DTSC::Packet.
|
///\brief Updates a track and its metadata given a DTSC::Packet.
|
||||||
///
|
///
|
||||||
|
@ -709,7 +977,7 @@ namespace DTSC {
|
||||||
}
|
}
|
||||||
Part newPart;
|
Part newPart;
|
||||||
char * data;
|
char * data;
|
||||||
int dataLen;
|
unsigned int dataLen;
|
||||||
pack.getString("data", data, dataLen);
|
pack.getString("data", data, dataLen);
|
||||||
newPart.setSize(dataLen);
|
newPart.setSize(dataLen);
|
||||||
newPart.setOffset(pack.getInt("offset"));
|
newPart.setOffset(pack.getInt("offset"));
|
||||||
|
@ -976,6 +1244,32 @@ namespace DTSC {
|
||||||
}
|
}
|
||||||
moreheader = rhs.moreheader;
|
moreheader = rhs.moreheader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Meta::Meta(const DTSC::Packet & source){
|
||||||
|
reinit(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::reinit(const DTSC::Packet & source){
|
||||||
|
tracks.clear();
|
||||||
|
vod = source.getFlag("vod");
|
||||||
|
live = source.getFlag("live");
|
||||||
|
merged = source.getFlag("merged");
|
||||||
|
bufferWindow = source.getInt("buffer_window");
|
||||||
|
moreheader = source.getInt("moreheader");
|
||||||
|
Scan tmpTracks = source.getScan().getMember("tracks");
|
||||||
|
unsigned int num = 0;
|
||||||
|
Scan tmpTrack;
|
||||||
|
do{
|
||||||
|
tmpTrack = tmpTracks.getIndice(num);
|
||||||
|
if (tmpTrack.asBool()){
|
||||||
|
int trackId = tmpTrack.getMember("trackid").asInt();
|
||||||
|
if (trackId){
|
||||||
|
tracks[trackId] = Track(tmpTrack);
|
||||||
|
}
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
}while(tmpTrack.asBool());
|
||||||
|
}
|
||||||
|
|
||||||
///\brief Creates a meta object from a JSON::Value
|
///\brief Creates a meta object from a JSON::Value
|
||||||
Meta::Meta(JSON::Value & meta) {
|
Meta::Meta(JSON::Value & meta) {
|
||||||
|
@ -1421,12 +1715,12 @@ namespace DTSC {
|
||||||
for (std::map<int, readOnlyTrack>::iterator it = tracks.begin(); it != tracks.end(); it++) {
|
for (std::map<int, readOnlyTrack>::iterator it = tracks.begin(); it != tracks.end(); it++) {
|
||||||
dataLen += it->second.getSendLen();
|
dataLen += it->second.getSendLen();
|
||||||
}
|
}
|
||||||
return dataLen;
|
return dataLen+8;//add 8 bytes header length
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Writes a read-only meta object to a pointer
|
///\brief Writes a read-only meta object to a pointer
|
||||||
void readOnlyMeta::writeTo(char * p){
|
void readOnlyMeta::writeTo(char * p){
|
||||||
int dataLen = getSendLen();
|
int dataLen = getSendLen() - 8;//strip 8 bytes header
|
||||||
writePointer(p, DTSC::Magic_Header, 4);
|
writePointer(p, DTSC::Magic_Header, 4);
|
||||||
writePointer(p, convertInt(dataLen), 4);
|
writePointer(p, convertInt(dataLen), 4);
|
||||||
writePointer(p, "\340\000\006tracks\340", 10);
|
writePointer(p, "\340\000\006tracks\340", 10);
|
||||||
|
@ -1457,7 +1751,7 @@ namespace DTSC {
|
||||||
|
|
||||||
///\brief Writes a read-only meta object to a socket
|
///\brief Writes a read-only meta object to a socket
|
||||||
void readOnlyMeta::send(Socket::Connection & conn) {
|
void readOnlyMeta::send(Socket::Connection & conn) {
|
||||||
int dataLen = getSendLen();
|
int dataLen = getSendLen()-8;//strip 8 bytes header
|
||||||
conn.SendNow(DTSC::Magic_Header, 4);
|
conn.SendNow(DTSC::Magic_Header, 4);
|
||||||
conn.SendNow(convertInt(dataLen), 4);
|
conn.SendNow(convertInt(dataLen), 4);
|
||||||
conn.SendNow("\340\000\006tracks\340", 10);
|
conn.SendNow("\340\000\006tracks\340", 10);
|
||||||
|
@ -1492,12 +1786,12 @@ namespace DTSC {
|
||||||
for (std::map<int, Track>::iterator it = tracks.begin(); it != tracks.end(); it++) {
|
for (std::map<int, Track>::iterator it = tracks.begin(); it != tracks.end(); it++) {
|
||||||
dataLen += it->second.getSendLen();
|
dataLen += it->second.getSendLen();
|
||||||
}
|
}
|
||||||
return dataLen;
|
return dataLen+8;//add 8 bytes header
|
||||||
}
|
}
|
||||||
|
|
||||||
///\brief Writes a meta object to a pointer
|
///\brief Writes a meta object to a pointer
|
||||||
void Meta::writeTo(char * p){
|
void Meta::writeTo(char * p){
|
||||||
int dataLen = getSendLen();
|
int dataLen = getSendLen()-8;//strip 8 bytes header
|
||||||
writePointer(p, DTSC::Magic_Header, 4);
|
writePointer(p, DTSC::Magic_Header, 4);
|
||||||
writePointer(p, convertInt(dataLen), 4);
|
writePointer(p, convertInt(dataLen), 4);
|
||||||
writePointer(p, "\340\000\006tracks\340", 10);
|
writePointer(p, "\340\000\006tracks\340", 10);
|
||||||
|
@ -1528,7 +1822,7 @@ namespace DTSC {
|
||||||
|
|
||||||
///\brief Writes a meta object to a socket
|
///\brief Writes a meta object to a socket
|
||||||
void Meta::send(Socket::Connection & conn) {
|
void Meta::send(Socket::Connection & conn) {
|
||||||
int dataLen = getSendLen();
|
int dataLen = getSendLen()-8;//strip 8 bytes header
|
||||||
conn.SendNow(DTSC::Magic_Header, 4);
|
conn.SendNow(DTSC::Magic_Header, 4);
|
||||||
conn.SendNow(convertInt(dataLen), 4);
|
conn.SendNow(convertInt(dataLen), 4);
|
||||||
conn.SendNow("\340\000\006tracks\340", 10);
|
conn.SendNow("\340\000\006tracks\340", 10);
|
||||||
|
|
|
@ -376,8 +376,9 @@ bool FLV::Tag::DTSCLoader(DTSC::Packet & packData, DTSC::Track & track){
|
||||||
len = 0;
|
len = 0;
|
||||||
if (track.type == "video"){
|
if (track.type == "video"){
|
||||||
char * tmpData = 0;
|
char * tmpData = 0;
|
||||||
packData.getString("data", tmpData, len);
|
unsigned int tmpLen = 0;
|
||||||
len += 16;
|
packData.getString("data", tmpData, tmpLen);
|
||||||
|
len = tmpLen + 16;
|
||||||
if (track.codec == "H264"){
|
if (track.codec == "H264"){
|
||||||
len += 4;
|
len += 4;
|
||||||
}
|
}
|
||||||
|
@ -418,8 +419,9 @@ bool FLV::Tag::DTSCLoader(DTSC::Packet & packData, DTSC::Track & track){
|
||||||
}
|
}
|
||||||
if (track.type == "audio"){
|
if (track.type == "audio"){
|
||||||
char * tmpData = 0;
|
char * tmpData = 0;
|
||||||
packData.getString("data", tmpData, len);
|
unsigned int tmpLen = 0;
|
||||||
len += 16;
|
packData.getString("data", tmpData, tmpLen);
|
||||||
|
len = tmpLen + 16;
|
||||||
if (track.codec == "AAC"){
|
if (track.codec == "AAC"){
|
||||||
len ++;
|
len ++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue