From 38ef8704f8cd5c00f712361f4f732354c08c24c8 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Tue, 11 Dec 2012 11:03:33 +0100 Subject: [PATCH] Global cleanups and standardization of code style. --- lib/amf.cpp | 1027 ++++++++++++---------- lib/amf.h | 25 +- lib/auth.cpp | 42 +- lib/auth.h | 2 +- lib/base64.cpp | 62 +- lib/config.cpp | 141 ++-- lib/config.h | 10 +- lib/crypto.cpp | 0 lib/crypto.h | 25 - lib/dtsc.cpp | 200 +++-- lib/dtsc.h | 18 +- lib/filesystem.cpp | 308 ++++--- lib/filesystem.h | 76 +- lib/flv_tag.cpp | 710 +++++++++++----- lib/flv_tag.h | 14 +- lib/ftp.cpp | 488 +++++++---- lib/ftp.h | 59 +- lib/http_parser.cpp | 121 ++- lib/http_parser.h | 8 +- lib/json.cpp | 315 ++++--- lib/json.h | 21 +- lib/mp4.cpp | 1962 ++++++++++++++++++++++++++----------------- lib/mp4.h | 289 ++++--- lib/procs.cpp | 302 ++++--- lib/procs.h | 4 +- lib/rtmpchunks.cpp | 538 +++++++----- lib/rtmpchunks.h | 11 +- lib/socket.cpp | 295 ++++--- lib/socket.h | 21 +- lib/stream.cpp | 29 +- lib/stream.h | 2 +- lib/timing.cpp | 17 +- lib/timing.h | 4 +- 33 files changed, 4322 insertions(+), 2824 deletions(-) delete mode 100644 lib/crypto.cpp delete mode 100644 lib/crypto.h diff --git a/lib/amf.cpp b/lib/amf.cpp index 1bd81168..dcd163e5 100644 --- a/lib/amf.cpp +++ b/lib/amf.cpp @@ -4,80 +4,101 @@ #include "amf.h" #include #include //needed for stderr only - /// Returns the std::string Indice for the current object, if available. /// Returns an empty string if no indice exists. -std::string AMF::Object::Indice(){return myIndice;}; +std::string AMF::Object::Indice(){ + return myIndice; +} /// Returns the AMF::obj0type AMF0 object type for this object. -AMF::obj0type AMF::Object::GetType(){return myType;}; +AMF::obj0type AMF::Object::GetType(){ + return myType; +} /// Returns the numeric value of this object, if available. /// If this object holds no numeric value, 0 is returned. -double AMF::Object::NumValue(){return numval;}; +double AMF::Object::NumValue(){ + return numval; +} /// Returns the std::string value of this object, if available. /// If this object holds no string value, an empty string is returned. -std::string AMF::Object::StrValue(){return strval;}; +std::string AMF::Object::StrValue(){ + return strval; +} /// Returns the C-string value of this object, if available. /// If this object holds no string value, an empty C-string is returned. -const char * AMF::Object::Str(){return strval.c_str();}; +const char * AMF::Object::Str(){ + return strval.c_str(); +} /// Returns a count of the amount of objects this object currently holds. /// If this object is not a container type, this function will always return 0. -int AMF::Object::hasContent(){return contents.size();}; +int AMF::Object::hasContent(){ + return contents.size(); +} /// Adds an AMF::Object to this object. Works for all types, but only makes sense for container types. -void AMF::Object::addContent(AMF::Object c){contents.push_back(c);}; +void AMF::Object::addContent(AMF::Object c){ + contents.push_back(c); +} /// Returns a pointer to the object held at indice i. /// Returns AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice. /// \param i The indice of the object in this container. -AMF::Object* AMF::Object::getContentP(int i){return &contents.at(i);}; +AMF::Object* AMF::Object::getContentP(int i){ + return &contents.at(i); +} /// Returns a copy of the object held at indice i. /// Returns a AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice. /// \param i The indice of the object in this container. -AMF::Object AMF::Object::getContent(int i){return contents.at(i);}; +AMF::Object AMF::Object::getContent(int i){ + return contents.at(i); +} /// Returns a pointer to the object held at indice s. /// Returns NULL if no object is held at this indice. /// \param s The indice of the object in this container. AMF::Object* AMF::Object::getContentP(std::string s){ for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ - if (it->Indice() == s){return &(*it);} + if (it->Indice() == s){ + return &( *it); + } } return 0; -}; +} /// Returns a copy of the object held at indice s. /// Returns a AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice. /// \param s The indice of the object in this container. AMF::Object AMF::Object::getContent(std::string s){ for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ - if (it->Indice() == s){return *it;} + if (it->Indice() == s){ + return *it; + } } return AMF::Object("error", AMF0_DDV_CONTAINER); -}; +} /// Default constructor. /// Simply fills the data with AMF::Object("error", AMF0_DDV_CONTAINER) AMF::Object::Object(){ *this = AMF::Object("error", AMF0_DDV_CONTAINER); -};//default constructor +} //default constructor /// Constructor for numeric objects. /// The object type is by default AMF::AMF0_NUMBER, but this can be forced to a different value. /// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic. /// \param val The numeric value of this object. Numeric AMF0 objects only support double-type values. /// \param setType The object type to force this object to. -AMF::Object::Object(std::string indice, double val, AMF::obj0type setType){//num type initializer +AMF::Object::Object(std::string indice, double val, AMF::obj0type setType){ //num type initializer myIndice = indice; myType = setType; strval = ""; numval = val; -}; +} /// Constructor for string objects. /// The object type is by default AMF::AMF0_STRING, but this can be forced to a different value. @@ -85,23 +106,23 @@ AMF::Object::Object(std::string indice, double val, AMF::obj0type setType){//num /// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic. /// \param val The string value of this object. /// \param setType The object type to force this object to. -AMF::Object::Object(std::string indice, std::string val, AMF::obj0type setType){//str type initializer +AMF::Object::Object(std::string indice, std::string val, AMF::obj0type setType){ //str type initializer myIndice = indice; myType = setType; strval = val; numval = 0; -}; +} /// Constructor for container objects. /// The object type is by default AMF::AMF0_OBJECT, but this can be forced to a different value. /// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic. /// \param setType The object type to force this object to. -AMF::Object::Object(std::string indice, AMF::obj0type setType){//object type initializer +AMF::Object::Object(std::string indice, AMF::obj0type setType){ //object type initializer myIndice = indice; myType = setType; strval = ""; numval = 0; -}; +} /// Prints the contents of this object to std::cerr. /// If this object contains other objects, it will call itself recursively @@ -111,41 +132,90 @@ std::string AMF::Object::Print(std::string indent){ st << indent; // print my type switch (myType){ - case AMF::AMF0_NUMBER: st << "Number"; break; - case AMF::AMF0_BOOL: st << "Bool"; break; - case AMF::AMF0_STRING://short string - case AMF::AMF0_LONGSTRING: st << "String"; break; - case AMF::AMF0_OBJECT: st << "Object"; break; - case AMF::AMF0_MOVIECLIP: st << "MovieClip"; break; - case AMF::AMF0_NULL: st << "Null"; break; - case AMF::AMF0_UNDEFINED: st << "Undefined"; break; - case AMF::AMF0_REFERENCE: st << "Reference"; break; - case AMF::AMF0_ECMA_ARRAY: st << "ECMA Array"; break; - case AMF::AMF0_OBJ_END: st << "Object end"; break; - case AMF::AMF0_STRICT_ARRAY: st << "Strict Array"; break; - case AMF::AMF0_DATE: st << "Date"; break; - case AMF::AMF0_UNSUPPORTED: st << "Unsupported"; break; - case AMF::AMF0_RECORDSET: st << "Recordset"; break; - case AMF::AMF0_XMLDOC: st << "XML Document"; break; - case AMF::AMF0_TYPED_OBJ: st << "Typed Object"; break; - case AMF::AMF0_UPGRADE: st << "Upgrade to AMF3"; break; - case AMF::AMF0_DDV_CONTAINER: st << "DDVTech Container"; break; + case AMF::AMF0_NUMBER: + st << "Number"; + break; + case AMF::AMF0_BOOL: + st << "Bool"; + break; + case AMF::AMF0_STRING: //short string + case AMF::AMF0_LONGSTRING: + st << "String"; + break; + case AMF::AMF0_OBJECT: + st << "Object"; + break; + case AMF::AMF0_MOVIECLIP: + st << "MovieClip"; + break; + case AMF::AMF0_NULL: + st << "Null"; + break; + case AMF::AMF0_UNDEFINED: + st << "Undefined"; + break; + case AMF::AMF0_REFERENCE: + st << "Reference"; + break; + case AMF::AMF0_ECMA_ARRAY: + st << "ECMA Array"; + break; + case AMF::AMF0_OBJ_END: + st << "Object end"; + break; + case AMF::AMF0_STRICT_ARRAY: + st << "Strict Array"; + break; + case AMF::AMF0_DATE: + st << "Date"; + break; + case AMF::AMF0_UNSUPPORTED: + st << "Unsupported"; + break; + case AMF::AMF0_RECORDSET: + st << "Recordset"; + break; + case AMF::AMF0_XMLDOC: + st << "XML Document"; + break; + case AMF::AMF0_TYPED_OBJ: + st << "Typed Object"; + break; + case AMF::AMF0_UPGRADE: + st << "Upgrade to AMF3"; + break; + case AMF::AMF0_DDV_CONTAINER: + st << "DDVTech Container"; + break; } // print my string indice, if available st << " " << myIndice << " "; // print my numeric or string contents switch (myType){ - case AMF::AMF0_NUMBER: case AMF::AMF0_BOOL: case AMF::AMF0_REFERENCE: case AMF::AMF0_DATE: st << numval; break; - case AMF::AMF0_STRING: case AMF::AMF0_LONGSTRING: case AMF::AMF0_XMLDOC: case AMF::AMF0_TYPED_OBJ: st << strval; break; - default: break;//we don't care about the rest, and don't want a compiler warning... + case AMF::AMF0_NUMBER: + case AMF::AMF0_BOOL: + case AMF::AMF0_REFERENCE: + case AMF::AMF0_DATE: + st << numval; + break; + case AMF::AMF0_STRING: + case AMF::AMF0_LONGSTRING: + case AMF::AMF0_XMLDOC: + case AMF::AMF0_TYPED_OBJ: + st << strval; + break; + default: + break; //we don't care about the rest, and don't want a compiler warning... } st << std::endl; // if I hold other objects, print those too, recursively. if (contents.size() > 0){ - for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){st << it->Print(indent+" ");} + for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ + st << it->Print(indent + " "); + } } return st.str(); -};//print +} //print /// Packs the AMF object to a std::string for transfer over the network. /// If the object is a container type, this function will call itself recursively and contain all contents. @@ -153,24 +223,36 @@ std::string AMF::Object::Print(std::string indent){ std::string AMF::Object::Pack(){ std::string r = ""; //check for string/longstring conversion - if ((myType == AMF::AMF0_STRING) && (strval.size() > 0xFFFF)){myType = AMF::AMF0_LONGSTRING;} + if ((myType == AMF::AMF0_STRING) && (strval.size() > 0xFFFF)){ + myType = AMF::AMF0_LONGSTRING; + } //skip output of DDV container types, they do not exist. Only output their contents. - if (myType != AMF::AMF0_DDV_CONTAINER){r += myType;} + if (myType != AMF::AMF0_DDV_CONTAINER){ + r += myType; + } //output the properly formatted AMF0 data stream for this object's contents. switch (myType){ case AMF::AMF0_NUMBER: - r += *(((char*)&numval)+7); r += *(((char*)&numval)+6); - r += *(((char*)&numval)+5); r += *(((char*)&numval)+4); - r += *(((char*)&numval)+3); r += *(((char*)&numval)+2); - r += *(((char*)&numval)+1); r += *(((char*)&numval)); + r += *(((char*) &numval) + 7); + r += *(((char*) &numval) + 6); + r += *(((char*) &numval) + 5); + r += *(((char*) &numval) + 4); + r += *(((char*) &numval) + 3); + r += *(((char*) &numval) + 2); + r += *(((char*) &numval) + 1); + r += *(((char*) &numval)); break; case AMF::AMF0_DATE: - r += *(((char*)&numval)+7); r += *(((char*)&numval)+6); - r += *(((char*)&numval)+5); r += *(((char*)&numval)+4); - r += *(((char*)&numval)+3); r += *(((char*)&numval)+2); - r += *(((char*)&numval)+1); r += *(((char*)&numval)); - r += (char)0;//timezone always 0 - r += (char)0;//timezone always 0 + r += *(((char*) &numval) + 7); + r += *(((char*) &numval) + 6); + r += *(((char*) &numval) + 5); + r += *(((char*) &numval) + 4); + r += *(((char*) &numval) + 3); + r += *(((char*) &numval) + 2); + r += *(((char*) &numval) + 1); + r += *(((char*) &numval)); + r += (char)0; //timezone always 0 + r += (char)0; //timezone always 0 break; case AMF::AMF0_BOOL: r += (char)numval; @@ -181,18 +263,18 @@ std::string AMF::Object::Pack(){ r += strval; break; case AMF::AMF0_LONGSTRING: - case AMF::AMF0_XMLDOC://is always a longstring - r += strval.size() / (256*256*256); - r += strval.size() / (256*256); + case AMF::AMF0_XMLDOC: //is always a longstring + r += strval.size() / (256 * 256 * 256); + r += strval.size() / (256 * 256); r += strval.size() / 256; r += strval.size() % 256; r += strval; break; - case AMF::AMF0_TYPED_OBJ: + case AMF::AMF0_TYPED_OBJ: //is an object, with the classname first r += Indice().size() / 256; r += Indice().size() % 256; r += Indice(); - //is an object, with the classname first + /* no break */ case AMF::AMF0_OBJECT: if (contents.size() > 0){ for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ @@ -202,7 +284,9 @@ std::string AMF::Object::Pack(){ r += it->Pack(); } } - r += (char)0; r += (char)0; r += (char)9; + r += (char)0; + r += (char)0; + r += (char)9; break; case AMF::AMF0_MOVIECLIP: case AMF::AMF0_OBJ_END: @@ -217,11 +301,14 @@ std::string AMF::Object::Pack(){ r += (char)((int)numval / 256); r += (char)((int)numval % 256); break; - case AMF::AMF0_ECMA_ARRAY:{ + case AMF::AMF0_ECMA_ARRAY: { int arrlen = 0; if (contents.size() > 0){ arrlen = contents.size(); - r += arrlen / (256*256*256); r += arrlen / (256*256); r += arrlen / 256; r += arrlen % 256; + r += arrlen / (256 * 256 * 256); + r += arrlen / (256 * 256); + r += arrlen / 256; + r += arrlen % 256; for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ r += it->Indice().size() / 256; r += it->Indice().size() % 256; @@ -229,23 +316,36 @@ std::string AMF::Object::Pack(){ r += it->Pack(); } }else{ - r += (char)0; r += (char)0; r += (char)0; r += (char)0; + r += (char)0; + r += (char)0; + r += (char)0; + r += (char)0; } - r += (char)0; r += (char)0; r += (char)9; - } break; - case AMF::AMF0_STRICT_ARRAY:{ + r += (char)0; + r += (char)0; + r += (char)9; + } + break; + case AMF::AMF0_STRICT_ARRAY: { int arrlen = 0; if (contents.size() > 0){ arrlen = contents.size(); - r += arrlen / (256*256*256); r += arrlen / (256*256); r += arrlen / 256; r += arrlen % 256; + r += arrlen / (256 * 256 * 256); + r += arrlen / (256 * 256); + r += arrlen / 256; + r += arrlen % 256; for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ r += it->Pack(); } }else{ - r += (char)0; r += (char)0; r += (char)0; r += (char)0; + r += (char)0; + r += (char)0; + r += (char)0; + r += (char)0; } - } break; - case AMF::AMF0_DDV_CONTAINER://only send contents + } + break; + case AMF::AMF0_DDV_CONTAINER: //only send contents if (contents.size() > 0){ for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ r += it->Pack(); @@ -254,7 +354,7 @@ std::string AMF::Object::Pack(){ break; } return r; -};//pack +} //pack /// Parses a single AMF0 type - used recursively by the AMF::parse() functions. /// This function updates i every call with the new position in the data. @@ -267,248 +367,280 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign std::string tmpstr; unsigned int tmpi = 0; unsigned char tmpdbl[8]; - double *d;// hack to work around strict aliasing - #if DEBUG >= 10 + double *d; // hack to work around strict aliasing +#if DEBUG >= 10 fprintf(stderr, "Note: AMF type %hhx found. %i bytes left\n", data[i], len-i); - #endif +#endif switch (data[i]){ case AMF::AMF0_NUMBER: - tmpdbl[7] = data[i+1]; - tmpdbl[6] = data[i+2]; - tmpdbl[5] = data[i+3]; - tmpdbl[4] = data[i+4]; - tmpdbl[3] = data[i+5]; - tmpdbl[2] = data[i+6]; - tmpdbl[1] = data[i+7]; - tmpdbl[0] = data[i+8]; - i+=9;//skip 8(a double)+1 forwards + tmpdbl[7] = data[i + 1]; + tmpdbl[6] = data[i + 2]; + tmpdbl[5] = data[i + 3]; + tmpdbl[4] = data[i + 4]; + tmpdbl[3] = data[i + 5]; + tmpdbl[2] = data[i + 6]; + tmpdbl[1] = data[i + 7]; + tmpdbl[0] = data[i + 8]; + i += 9; //skip 8(a double)+1 forwards d = (double*)tmpdbl; return AMF::Object(name, *d, AMF::AMF0_NUMBER); break; case AMF::AMF0_DATE: - tmpdbl[7] = data[i+1]; - tmpdbl[6] = data[i+2]; - tmpdbl[5] = data[i+3]; - tmpdbl[4] = data[i+4]; - tmpdbl[3] = data[i+5]; - tmpdbl[2] = data[i+6]; - tmpdbl[1] = data[i+7]; - tmpdbl[0] = data[i+8]; - i+=11;//skip 8(a double)+1+timezone(2) forwards + tmpdbl[7] = data[i + 1]; + tmpdbl[6] = data[i + 2]; + tmpdbl[5] = data[i + 3]; + tmpdbl[4] = data[i + 4]; + tmpdbl[3] = data[i + 5]; + tmpdbl[2] = data[i + 6]; + tmpdbl[1] = data[i + 7]; + tmpdbl[0] = data[i + 8]; + i += 11; //skip 8(a double)+1+timezone(2) forwards d = (double*)tmpdbl; return AMF::Object(name, *d, AMF::AMF0_DATE); break; case AMF::AMF0_BOOL: - i+=2;//skip bool+1 forwards - if (data[i-1] == 0){ + i += 2; //skip bool+1 forwards + if (data[i - 1] == 0){ return AMF::Object(name, (double)0, AMF::AMF0_BOOL); }else{ return AMF::Object(name, (double)1, AMF::AMF0_BOOL); } break; case AMF::AMF0_REFERENCE: - tmpi = data[i+1]*256+data[i+2];//get the ref number value as a double - i+=3;//skip ref+1 forwards + tmpi = data[i + 1] * 256 + data[i + 2]; //get the ref number value as a double + i += 3; //skip ref+1 forwards return AMF::Object(name, (double)tmpi, AMF::AMF0_REFERENCE); break; case AMF::AMF0_XMLDOC: - tmpi = data[i+1]*256*256*256+data[i+2]*256*256+data[i+3]*256+data[i+4];//set tmpi to UTF-8-long length - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char *)data+i+5, (size_t)tmpi);//add the string data - i += tmpi + 5;//skip length+size+1 forwards + tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; //set tmpi to UTF-8-long length + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char *)data + i + 5, (size_t)tmpi); //add the string data + i += tmpi + 5; //skip length+size+1 forwards return AMF::Object(name, tmpstr, AMF::AMF0_XMLDOC); break; case AMF::AMF0_LONGSTRING: - tmpi = data[i+1]*256*256*256+data[i+2]*256*256+data[i+3]*256+data[i+4];//set tmpi to UTF-8-long length - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char *)data+i+5, (size_t)tmpi);//add the string data - i += tmpi + 5;//skip length+size+1 forwards + tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; //set tmpi to UTF-8-long length + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char *)data + i + 5, (size_t)tmpi); //add the string data + i += tmpi + 5; //skip length+size+1 forwards return AMF::Object(name, tmpstr, AMF::AMF0_LONGSTRING); break; case AMF::AMF0_STRING: - tmpi = data[i+1]*256+data[i+2];//set tmpi to UTF-8 length - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char *)data+i+3, (size_t)tmpi);//add the string data - i += tmpi + 3;//skip length+size+1 forwards + tmpi = data[i + 1] * 256 + data[i + 2]; //set tmpi to UTF-8 length + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char *)data + i + 3, (size_t)tmpi); //add the string data + i += tmpi + 3; //skip length+size+1 forwards return AMF::Object(name, tmpstr, AMF::AMF0_STRING); break; case AMF::AMF0_NULL: case AMF::AMF0_UNDEFINED: case AMF::AMF0_UNSUPPORTED: ++i; - return AMF::Object(name, (double)0, (AMF::obj0type)data[i-1]); + return AMF::Object(name, (double)0, (AMF::obj0type)data[i - 1]); break; - case AMF::AMF0_OBJECT:{ + case AMF::AMF0_OBJECT: { ++i; AMF::Object ret(name, AMF::AMF0_OBJECT); - while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x000009) - tmpi = data[i]*256+data[i+1];//set tmpi to the UTF-8 length - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char*)data+i+2, (size_t)tmpi);//add the string data - i += tmpi + 2;//skip length+size forwards - ret.addContent(AMF::parseOne(data, len, i, tmpstr));//add content, recursively parsed, updating i, setting indice to tmpstr + while (data[i] + data[i + 1] != 0){ //while not encountering 0x0000 (we assume 0x000009) + tmpi = data[i] * 256 + data[i + 1]; //set tmpi to the UTF-8 length + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char*)data + i + 2, (size_t)tmpi); //add the string data + i += tmpi + 2; //skip length+size forwards + ret.addContent(AMF::parseOne(data, len, i, tmpstr)); //add content, recursively parsed, updating i, setting indice to tmpstr } - i += 3;//skip 0x000009 + i += 3; //skip 0x000009 return ret; - } break; - case AMF::AMF0_TYPED_OBJ:{ + } + break; + case AMF::AMF0_TYPED_OBJ: { ++i; - tmpi = data[i]*256+data[i+1];//set tmpi to the UTF-8 length - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char*)data+i+2, (size_t)tmpi);//add the string data - AMF::Object ret(tmpstr, AMF::AMF0_TYPED_OBJ);//the object is not named "name" but tmpstr - while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x000009) - tmpi = data[i]*256+data[i+1];//set tmpi to the UTF-8 length - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char*)data+i+2, (size_t)tmpi);//add the string data - i += tmpi + 2;//skip length+size forwards - ret.addContent(AMF::parseOne(data, len, i, tmpstr));//add content, recursively parsed, updating i, setting indice to tmpstr + tmpi = data[i] * 256 + data[i + 1]; //set tmpi to the UTF-8 length + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char*)data + i + 2, (size_t)tmpi); //add the string data + AMF::Object ret(tmpstr, AMF::AMF0_TYPED_OBJ); //the object is not named "name" but tmpstr + while (data[i] + data[i + 1] != 0){ //while not encountering 0x0000 (we assume 0x000009) + tmpi = data[i] * 256 + data[i + 1]; //set tmpi to the UTF-8 length + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char*)data + i + 2, (size_t)tmpi); //add the string data + i += tmpi + 2; //skip length+size forwards + ret.addContent(AMF::parseOne(data, len, i, tmpstr)); //add content, recursively parsed, updating i, setting indice to tmpstr } - i += 3;//skip 0x000009 + i += 3; //skip 0x000009 return ret; - } break; - case AMF::AMF0_ECMA_ARRAY:{ + } + break; + case AMF::AMF0_ECMA_ARRAY: { ++i; AMF::Object ret(name, AMF::AMF0_ECMA_ARRAY); - i += 4;//ignore the array length, we re-calculate it - while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x000009) - tmpi = data[i]*256+data[i+1];//set tmpi to the UTF-8 length - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char*)data+i+2, (size_t)tmpi);//add the string data - i += tmpi + 2;//skip length+size forwards - ret.addContent(AMF::parseOne(data, len, i, tmpstr));//add content, recursively parsed, updating i, setting indice to tmpstr + i += 4; //ignore the array length, we re-calculate it + while (data[i] + data[i + 1] != 0){ //while not encountering 0x0000 (we assume 0x000009) + tmpi = data[i] * 256 + data[i + 1]; //set tmpi to the UTF-8 length + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char*)data + i + 2, (size_t)tmpi); //add the string data + i += tmpi + 2; //skip length+size forwards + ret.addContent(AMF::parseOne(data, len, i, tmpstr)); //add content, recursively parsed, updating i, setting indice to tmpstr } - i += 3;//skip 0x000009 + i += 3; //skip 0x000009 return ret; - } break; - case AMF::AMF0_STRICT_ARRAY:{ + } + break; + case AMF::AMF0_STRICT_ARRAY: { AMF::Object ret(name, AMF::AMF0_STRICT_ARRAY); - tmpi = data[i+1]*256*256*256+data[i+2]*256*256+data[i+3]*256+data[i+4];//set tmpi to array length - i += 5;//skip size+1 forwards - while (tmpi > 0){//while not done parsing array - ret.addContent(AMF::parseOne(data, len, i, "arrVal"));//add content, recursively parsed, updating i + tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; //set tmpi to array length + i += 5; //skip size+1 forwards + while (tmpi > 0){ //while not done parsing array + ret.addContent(AMF::parseOne(data, len, i, "arrVal")); //add content, recursively parsed, updating i --tmpi; } return ret; - } break; + } + break; } - #if DEBUG >= 2 +#if DEBUG >= 2 fprintf(stderr, "Error: Unimplemented AMF type %hhx - returning.\n", data[i]); - #endif +#endif return AMF::Object("error", AMF::AMF0_DDV_CONTAINER); -}//parseOne +} //parseOne /// Parses a C-string to a valid AMF::Object. /// This function will find all AMF objects in the string and return /// them all packed in a single AMF::AMF0_DDV_CONTAINER AMF::Object. AMF::Object AMF::parse(const unsigned char * data, unsigned int len){ - AMF::Object ret("returned", AMF::AMF0_DDV_CONTAINER);//container type + AMF::Object ret("returned", AMF::AMF0_DDV_CONTAINER); //container type unsigned int i = 0, j = 0; while (i < len){ ret.addContent(AMF::parseOne(data, len, i, "")); - if (i > j){j = i;}else{return ret;} + if (i > j){ + j = i; + }else{ + return ret; + } } return ret; -}//parse +} //parse /// Parses a std::string to a valid AMF::Object. /// This function will find all AMF objects in the string and return /// them all packed in a single AMF::AMF0_DDV_CONTAINER AMF::Object. AMF::Object AMF::parse(std::string data){ return AMF::parse((const unsigned char*)data.c_str(), data.size()); -}//parse +} //parse /// Returns the std::string Indice for the current object, if available. /// Returns an empty string if no indice exists. -std::string AMF::Object3::Indice(){return myIndice;}; +std::string AMF::Object3::Indice(){ + return myIndice; +} /// Returns the AMF::obj0type AMF0 object type for this object. -AMF::obj3type AMF::Object3::GetType(){return myType;}; +AMF::obj3type AMF::Object3::GetType(){ + return myType; +} /// Returns the double value of this object, if available. /// If this object holds no double value, 0 is returned. -double AMF::Object3::DblValue(){return dblval;}; +double AMF::Object3::DblValue(){ + return dblval; +} /// Returns the integer value of this object, if available. /// If this object holds no integer value, 0 is returned. -int AMF::Object3::IntValue(){return intval;}; +int AMF::Object3::IntValue(){ + return intval; +} /// Returns the std::string value of this object, if available. /// If this object holds no string value, an empty string is returned. -std::string AMF::Object3::StrValue(){return strval;}; +std::string AMF::Object3::StrValue(){ + return strval; +} /// Returns the C-string value of this object, if available. /// If this object holds no string value, an empty C-string is returned. -const char * AMF::Object3::Str(){return strval.c_str();}; +const char * AMF::Object3::Str(){ + return strval.c_str(); +} /// Returns a count of the amount of objects this object currently holds. /// If this object is not a container type, this function will always return 0. -int AMF::Object3::hasContent(){return contents.size();}; +int AMF::Object3::hasContent(){ + return contents.size(); +} /// Adds an AMF::Object to this object. Works for all types, but only makes sense for container types. -void AMF::Object3::addContent(AMF::Object3 c){contents.push_back(c);}; +void AMF::Object3::addContent(AMF::Object3 c){ + contents.push_back(c); +} /// Returns a pointer to the object held at indice i. /// Returns AMF::AMF3_DDV_CONTAINER of indice "error" if no object is held at this indice. /// \param i The indice of the object in this container. -AMF::Object3* AMF::Object3::getContentP(int i){return &contents.at(i);}; +AMF::Object3* AMF::Object3::getContentP(int i){ + return &contents.at(i); +} /// Returns a copy of the object held at indice i. /// Returns a AMF::AMF3_DDV_CONTAINER of indice "error" if no object is held at this indice. /// \param i The indice of the object in this container. -AMF::Object3 AMF::Object3::getContent(int i){return contents.at(i);}; +AMF::Object3 AMF::Object3::getContent(int i){ + return contents.at(i); +} /// Returns a pointer to the object held at indice s. /// Returns NULL if no object is held at this indice. /// \param s The indice of the object in this container. AMF::Object3* AMF::Object3::getContentP(std::string s){ for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ - if (it->Indice() == s){return &(*it);} + if (it->Indice() == s){ + return &( *it); + } } return 0; -}; +} /// Returns a copy of the object held at indice s. /// Returns a AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice. /// \param s The indice of the object in this container. AMF::Object3 AMF::Object3::getContent(std::string s){ for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ - if (it->Indice() == s){return *it;} + if (it->Indice() == s){ + return *it; + } } return AMF::Object3("error", AMF3_DDV_CONTAINER); -}; +} /// Default constructor. /// Simply fills the data with AMF::Object3("error", AMF3_DDV_CONTAINER) AMF::Object3::Object3(){ *this = AMF::Object3("error", AMF3_DDV_CONTAINER); -};//default constructor +} //default constructor /// Constructor for double objects. /// The object type is by default AMF::AMF3_DOUBLE, but this can be forced to a different value. /// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic. /// \param val The numeric value of this object. Double AMF3 objects only support double-type values. /// \param setType The object type to force this object to. -AMF::Object3::Object3(std::string indice, double val, AMF::obj3type setType){//num type initializer +AMF::Object3::Object3(std::string indice, double val, AMF::obj3type setType){ //num type initializer myIndice = indice; myType = setType; strval = ""; dblval = val; intval = 0; -}; +} /// Constructor for integer objects. /// The object type is by default AMF::AMF3_INTEGER, but this can be forced to a different value. /// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic. /// \param val The numeric value of this object. Integer AMF3 objects only support integer-type values. /// \param setType The object type to force this object to. -AMF::Object3::Object3(std::string indice, int val, AMF::obj3type setType){//num type initializer -myIndice = indice; -myType = setType; -strval = ""; -dblval = val; -intval = 0; -}; +AMF::Object3::Object3(std::string indice, int val, AMF::obj3type setType){ //num type initializer + myIndice = indice; + myType = setType; + strval = ""; + dblval = val; + intval = 0; +} /// Constructor for string objects. /// The object type is by default AMF::AMF0_STRING, but this can be forced to a different value. @@ -516,25 +648,25 @@ intval = 0; /// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic. /// \param val The string value of this object. /// \param setType The object type to force this object to. -AMF::Object3::Object3(std::string indice, std::string val, AMF::obj3type setType){//str type initializer +AMF::Object3::Object3(std::string indice, std::string val, AMF::obj3type setType){ //str type initializer myIndice = indice; myType = setType; strval = val; dblval = 0; intval = 0; -}; +} /// Constructor for container objects. /// The object type is by default AMF::AMF0_OBJECT, but this can be forced to a different value. /// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic. /// \param setType The object type to force this object to. -AMF::Object3::Object3(std::string indice, AMF::obj3type setType){//object type initializer +AMF::Object3::Object3(std::string indice, AMF::obj3type setType){ //object type initializer myIndice = indice; myType = setType; strval = ""; dblval = 0; intval = 0; -}; +} /// Prints the contents of this object to std::cerr. /// If this object contains other objects, it will call itself recursively @@ -543,28 +675,63 @@ void AMF::Object3::Print(std::string indent){ std::cerr << indent; // print my type switch (myType){ - case AMF::AMF3_UNDEFINED: std::cerr << "Undefined"; break; - case AMF::AMF3_NULL: std::cerr << "Null"; break; - case AMF::AMF3_FALSE: std::cerr << "False"; break; - case AMF::AMF3_TRUE: std::cerr << "True"; break; - case AMF::AMF3_INTEGER: std::cerr << "Integer"; break; - case AMF::AMF3_DOUBLE: std::cerr << "Double"; break; - case AMF::AMF3_STRING: std::cerr << "String"; break; - case AMF::AMF3_XMLDOC: std::cerr << "XML Doc"; break; - case AMF::AMF3_DATE: std::cerr << "Date"; break; - case AMF::AMF3_ARRAY: std::cerr << "Array"; break; - case AMF::AMF3_OBJECT: std::cerr << "Object"; break; - case AMF::AMF3_XML: std::cerr << "XML"; break; - case AMF::AMF3_BYTES: std::cerr << "ByteArray"; break; - case AMF::AMF3_DDV_CONTAINER: std::cerr << "DDVTech Container"; break; + case AMF::AMF3_UNDEFINED: + std::cerr << "Undefined"; + break; + case AMF::AMF3_NULL: + std::cerr << "Null"; + break; + case AMF::AMF3_FALSE: + std::cerr << "False"; + break; + case AMF::AMF3_TRUE: + std::cerr << "True"; + break; + case AMF::AMF3_INTEGER: + std::cerr << "Integer"; + break; + case AMF::AMF3_DOUBLE: + std::cerr << "Double"; + break; + case AMF::AMF3_STRING: + std::cerr << "String"; + break; + case AMF::AMF3_XMLDOC: + std::cerr << "XML Doc"; + break; + case AMF::AMF3_DATE: + std::cerr << "Date"; + break; + case AMF::AMF3_ARRAY: + std::cerr << "Array"; + break; + case AMF::AMF3_OBJECT: + std::cerr << "Object"; + break; + case AMF::AMF3_XML: + std::cerr << "XML"; + break; + case AMF::AMF3_BYTES: + std::cerr << "ByteArray"; + break; + case AMF::AMF3_DDV_CONTAINER: + std::cerr << "DDVTech Container"; + break; } // print my string indice, if available std::cerr << " " << myIndice << " "; // print my numeric or string contents switch (myType){ - case AMF::AMF3_INTEGER: std::cerr << intval; break; - case AMF::AMF3_DOUBLE: std::cerr << dblval; break; - case AMF::AMF3_STRING: case AMF::AMF3_XMLDOC: case AMF::AMF3_XML: case AMF::AMF3_BYTES: + case AMF::AMF3_INTEGER: + std::cerr << intval; + break; + case AMF::AMF3_DOUBLE: + std::cerr << dblval; + break; + case AMF::AMF3_STRING: + case AMF::AMF3_XMLDOC: + case AMF::AMF3_XML: + case AMF::AMF3_BYTES: if (intval > 0){ std::cerr << "REF" << intval; }else{ @@ -578,19 +745,23 @@ void AMF::Object3::Print(std::string indent){ std::cerr << dblval; } break; - case AMF::AMF3_ARRAY: case AMF::AMF3_OBJECT: + case AMF::AMF3_ARRAY: + case AMF::AMF3_OBJECT: if (intval > 0){ std::cerr << "REF" << intval; } break; - default: break;//we don't care about the rest, and don't want a compiler warning... + default: + break; //we don't care about the rest, and don't want a compiler warning... } std::cerr << std::endl; // if I hold other objects, print those too, recursively. if (contents.size() > 0){ - for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){it->Print(indent+" ");} + for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){ + it->Print(indent + " "); + } } -};//print +} //print /// Packs the AMF object to a std::string for transfer over the network. /// If the object is a container type, this function will call itself recursively and contain all contents. @@ -598,7 +769,7 @@ void AMF::Object3::Print(std::string indent){ std::string AMF::Object3::Pack(){ std::string r = ""; return r; -};//pack +} //pack /// Parses a single AMF3 type - used recursively by the AMF::parse3() functions. /// This function updates i every call with the new position in the data. @@ -612,364 +783,370 @@ AMF::Object3 AMF::parseOne3(const unsigned char *& data, unsigned int &len, unsi unsigned int tmpi = 0; unsigned int arrsize = 0; unsigned char tmpdbl[8]; - double *d;// hack to work around strict aliasing - #if DEBUG >= 10 + double *d; // hack to work around strict aliasing +#if DEBUG >= 10 fprintf(stderr, "Note: AMF3 type %hhx found. %i bytes left\n", data[i], len-i); - #endif +#endif switch (data[i]){ case AMF::AMF3_UNDEFINED: case AMF::AMF3_NULL: case AMF::AMF3_FALSE: case AMF::AMF3_TRUE: ++i; - return AMF::Object3(name, (AMF::obj3type)data[i-1]); + return AMF::Object3(name, (AMF::obj3type)data[i - 1]); break; case AMF::AMF3_INTEGER: - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 3;//fix sign bit + tmpi = (tmpi << 3) >> 3; //fix sign bit return AMF::Object3(name, (int)tmpi, AMF::AMF3_INTEGER); break; case AMF::AMF3_DOUBLE: - tmpdbl[7] = data[i+1]; - tmpdbl[6] = data[i+2]; - tmpdbl[5] = data[i+3]; - tmpdbl[4] = data[i+4]; - tmpdbl[3] = data[i+5]; - tmpdbl[2] = data[i+6]; - tmpdbl[1] = data[i+7]; - tmpdbl[0] = data[i+8]; - i+=9;//skip 8(a double)+1 forwards + tmpdbl[7] = data[i + 1]; + tmpdbl[6] = data[i + 2]; + tmpdbl[5] = data[i + 3]; + tmpdbl[4] = data[i + 4]; + tmpdbl[3] = data[i + 5]; + tmpdbl[2] = data[i + 6]; + tmpdbl[1] = data[i + 7]; + tmpdbl[0] = data[i + 8]; + i += 9; //skip 8(a double)+1 forwards d = (double*)tmpdbl; return AMF::Object3(name, *d, AMF::AMF3_DOUBLE); break; case AMF::AMF3_STRING: - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 3;//fix sign bit + tmpi = (tmpi << 3) >> 3; //fix sign bit if ((tmpi & 1) == 0){ - return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_STRING);//reference type + return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_STRING); //reference type } - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char *)data+i, (size_t)(tmpi >> 1));//add the string data - i += (tmpi >> 1);//skip length+size+1 forwards - return AMF::Object3(name, tmpstr, AMF::AMF3_STRING);//normal type + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char *)data + i, (size_t)(tmpi >> 1)); //add the string data + i += (tmpi >> 1); //skip length+size+1 forwards + return AMF::Object3(name, tmpstr, AMF::AMF3_STRING); //normal type break; case AMF::AMF3_XMLDOC: - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 3;//fix sign bit + tmpi = (tmpi << 3) >> 3; //fix sign bit if ((tmpi & 1) == 0){ - return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_XMLDOC);//reference type + return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_XMLDOC); //reference type } - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char *)data+i, (size_t)(tmpi >> 1));//add the string data - i += (tmpi >> 1);//skip length+size+1 forwards - return AMF::Object3(name, tmpstr, AMF::AMF3_XMLDOC);//normal type + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char *)data + i, (size_t)(tmpi >> 1)); //add the string data + i += (tmpi >> 1); //skip length+size+1 forwards + return AMF::Object3(name, tmpstr, AMF::AMF3_XMLDOC); //normal type break; case AMF::AMF3_XML: - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 3;//fix sign bit + tmpi = (tmpi << 3) >> 3; //fix sign bit if ((tmpi & 1) == 0){ - return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_XML);//reference type + return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_XML); //reference type } - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char *)data+i, (size_t)(tmpi >> 1));//add the string data - i += (tmpi >> 1);//skip length+size+1 forwards - return AMF::Object3(name, tmpstr, AMF::AMF3_XML);//normal type + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char *)data + i, (size_t)(tmpi >> 1)); //add the string data + i += (tmpi >> 1); //skip length+size+1 forwards + return AMF::Object3(name, tmpstr, AMF::AMF3_XML); //normal type break; case AMF::AMF3_BYTES: - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - tmpi = (tmpi << 3) >> 3;//fix sign bit - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + tmpi = (tmpi << 3) >> 3; //fix sign bit + i += 5; } } } if ((tmpi & 1) == 0){ - return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_BYTES);//reference type + return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_BYTES); //reference type } - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char *)data+i, (size_t)(tmpi >> 1));//add the string data - i += (tmpi >> 1);//skip length+size+1 forwards - return AMF::Object3(name, tmpstr, AMF::AMF3_BYTES);//normal type + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char *)data + i, (size_t)(tmpi >> 1)); //add the string data + i += (tmpi >> 1); //skip length+size+1 forwards + return AMF::Object3(name, tmpstr, AMF::AMF3_BYTES); //normal type break; case AMF::AMF3_DATE: - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 3;//fix sign bit + tmpi = (tmpi << 3) >> 3; //fix sign bit if ((tmpi & 1) == 0){ - return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_DATE);//reference type + return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_DATE); //reference type } tmpdbl[7] = data[i]; - tmpdbl[6] = data[i+1]; - tmpdbl[5] = data[i+2]; - tmpdbl[4] = data[i+3]; - tmpdbl[3] = data[i+4]; - tmpdbl[2] = data[i+5]; - tmpdbl[1] = data[i+6]; - tmpdbl[0] = data[i+7]; + tmpdbl[6] = data[i + 1]; + tmpdbl[5] = data[i + 2]; + tmpdbl[4] = data[i + 3]; + tmpdbl[3] = data[i + 4]; + tmpdbl[2] = data[i + 5]; + tmpdbl[1] = data[i + 6]; + tmpdbl[0] = data[i + 7]; d = (double*)tmpdbl; - i += 8;//skip a double forwards + i += 8; //skip a double forwards return AMF::Object3(name, *d, AMF::AMF3_DATE); break; - case AMF::AMF3_ARRAY:{ - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + case AMF::AMF3_ARRAY: { + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 3;//fix sign bit + tmpi = (tmpi << 3) >> 3; //fix sign bit if ((tmpi & 1) == 0){ - return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_ARRAY);//reference type + return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_ARRAY); //reference type } AMF::Object3 ret(name, AMF::AMF3_ARRAY); arrsize = tmpi >> 1; do{ - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 4;//fix sign bit, ignore references for now... + tmpi = (tmpi << 3) >> 4; //fix sign bit, ignore references for now... /// \todo Fix references? if (tmpi > 0){ - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char*)data+i, (size_t)tmpi);//add the string data - ret.addContent(AMF::parseOne3(data, len, i, tmpstr));//add content, recursively parsed, updating i + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char*)data + i, (size_t)tmpi); //add the string data + ret.addContent(AMF::parseOne3(data, len, i, tmpstr)); //add content, recursively parsed, updating i } - }while(tmpi > 0); - while (arrsize > 0){//while not done parsing array - ret.addContent(AMF::parseOne3(data, len, i, "arrVal"));//add content, recursively parsed, updating i + }while (tmpi > 0); + while (arrsize > 0){ //while not done parsing array + ret.addContent(AMF::parseOne3(data, len, i, "arrVal")); //add content, recursively parsed, updating i --arrsize; } return ret; - } break; - case AMF::AMF3_OBJECT:{ - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + } + break; + case AMF::AMF3_OBJECT: { + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 3;//fix sign bit + tmpi = (tmpi << 3) >> 3; //fix sign bit if ((tmpi & 1) == 0){ - return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_OBJECT);//reference type + return AMF::Object3(name, (int)((tmpi >> 1) + 1), AMF::AMF3_OBJECT); //reference type } AMF::Object3 ret(name, AMF::AMF3_OBJECT); bool isdynamic = false; - if ((tmpi & 2) == 0){//traits by reference, skip for now + if ((tmpi & 2) == 0){ //traits by reference, skip for now /// \todo Implement traits by reference. Or references in general, of course... }else{ isdynamic = ((tmpi & 8) == 8); - arrsize = tmpi >> 4;//count of sealed members + arrsize = tmpi >> 4; //count of sealed members /// \todo Read in arrsize sealed member names, then arrsize sealed members. } if (isdynamic){ do{ - if (data[i+1] < 0x80){ - tmpi = data[i+1]; - i+=2; + if (data[i + 1] < 0x80){ + tmpi = data[i + 1]; + i += 2; }else{ - tmpi = (data[i+1] & 0x7F) << 7;//strip the upper bit, shift 7 up. - if (data[i+2] < 0x80){ - tmpi |= data[i+2]; - i+=3; + tmpi = (data[i + 1] & 0x7F) << 7; //strip the upper bit, shift 7 up. + if (data[i + 2] < 0x80){ + tmpi |= data[i + 2]; + i += 3; }else{ - tmpi = (tmpi | (data[i+2] & 0x7F)) << 7;//strip the upper bit, shift 7 up. - if (data[i+3] < 0x80){ - tmpi |= data[i+3]; - i+=4; + tmpi = (tmpi | (data[i + 2] & 0x7F)) << 7; //strip the upper bit, shift 7 up. + if (data[i + 3] < 0x80){ + tmpi |= data[i + 3]; + i += 4; }else{ - tmpi = (tmpi | (data[i+3] & 0x7F)) << 8;//strip the upper bit, shift 7 up. - tmpi |= data[i+4]; - i+=5; + tmpi = (tmpi | (data[i + 3] & 0x7F)) << 8; //strip the upper bit, shift 7 up. + tmpi |= data[i + 4]; + i += 5; } } } - tmpi = (tmpi << 3) >> 4;//fix sign bit, ignore references for now... + tmpi = (tmpi << 3) >> 4; //fix sign bit, ignore references for now... /// \todo Fix references? if (tmpi > 0){ - tmpstr.clear();//clean tmpstr, just to be sure - tmpstr.append((const char*)data+i, (size_t)tmpi);//add the string data - ret.addContent(AMF::parseOne3(data, len, i, tmpstr));//add content, recursively parsed, updating i + tmpstr.clear(); //clean tmpstr, just to be sure + tmpstr.append((const char*)data + i, (size_t)tmpi); //add the string data + ret.addContent(AMF::parseOne3(data, len, i, tmpstr)); //add content, recursively parsed, updating i } - }while(tmpi > 0);//keep reading dynamic values until empty string - }//dynamic types + }while (tmpi > 0); //keep reading dynamic values until empty string + } //dynamic types return ret; - } break; + } + break; } - #if DEBUG >= 2 +#if DEBUG >= 2 fprintf(stderr, "Error: Unimplemented AMF3 type %hhx - returning.\n", data[i]); - #endif +#endif return AMF::Object3("error", AMF::AMF3_DDV_CONTAINER); -}//parseOne +} //parseOne /// Parses a C-string to a valid AMF::Object3. /// This function will find all AMF3 objects in the string and return /// them all packed in a single AMF::AMF3_DDV_CONTAINER AMF::Object3. AMF::Object3 AMF::parse3(const unsigned char * data, unsigned int len){ - AMF::Object3 ret("returned", AMF::AMF3_DDV_CONTAINER);//container type + AMF::Object3 ret("returned", AMF::AMF3_DDV_CONTAINER); //container type unsigned int i = 0, j = 0; while (i < len){ ret.addContent(AMF::parseOne3(data, len, i, "")); - if (i > j){j = i;}else{return ret;} + if (i > j){ + j = i; + }else{ + return ret; + } } return ret; -}//parse +} //parse /// Parses a std::string to a valid AMF::Object3. /// This function will find all AMF3 objects in the string and return /// them all packed in a single AMF::AMF3_DDV_CONTAINER AMF::Object3. AMF::Object3 AMF::parse3(std::string data){ return AMF::parse3((const unsigned char*)data.c_str(), data.size()); -}//parse +} //parse diff --git a/lib/amf.h b/lib/amf.h index 836cfdb2..f797a6ba 100644 --- a/lib/amf.h +++ b/lib/amf.h @@ -4,14 +4,13 @@ #pragma once #include #include -//#include #include /// Holds all AMF parsing and creation related functions and classes. -namespace AMF{ +namespace AMF { /// Enumerates all possible AMF0 types, adding a special DDVTECH container type for ease of use. - enum obj0type { + enum obj0type{ AMF0_NUMBER = 0x00, AMF0_BOOL = 0x01, AMF0_STRING = 0x02, @@ -34,7 +33,7 @@ namespace AMF{ }; /// Enumerates all possible AMF3 types, adding a special DDVTECH container type for ease of use. - enum obj3type { + enum obj3type{ AMF3_UNDEFINED = 0x00, AMF3_NULL = 0x01, AMF3_FALSE = 0x02, @@ -50,10 +49,10 @@ namespace AMF{ AMF3_BYTES = 0x0C, AMF3_DDV_CONTAINER = 0xFF }; - + /// Recursive class that holds AMF0 objects. /// It supports all AMF0 types (defined in AMF::obj0type), adding support for a special DDVTECH container type. - class Object { + class Object{ public: std::string Indice(); obj0type GetType(); @@ -78,7 +77,8 @@ namespace AMF{ std::string strval; ///< Holds this objects string value, if any. double numval; ///< Holds this objects numeric value, if any. std::vector contents; ///< Holds this objects contents, if any (for container types). - };//AMFType + }; + //AMFType /// Parses a C-string to a valid AMF::Object. Object parse(const unsigned char * data, unsigned int len); @@ -89,7 +89,7 @@ namespace AMF{ /// Recursive class that holds AMF3 objects. /// It supports all AMF3 types (defined in AMF::obj3type), adding support for a special DDVTECH container type. - class Object3 { + class Object3{ public: std::string Indice(); obj3type GetType(); @@ -117,13 +117,14 @@ namespace AMF{ double dblval; ///< Holds this objects double value, if any. int intval; ///< Holds this objects int value, if any. std::vector contents; ///< Holds this objects contents, if any (for container types). - };//AMFType - + }; + //AMFType + /// Parses a C-string to a valid AMF::Object3. Object3 parse3(const unsigned char * data, unsigned int len); /// Parses a std::string to a valid AMF::Object3. Object3 parse3(std::string data); /// Parses a single AMF3 type - used recursively by the AMF::parse3() functions. Object3 parseOne3(const unsigned char *& data, unsigned int &len, unsigned int &i, std::string name); - -};//AMF namespace + +} //AMF namespace diff --git a/lib/auth.cpp b/lib/auth.cpp index 13c3e1d3..df649766 100644 --- a/lib/auth.cpp +++ b/lib/auth.cpp @@ -6,35 +6,21 @@ #include "auth.h" #include "base64.h" -namespace Secure{ +namespace Secure { - static unsigned char __gbv2keypub_der[] = { - 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, - 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe5, 0xd7, 0x9c, - 0x7d, 0x73, 0xc6, 0xe6, 0xfb, 0x35, 0x7e, 0xd7, 0x57, 0x99, 0x07, 0xdb, - 0x99, 0x70, 0xc9, 0xd0, 0x3e, 0x53, 0x57, 0x3c, 0x1e, 0x55, 0xda, 0x0f, - 0x69, 0xbf, 0x26, 0x79, 0xc7, 0xb6, 0xdd, 0x8e, 0x83, 0x32, 0x65, 0x74, - 0x0d, 0x74, 0x48, 0x42, 0x49, 0x22, 0x52, 0x58, 0x56, 0xc3, 0xe4, 0x49, - 0x5d, 0xac, 0x6a, 0x94, 0xb1, 0x64, 0x14, 0xbf, 0x4d, 0xd5, 0xd7, 0x3a, - 0xca, 0x5c, 0x1e, 0x6f, 0x42, 0x30, 0xac, 0x29, 0xaa, 0xa0, 0x85, 0xd2, - 0x16, 0xa2, 0x8e, 0x89, 0x12, 0xc4, 0x92, 0x06, 0xea, 0xed, 0x48, 0xf6, - 0xdb, 0xed, 0x4f, 0x62, 0x6c, 0xfa, 0xcf, 0xc2, 0xb9, 0x8d, 0x04, 0xb2, - 0xba, 0x63, 0xc9, 0xcc, 0xee, 0x23, 0x64, 0x46, 0x14, 0x12, 0xc8, 0x38, - 0x67, 0x69, 0x6b, 0xaf, 0xd1, 0x7c, 0xb1, 0xb5, 0x79, 0xe4, 0x4e, 0x3a, - 0xa7, 0xe8, 0x28, 0x89, 0x25, 0xc0, 0xd0, 0xd8, 0xc7, 0xd2, 0x26, 0xaa, - 0xf5, 0xbf, 0x36, 0x55, 0x01, 0x89, 0x58, 0x1f, 0x1e, 0xf5, 0xa5, 0x42, - 0x8f, 0x60, 0x2e, 0xc2, 0xd8, 0x21, 0x0b, 0x6c, 0x8d, 0xbb, 0x72, 0xf2, - 0x19, 0x30, 0xe3, 0x4c, 0x3e, 0x80, 0xe7, 0xf2, 0xe3, 0x89, 0x4f, 0xd4, - 0xee, 0x96, 0x3e, 0x4a, 0x9b, 0xe5, 0x16, 0x01, 0xf1, 0x98, 0xc9, 0x0b, - 0xd6, 0xdf, 0x8a, 0x64, 0x47, 0xc4, 0x44, 0xcc, 0x92, 0x69, 0x28, 0xee, - 0x7d, 0xac, 0xdc, 0x30, 0x56, 0x3a, 0xe7, 0xbc, 0xba, 0x45, 0x16, 0x2c, - 0x4c, 0x46, 0x6b, 0x2b, 0x20, 0xfb, 0x3d, 0x20, 0x35, 0xbb, 0x48, 0x49, - 0x13, 0x65, 0xc9, 0x9a, 0x38, 0x10, 0x84, 0x1a, 0x8c, 0xc9, 0xd7, 0xde, - 0x07, 0x10, 0x5a, 0xfb, 0xb4, 0x95, 0xae, 0x18, 0xf2, 0xe3, 0x15, 0xe8, - 0xad, 0x7e, 0xe5, 0x3c, 0xa8, 0x47, 0x85, 0xd6, 0x1f, 0x54, 0xb5, 0xa3, - 0x79, 0x02, 0x03, 0x01, 0x00, 0x01 - }; ///< The GBv2 public key file. + static unsigned char __gbv2keypub_der[] = {0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe5, 0xd7, 0x9c, 0x7d, 0x73, 0xc6, 0xe6, 0xfb, + 0x35, 0x7e, 0xd7, 0x57, 0x99, 0x07, 0xdb, 0x99, 0x70, 0xc9, 0xd0, 0x3e, 0x53, 0x57, 0x3c, 0x1e, 0x55, 0xda, 0x0f, 0x69, 0xbf, 0x26, 0x79, 0xc7, + 0xb6, 0xdd, 0x8e, 0x83, 0x32, 0x65, 0x74, 0x0d, 0x74, 0x48, 0x42, 0x49, 0x22, 0x52, 0x58, 0x56, 0xc3, 0xe4, 0x49, 0x5d, 0xac, 0x6a, 0x94, 0xb1, + 0x64, 0x14, 0xbf, 0x4d, 0xd5, 0xd7, 0x3a, 0xca, 0x5c, 0x1e, 0x6f, 0x42, 0x30, 0xac, 0x29, 0xaa, 0xa0, 0x85, 0xd2, 0x16, 0xa2, 0x8e, 0x89, 0x12, + 0xc4, 0x92, 0x06, 0xea, 0xed, 0x48, 0xf6, 0xdb, 0xed, 0x4f, 0x62, 0x6c, 0xfa, 0xcf, 0xc2, 0xb9, 0x8d, 0x04, 0xb2, 0xba, 0x63, 0xc9, 0xcc, 0xee, + 0x23, 0x64, 0x46, 0x14, 0x12, 0xc8, 0x38, 0x67, 0x69, 0x6b, 0xaf, 0xd1, 0x7c, 0xb1, 0xb5, 0x79, 0xe4, 0x4e, 0x3a, 0xa7, 0xe8, 0x28, 0x89, 0x25, + 0xc0, 0xd0, 0xd8, 0xc7, 0xd2, 0x26, 0xaa, 0xf5, 0xbf, 0x36, 0x55, 0x01, 0x89, 0x58, 0x1f, 0x1e, 0xf5, 0xa5, 0x42, 0x8f, 0x60, 0x2e, 0xc2, 0xd8, + 0x21, 0x0b, 0x6c, 0x8d, 0xbb, 0x72, 0xf2, 0x19, 0x30, 0xe3, 0x4c, 0x3e, 0x80, 0xe7, 0xf2, 0xe3, 0x89, 0x4f, 0xd4, 0xee, 0x96, 0x3e, 0x4a, 0x9b, + 0xe5, 0x16, 0x01, 0xf1, 0x98, 0xc9, 0x0b, 0xd6, 0xdf, 0x8a, 0x64, 0x47, 0xc4, 0x44, 0xcc, 0x92, 0x69, 0x28, 0xee, 0x7d, 0xac, 0xdc, 0x30, 0x56, + 0x3a, 0xe7, 0xbc, 0xba, 0x45, 0x16, 0x2c, 0x4c, 0x46, 0x6b, 0x2b, 0x20, 0xfb, 0x3d, 0x20, 0x35, 0xbb, 0x48, 0x49, 0x13, 0x65, 0xc9, 0x9a, 0x38, + 0x10, 0x84, 0x1a, 0x8c, 0xc9, 0xd7, 0xde, 0x07, 0x10, 0x5a, 0xfb, 0xb4, 0x95, 0xae, 0x18, 0xf2, 0xe3, 0x15, 0xe8, 0xad, 0x7e, 0xe5, 0x3c, 0xa8, + 0x47, 0x85, 0xd6, 0x1f, 0x54, 0xb5, 0xa3, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01}; ///< The GBv2 public key file. static unsigned int __gbv2keypub_der_len = 294; ///< Length of GBv2 public key data /// Attempts to load the GBv2 public key. diff --git a/lib/auth.h b/lib/auth.h index 9b299232..7024e36f 100644 --- a/lib/auth.h +++ b/lib/auth.h @@ -1,7 +1,7 @@ #pragma once #include -namespace Secure{ +namespace Secure { class Auth{ private: void * pubkey; ///< Holds the public key. diff --git a/lib/base64.cpp b/lib/base64.cpp index a2c9dec3..8a15611f 100644 --- a/lib/base64.cpp +++ b/lib/base64.cpp @@ -3,62 +3,84 @@ /// Needed for base64_encode function const std::string Base64::chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - /// Helper for base64_decode function -inline bool Base64::is_base64(unsigned char c) { +/// Helper for base64_decode function +inline bool Base64::is_base64(unsigned char c){ return (isalnum(c) || (c == '+') || (c == '/')); } /// Used to base64 encode data. Input is the plaintext as std::string, output is the encoded data as std::string. /// \param input Plaintext data to encode. /// \returns Base64 encoded data. -std::string Base64::encode(std::string const input) { +std::string Base64::encode(std::string const input){ std::string ret; unsigned int in_len = input.size(); char quad[4], triple[3]; unsigned int i, x, n = 3; for (x = 0; x < in_len; x = x + 3){ - if ((in_len - x) / 3 == 0){n = (in_len - x) % 3;} - for (i=0; i < 3; i++){triple[i] = '0';} - for (i=0; i < n; i++){triple[i] = input[x + i];} + if ((in_len - x) / 3 == 0){ + n = (in_len - x) % 3; + } + for (i = 0; i < 3; i++){ + triple[i] = '0'; + } + for (i = 0; i < n; i++){ + triple[i] = input[x + i]; + } quad[0] = chars[(triple[0] & 0xFC) >> 2]; // FC = 11111100 quad[1] = chars[((triple[0] & 0x03) << 4) | ((triple[1] & 0xF0) >> 4)]; // 03 = 11 quad[2] = chars[((triple[1] & 0x0F) << 2) | ((triple[2] & 0xC0) >> 6)]; // 0F = 1111, C0=11110 quad[3] = chars[triple[2] & 0x3F]; // 3F = 111111 - if (n < 3){quad[3] = '=';} - if (n < 2){quad[2] = '=';} - for(i=0; i < 4; i++){ret += quad[i];} + if (n < 3){ + quad[3] = '='; + } + if (n < 2){ + quad[2] = '='; + } + for (i = 0; i < 4; i++){ + ret += quad[i]; + } } return ret; -}//base64_encode +} //base64_encode /// Used to base64 decode data. Input is the encoded data as std::string, output is the plaintext data as std::string. /// \param encoded_string Base64 encoded data to decode. /// \returns Plaintext decoded data. -std::string Base64::decode(std::string const& encoded_string) { +std::string Base64::decode(std::string const& encoded_string){ int in_len = encoded_string.size(); int i = 0; int j = 0; int in_ = 0; unsigned char char_array_4[4], char_array_3[3]; std::string ret; - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++){char_array_4[i] = chars.find(char_array_4[i]);} + while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])){ + char_array_4[i++ ] = encoded_string[in_]; + in_++; + if (i == 4){ + for (i = 0; i < 4; i++){ + char_array_4[i] = chars.find(char_array_4[i]); + } char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (i = 0; (i < 3); i++){ret += char_array_3[i];} + for (i = 0; (i < 3); i++){ + ret += char_array_3[i]; + } i = 0; } } - if (i) { - for (j = i; j <4; j++){char_array_4[j] = 0;} - for (j = 0; j <4; j++){char_array_4[j] = chars.find(char_array_4[j]);} + if (i){ + for (j = i; j < 4; j++){ + char_array_4[j] = 0; + } + for (j = 0; j < 4; j++){ + char_array_4[j] = chars.find(char_array_4[j]); + } char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + for (j = 0; (j < i - 1); j++) + ret += char_array_3[j]; } return ret; } diff --git a/lib/config.cpp b/lib/config.cpp index cc9c6928..9a771823 100644 --- a/lib/config.cpp +++ b/lib/config.cpp @@ -56,14 +56,18 @@ Util::Config::Config(std::string cmd, std::string version){ ///\endcode void Util::Config::addOption(std::string optname, JSON::Value option){ vals[optname] = option; - if (!vals[optname].isMember("value") && vals[optname].isMember("default")){ + if ( !vals[optname].isMember("value") && vals[optname].isMember("default")){ vals[optname]["value"].append(vals[optname]["default"]); vals[optname].removeMember("default"); } long_count = 0; for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){ - if (it->second.isMember("long")){long_count++;} - if (it->second.isMember("long_off")){long_count++;} + if (it->second.isMember("long")){ + long_count++; + } + if (it->second.isMember("long_off")){ + long_count++; + } } } @@ -73,16 +77,30 @@ void Util::Config::printHelp(std::ostream & output){ std::map args; for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){ unsigned int current = 0; - if (it->second.isMember("long")){current += it->second["long"].asString().size() + 4;} - if (it->second.isMember("short")){current += it->second["short"].asString().size() + 3;} - if (current > longest){longest = current;} + if (it->second.isMember("long")){ + current += it->second["long"].asString().size() + 4; + } + if (it->second.isMember("short")){ + current += it->second["short"].asString().size() + 3; + } + if (current > longest){ + longest = current; + } current = 0; - if (it->second.isMember("long_off")){current += it->second["long_off"].asString().size() + 4;} - if (it->second.isMember("short_off")){current += it->second["short_off"].asString().size() + 3;} - if (current > longest){longest = current;} + if (it->second.isMember("long_off")){ + current += it->second["long_off"].asString().size() + 4; + } + if (it->second.isMember("short_off")){ + current += it->second["short_off"].asString().size() + 3; + } + if (current > longest){ + longest = current; + } if (it->second.isMember("arg_num")){ current = it->first.size() + 3; - if (current > longest){longest = current;} + if (current > longest){ + longest = current; + } args[it->second["arg_num"].asInt()] = it->first; } } @@ -108,7 +126,9 @@ void Util::Config::printHelp(std::ostream & output){ f = "-" + it->second["short"].asString(); } } - while (f.size() < longest){f.append(" ");} + while (f.size() < longest){ + f.append(" "); + } if (it->second.isMember("arg")){ output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl; }else{ @@ -126,7 +146,9 @@ void Util::Config::printHelp(std::ostream & output){ f = "-" + it->second["short_off"].asString(); } } - while (f.size() < longest){f.append(" ");} + while (f.size() < longest){ + f.append(" "); + } if (it->second.isMember("arg")){ output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl; }else{ @@ -135,40 +157,49 @@ void Util::Config::printHelp(std::ostream & output){ } if (it->second.isMember("arg_num")){ f = it->first; - while (f.size() < longest){f.append(" ");} + while (f.size() < longest){ + f.append(" "); + } output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl; } } } - /// Parses commandline arguments. /// Calls exit if an unknown option is encountered, printing a help message. void Util::Config::parseArgs(int argc, char ** argv){ int opt = 0; std::string shortopts; - struct option * longOpts = (struct option*)calloc(long_count+1, sizeof(struct option)); + struct option * longOpts = (struct option*)calloc(long_count + 1, sizeof(struct option)); int long_i = 0; int arg_count = 0; for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){ if (it->second.isMember("short")){ shortopts += it->second["short"].asString(); - if (it->second.isMember("arg")){shortopts += ":";} + if (it->second.isMember("arg")){ + shortopts += ":"; + } } if (it->second.isMember("short_off")){ shortopts += it->second["short_off"].asString(); - if (it->second.isMember("arg")){shortopts += ":";} + if (it->second.isMember("arg")){ + shortopts += ":"; + } } if (it->second.isMember("long")){ longOpts[long_i].name = it->second["long"].asString().c_str(); longOpts[long_i].val = it->second["short"].asString()[0]; - if (it->second.isMember("arg")){longOpts[long_i].has_arg = 1;} + if (it->second.isMember("arg")){ + longOpts[long_i].has_arg = 1; + } long_i++; } if (it->second.isMember("long_off")){ longOpts[long_i].name = it->second["long_off"].asString().c_str(); longOpts[long_i].val = it->second["short_off"].asString()[0]; - if (it->second.isMember("arg")){longOpts[long_i].has_arg = 1;} + if (it->second.isMember("arg")){ + longOpts[long_i].has_arg = 1; + } long_i++; } if (it->second.isMember("arg_num") && !(it->second.isMember("value") && it->second["value"].size())){ @@ -203,10 +234,10 @@ void Util::Config::parseArgs(int argc, char ** argv){ } break; } - }//commandline options parser - free(longOpts);//free the long options array - long_i = 1;//re-use long_i as an argument counter - while (optind < argc){//parse all remaining options, ignoring anything unexpected. + } //commandline options parser + free(longOpts); //free the long options array + long_i = 1; //re-use long_i as an argument counter + while (optind < argc){ //parse all remaining options, ignoring anything unexpected. for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){ if (it->second.isMember("arg_num") && it->second["arg_num"].asInt() == long_i){ it->second["value"].append((std::string)argv[optind]); @@ -226,18 +257,18 @@ void Util::Config::parseArgs(int argc, char ** argv){ /// Returns a reference to the current value of an option or default if none was set. /// If the option does not exist, this exits the application with a return code of 37. JSON::Value & Util::Config::getOption(std::string optname, bool asArray){ - if (!vals.isMember(optname)){ + if ( !vals.isMember(optname)){ std::cout << "Fatal error: a non-existent option '" << optname << "' was accessed." << std::endl; exit(37); } - if (!vals[optname].isMember("value") || !vals[optname]["value"].isArray()){ + if ( !vals[optname].isMember("value") || !vals[optname]["value"].isArray()){ vals[optname]["value"].append(JSON::Value()); } if (asArray){ return vals[optname]["value"]; }else{ int n = vals[optname]["value"].size(); - return vals[optname]["value"][n-1]; + return vals[optname]["value"][n - 1]; } } @@ -273,7 +304,7 @@ void Util::Config::activate(){ } struct sigaction new_action; new_action.sa_handler = signal_handler; - sigemptyset (&new_action.sa_mask); + sigemptyset( &new_action.sa_mask); new_action.sa_flags = 0; sigaction(SIGINT, &new_action, NULL); sigaction(SIGHUP, &new_action, NULL); @@ -288,41 +319,53 @@ void Util::Config::activate(){ /// signal, and ignores all other signals. void Util::Config::signal_handler(int signum){ switch (signum){ - case SIGINT://these three signals will set is_active to false. + case SIGINT: //these three signals will set is_active to false. case SIGHUP: case SIGTERM: is_active = false; break; - case SIGCHLD://when a child dies, reap it. + case SIGCHLD: //when a child dies, reap it. wait(0); break; default: //other signals are ignored break; } -}//signal_handler +} //signal_handler /// Adds the default connector options to this Util::Config object. void Util::Config::addConnectorOptions(int port){ JSON::Value stored_port = JSON::fromString("{\"long\":\"port\", \"short\":\"p\", \"arg\":\"integer\", \"help\":\"TCP port to listen on.\"}"); stored_port["value"].append((long long int)port); addOption("listen_port", stored_port); - addOption("listen_interface", JSON::fromString("{\"long\":\"interface\", \"value\":[\"0.0.0.0\"], \"short\":\"i\", \"arg\":\"string\", \"help\":\"Interface address to listen on, or 0.0.0.0 for all available interfaces.\"}")); - addOption("username", JSON::fromString("{\"long\":\"username\", \"value\":[\"root\"], \"short\":\"u\", \"arg\":\"string\", \"help\":\"Username to drop privileges to, or root to not drop provileges.\"}")); - addOption("daemonize", JSON::fromString("{\"long\":\"daemon\", \"short\":\"d\", \"value\":[1], \"long_off\":\"nodaemon\", \"short_off\":\"n\", \"help\":\"Whether or not to daemonize the process after starting.\"}")); -}//addConnectorOptions + addOption("listen_interface", + JSON::fromString( + "{\"long\":\"interface\", \"value\":[\"0.0.0.0\"], \"short\":\"i\", \"arg\":\"string\", \"help\":\"Interface address to listen on, or 0.0.0.0 for all available interfaces.\"}")); + addOption("username", + JSON::fromString( + "{\"long\":\"username\", \"value\":[\"root\"], \"short\":\"u\", \"arg\":\"string\", \"help\":\"Username to drop privileges to, or root to not drop provileges.\"}")); + addOption("daemonize", + JSON::fromString( + "{\"long\":\"daemon\", \"short\":\"d\", \"value\":[1], \"long_off\":\"nodaemon\", \"short_off\":\"n\", \"help\":\"Whether or not to daemonize the process after starting.\"}")); +} //addConnectorOptions /// Gets directory the current executable is stored in. std::string Util::getMyPath(){ char mypath[500]; int ret = readlink("/proc/self/exe", mypath, 500); - if (ret != -1){mypath[ret] = 0;}else{mypath[0] = 0;} + if (ret != -1){ + mypath[ret] = 0; + }else{ + mypath[0] = 0; + } std::string tPath = mypath; size_t slash = tPath.rfind('/'); if (slash == std::string::npos){ slash = tPath.rfind('\\'); - if (slash == std::string::npos){return "";} + if (slash == std::string::npos){ + return ""; + } } - tPath.resize(slash+1); + tPath.resize(slash + 1); return tPath; } @@ -330,20 +373,20 @@ std::string Util::getMyPath(){ void Util::setUser(std::string username){ if (username != "root"){ struct passwd * user_info = getpwnam(username.c_str()); - if (!user_info){ - #if DEBUG >= 1 + if ( !user_info){ +#if DEBUG >= 1 fprintf(stderr, "Error: could not setuid %s: could not get PID\n", username.c_str()); - #endif +#endif return; }else{ if (setuid(user_info->pw_uid) != 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Error: could not setuid %s: not allowed\n", username.c_str()); - #endif +#endif }else{ - #if DEBUG >= 3 +#if DEBUG >= 3 fprintf(stderr, "Changed user to %s\n", username.c_str()); - #endif +#endif } } } @@ -354,12 +397,12 @@ void Util::setUser(std::string username){ /// Does not change directory to root. /// Does redirect output to /dev/null void Util::Daemonize(){ - #if DEBUG >= 3 +#if DEBUG >= 3 fprintf(stderr, "Going into background mode...\n"); - #endif - if (daemon(1, 0) < 0) { - #if DEBUG >= 1 +#endif + if (daemon(1, 0) < 0){ +#if DEBUG >= 1 fprintf(stderr, "Failed to daemonize: %s\n", strerror(errno)); - #endif +#endif } } diff --git a/lib/config.h b/lib/config.h index 7e91a4b6..c776c21b 100644 --- a/lib/config.h +++ b/lib/config.h @@ -2,11 +2,16 @@ /// Contains generic function headers for managing configuration. #pragma once + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + #include #include "json.h" /// Contains utility code, not directly related to streaming media -namespace Util{ +namespace Util { /// Deals with parsing configuration from commandline options. class Config{ @@ -40,4 +45,5 @@ namespace Util{ /// Will turn the current process into a daemon. void Daemonize(); -}; +} +; diff --git a/lib/crypto.cpp b/lib/crypto.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/crypto.h b/lib/crypto.h deleted file mode 100644 index 2187c9d4..00000000 --- a/lib/crypto.h +++ /dev/null @@ -1,25 +0,0 @@ -/// \file crypto.h -/// Holds all headers needed for RTMP cryptography functions. - -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut); - -void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult); - - -extern uint8_t genuineFMSKey[]; - -bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme); diff --git a/lib/dtsc.cpp b/lib/dtsc.cpp index 7ee542e2..1742e493 100644 --- a/lib/dtsc.cpp +++ b/lib/dtsc.cpp @@ -5,12 +5,12 @@ #include #include //for memcmp #include //for htonl/ntohl - char DTSC::Magic_Header[] = "DTSC"; char DTSC::Magic_Packet[] = "DTPD"; /// Initializes a DTSC::Stream with only one packet buffer. DTSC::Stream::Stream(){ + datapointertype = DTSC::INVALID; datapointer = 0; buffercount = 1; } @@ -18,8 +18,11 @@ DTSC::Stream::Stream(){ /// Initializes a DTSC::Stream with a minimum of rbuffers packet buffers. /// The actual buffer count may not at all times be the requested amount. DTSC::Stream::Stream(unsigned int rbuffers){ + datapointertype = DTSC::INVALID; datapointer = 0; - if (rbuffers < 1){rbuffers = 1;} + if (rbuffers < 1){ + rbuffers = 1; + } buffercount = rbuffers; } @@ -39,15 +42,19 @@ bool DTSC::Stream::parsePacket(std::string & buffer){ if (buffer.length() > 8){ if (memcmp(buffer.c_str(), DTSC::Magic_Header, 4) == 0){ len = ntohl(((uint32_t *)buffer.c_str())[1]); - if (buffer.length() < len+8){return false;} + if (buffer.length() < len + 8){ + return false; + } unsigned int i = 0; metadata = JSON::fromDTMI((unsigned char*)buffer.c_str() + 8, len, i); - buffer.erase(0, len+8); + buffer.erase(0, len + 8); return false; } if (memcmp(buffer.c_str(), DTSC::Magic_Packet, 4) == 0){ len = ntohl(((uint32_t *)buffer.c_str())[1]); - if (buffer.length() < len+8){return false;} + if (buffer.length() < len + 8){ + return false; + } buffers.push_front(JSON::Value()); unsigned int i = 0; buffers.front() = JSON::fromDTMI((unsigned char*)buffer.c_str() + 8, len, i); @@ -59,23 +66,33 @@ bool DTSC::Stream::parsePacket(std::string & buffer){ } if (buffers.front().isMember("datatype")){ std::string tmp = buffers.front()["datatype"].asString(); - if (tmp == "video"){datapointertype = VIDEO;} - if (tmp == "audio"){datapointertype = AUDIO;} - if (tmp == "meta"){datapointertype = META;} - if (tmp == "pause_marker"){datapointertype = PAUSEMARK;} + if (tmp == "video"){ + datapointertype = VIDEO; + } + if (tmp == "audio"){ + datapointertype = AUDIO; + } + if (tmp == "meta"){ + datapointertype = META; + } + if (tmp == "pause_marker"){ + datapointertype = PAUSEMARK; + } + } + buffer.erase(0, len + 8); + while (buffers.size() > buffercount){ + buffers.pop_back(); } - buffer.erase(0, len+8); - while (buffers.size() > buffercount){buffers.pop_back();} advanceRings(); syncing = false; return true; } - #if DEBUG >= 2 +#if DEBUG >= 2 if (!syncing){ std::cerr << "Error: Invalid DTMI data detected - re-syncing" << std::endl; syncing = true; } - #endif +#endif size_t magic_search = buffer.find(Magic_Packet); if (magic_search == std::string::npos){ buffer.clear(); @@ -97,18 +114,22 @@ bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){ std::string header_bytes = buffer.copy(8); if (memcmp(header_bytes.c_str(), DTSC::Magic_Header, 4) == 0){ len = ntohl(((uint32_t *)header_bytes.c_str())[1]); - if (!buffer.available(len+8)){return false;} + if ( !buffer.available(len + 8)){ + return false; + } unsigned int i = 0; - std::string wholepacket = buffer.remove(len+8); + std::string wholepacket = buffer.remove(len + 8); metadata = JSON::fromDTMI((unsigned char*)wholepacket.c_str() + 8, len, i); return false; } if (memcmp(header_bytes.c_str(), DTSC::Magic_Packet, 4) == 0){ len = ntohl(((uint32_t *)header_bytes.c_str())[1]); - if (!buffer.available(len+8)){return false;} + if ( !buffer.available(len + 8)){ + return false; + } buffers.push_front(JSON::Value()); unsigned int i = 0; - std::string wholepacket = buffer.remove(len+8); + std::string wholepacket = buffer.remove(len + 8); buffers.front() = JSON::fromDTMI((unsigned char*)wholepacket.c_str() + 8, len, i); datapointertype = INVALID; if (buffers.front().isMember("data")){ @@ -118,22 +139,32 @@ bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){ } if (buffers.front().isMember("datatype")){ std::string tmp = buffers.front()["datatype"].asString(); - if (tmp == "video"){datapointertype = VIDEO;} - if (tmp == "audio"){datapointertype = AUDIO;} - if (tmp == "meta"){datapointertype = META;} - if (tmp == "pause_marker"){datapointertype = PAUSEMARK;} + if (tmp == "video"){ + datapointertype = VIDEO; + } + if (tmp == "audio"){ + datapointertype = AUDIO; + } + if (tmp == "meta"){ + datapointertype = META; + } + if (tmp == "pause_marker"){ + datapointertype = PAUSEMARK; + } + } + while (buffers.size() > buffercount){ + buffers.pop_back(); } - while (buffers.size() > buffercount){buffers.pop_back();} advanceRings(); syncing = false; return true; } - #if DEBUG >= 2 +#if DEBUG >= 2 if (!syncing){ std::cerr << "Error: Invalid DTMI data detected - syncing" << std::endl; syncing = true; } - #endif +#endif buffer.get().clear(); } return false; @@ -185,19 +216,30 @@ void DTSC::Stream::advanceRings(){ std::deque::iterator dit; std::set::iterator sit; for (sit = rings.begin(); sit != rings.end(); sit++){ - (*sit)->b++; - if ((*sit)->waiting){(*sit)->waiting = false; (*sit)->b = 0;} - if ((*sit)->starved || ((*sit)->b >= buffers.size())){(*sit)->starved = true; (*sit)->b = 0;} + ( *sit)->b++; + if (( *sit)->waiting){ + ( *sit)->waiting = false; + ( *sit)->b = 0; + } + if (( *sit)->starved || (( *sit)->b >= buffers.size())){ + ( *sit)->starved = true; + ( *sit)->b = 0; + } } for (dit = keyframes.begin(); dit != keyframes.end(); dit++){ dit->b++; - if (dit->b >= buffers.size()){keyframes.erase(dit); break;} + if (dit->b >= buffers.size()){ + keyframes.erase(dit); + break; + } } if ((lastType() == VIDEO) && (buffers.front().isMember("keyframe"))){ keyframes.push_front(DTSC::Ring(0)); } //increase buffer size if no keyframes available - if ((buffercount > 1) && (keyframes.size() < 1)){buffercount++;} + if ((buffercount > 1) && (keyframes.size() < 1)){ + buffercount++; + } } /// Constructs a new Ring, at the given buffer position. @@ -235,7 +277,9 @@ void DTSC::Stream::dropRing(DTSC::Ring * ptr){ /// Drops all Ring classes that have been given out. DTSC::Stream::~Stream(){ std::set::iterator sit; - for (sit = rings.begin(); sit != rings.end(); sit++){delete (*sit);} + for (sit = rings.begin(); sit != rings.end(); sit++){ + delete ( *sit); + } } /// Open a filename for DTSC reading/writing. @@ -247,12 +291,12 @@ DTSC::File::File(std::string filename, bool create){ fseek(F, 0, SEEK_SET); fwrite(DTSC::Magic_Header, 4, 1, F); memset(buffer, 0, 4); - fwrite(buffer, 4, 1, F);//write 4 zero-bytes + fwrite(buffer, 4, 1, F); //write 4 zero-bytes headerSize = 0; }else{ F = fopen(filename.c_str(), "r+b"); } - if (!F){ + if ( !F){ fprintf(stderr, "Could not open file %s\n", filename.c_str()); return; } @@ -262,15 +306,15 @@ DTSC::File::File(std::string filename, bool create){ 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 + fwrite(buffer, 4, 1, F); //write 4 zero-bytes }else{ uint32_t * ubuffer = (uint32_t *)buffer; headerSize = ntohl(ubuffer[0]); } readHeader(0); - fseek(F, 8+headerSize, SEEK_SET); + fseek(F, 8 + headerSize, SEEK_SET); currframe = 1; - frames[1] = 8+headerSize; + frames[1] = 8 + headerSize; msframes[1] = 0; } @@ -289,7 +333,7 @@ bool DTSC::File::writeHeader(std::string & header, bool force){ headerSize = header.size(); fseek(F, 8, SEEK_SET); int ret = fwrite(header.c_str(), headerSize, 1, F); - fseek(F, 8+headerSize, SEEK_SET); + fseek(F, 8 + headerSize, SEEK_SET); return (ret == 1); } @@ -299,13 +343,19 @@ long long int DTSC::File::addHeader(std::string & header){ fseek(F, 0, SEEK_END); long long int writePos = ftell(F); int hSize = htonl(header.size()); - int ret = fwrite(DTSC::Magic_Header, 4, 1, F);//write header - if (ret != 1){return 0;} - ret = fwrite((void*)(&hSize), 4, 1, F);//write size - if (ret != 1){return 0;} - ret = fwrite(header.c_str(), header.size(), 1, F);//write contents - if (ret != 1){return 0;} - return writePos;//return position written at + int ret = fwrite(DTSC::Magic_Header, 4, 1, F); //write header + if (ret != 1){ + return 0; + } + ret = fwrite((void*)( &hSize), 4, 1, F); //write size + if (ret != 1){ + return 0; + } + ret = fwrite(header.c_str(), header.size(), 1, F); //write contents + if (ret != 1){ + return 0; + } + return writePos; //return position written at } /// Reads the header at the given file position. @@ -315,9 +365,9 @@ void DTSC::File::readHeader(int pos){ fseek(F, pos, SEEK_SET); if (fread(buffer, 4, 1, F) != 1){ if (feof(F)){ - #if DEBUG >= 4 +#if DEBUG >= 4 fprintf(stderr, "End of file reached (H%i)\n", pos); - #endif +#endif }else{ fprintf(stderr, "Could not read header (H%i)\n", pos); } @@ -355,13 +405,13 @@ void DTSC::File::readHeader(int pos){ if (metadata.isMember("keytime")){ msframes.clear(); for (int i = 0; i < metadata["keytime"].size(); ++i){ - msframes[i+1] = metadata["keytime"][i].asInt(); + msframes[i + 1] = metadata["keytime"][i].asInt(); } } if (metadata.isMember("keybpos")){ frames.clear(); for (int i = 0; i < metadata["keybpos"].size(); ++i){ - frames[i+1] = metadata["keybpos"][i].asInt(); + frames[i + 1] = metadata["keybpos"][i].asInt(); } } } @@ -373,9 +423,9 @@ void DTSC::File::seekNext(){ lastreadpos = ftell(F); if (fread(buffer, 4, 1, F) != 1){ if (feof(F)){ - #if DEBUG >= 4 +#if DEBUG >= 4 fprintf(stderr, "End of file reached.\n"); - #endif +#endif }else{ fprintf(stderr, "Could not read header\n"); } @@ -409,13 +459,13 @@ void DTSC::File::seekNext(){ if (frames[currframe] != lastreadpos){ currframe++; currtime = jsonbuffer["time"].asInt(); - #if DEBUG >= 6 +#if DEBUG >= 6 if (frames[currframe] != lastreadpos){ std::cerr << "Found a new frame " << currframe << " @ " << lastreadpos << "b/" << currtime << "ms" << std::endl; - }else{ + } else{ std::cerr << "Passing frame " << currframe << " @ " << lastreadpos << "b/" << currtime << "ms" << std::endl; } - #endif +#endif frames[currframe] = lastreadpos; msframes[currframe] = currtime; } @@ -423,36 +473,47 @@ void DTSC::File::seekNext(){ } /// Returns the byte positon of the start of the last packet that was read. -long long int DTSC::File::getLastReadPos(){return lastreadpos;} +long long int DTSC::File::getLastReadPos(){ + return lastreadpos; +} /// Returns the internal buffer of the last read packet in raw binary format. -std::string & DTSC::File::getPacket(){return strbuffer;} +std::string & DTSC::File::getPacket(){ + return strbuffer; +} /// Returns the internal buffer of the last read packet in JSON format. -JSON::Value & DTSC::File::getJSON(){return jsonbuffer;} +JSON::Value & DTSC::File::getJSON(){ + return jsonbuffer; +} /// Attempts to seek to the given frame number within the file. /// Returns true if successful, false otherwise. bool DTSC::File::seek_frame(int frameno){ if (frames.count(frameno) > 0){ if (fseek(F, frames[frameno], SEEK_SET) == 0){ - #if DEBUG >= 4 +#if DEBUG >= 4 std::cerr << "Seek direct from " << currframe << " @ " << frames[currframe] << " to " << frameno << " @ " << frames[frameno] << std::endl; - #endif +#endif currframe = frameno; return true; } }else{ for (int i = frameno; i >= 1; --i){ - if (frames.count(i) > 0){currframe = i; break;} + if (frames.count(i) > 0){ + currframe = i; + break; + } } if (fseek(F, frames[currframe], SEEK_SET) == 0){ - #if DEBUG >= 4 +#if DEBUG >= 4 std::cerr << "Seeking from frame " << currframe << " @ " << frames[currframe] << " to " << frameno << std::endl; - #endif +#endif while (currframe < frameno){ seekNext(); - if (jsonbuffer.isNull()){return false;} + if (jsonbuffer.isNull()){ + return false; + } } seek_frame(frameno); return true; @@ -468,16 +529,23 @@ bool DTSC::File::seek_time(int ms){ currtime = 0; currframe = 1; for (it = msframes.begin(); it != msframes.end(); ++it){ - if (it->second > ms){break;} - if (it->second > currtime){currtime = it->second; currframe = it->first;} + if (it->second > ms){ + break; + } + if (it->second > currtime){ + currtime = it->second; + currframe = it->first; + } } if (fseek(F, frames[currframe], SEEK_SET) == 0){ - #if DEBUG >= 4 +#if DEBUG >= 4 std::cerr << "Seeking from frame " << currframe << " @ " << msframes[currframe] << "ms to " << ms << "ms" << std::endl; - #endif +#endif while (currtime < ms){ seekNext(); - if (jsonbuffer.isNull()){return false;} + if (jsonbuffer.isNull()){ + return false; + } } if (currtime > ms){ return seek_frame(currframe - 1); diff --git a/lib/dtsc.h b/lib/dtsc.h index 1bced5d1..f3dd687d 100644 --- a/lib/dtsc.h +++ b/lib/dtsc.h @@ -12,8 +12,6 @@ #include "json.h" #include "socket.h" - - /// Holds all DDVTECH Stream Container classes and parsers. ///length (int, length in seconds, if available) ///video: @@ -50,10 +48,10 @@ /// - nalu (int, if set, is a nalu) /// - nalu_end (int, if set, is a end-of-sequence) /// - offset (int, unsigned version of signed int! Holds the ms offset between timestamp and proper display time for B-frames) -namespace DTSC{ +namespace DTSC { /// This enum holds all possible datatypes for DTSC packets. - enum datatype { + enum datatype{ AUDIO, ///< Stream Audio data VIDEO, ///< Stream Video data META, ///< Stream Metadata @@ -91,12 +89,12 @@ namespace DTSC{ FILE * F; unsigned long headerSize; char buffer[4]; - };//FileWriter - + }; + //FileWriter /// A part from the DTSC::Stream ringbuffer. /// Holds information about a buffer that will stay consistent - class Ring { + class Ring{ public: Ring(unsigned int v); volatile unsigned int b; ///< Holds current number of buffer. May and is intended to change unexpectedly! @@ -107,7 +105,7 @@ namespace DTSC{ /// Holds temporary data for a DTSC stream and provides functions to utilize it. /// Optionally also acts as a ring buffer of a certain requested size. /// If ring buffering mode is enabled, it will automatically grow in size to always contain at least one keyframe. - class Stream { + class Stream{ public: Stream(); ~Stream(); @@ -125,7 +123,7 @@ namespace DTSC{ Ring * getRing(); unsigned int getTime(); void dropRing(Ring * ptr); - private: + private: std::deque buffers; std::set rings; std::deque keyframes; @@ -134,4 +132,4 @@ namespace DTSC{ datatype datapointertype; unsigned int buffercount; }; -}; +} diff --git a/lib/filesystem.cpp b/lib/filesystem.cpp index 06f5cbb7..791d529a 100644 --- a/lib/filesystem.cpp +++ b/lib/filesystem.cpp @@ -1,215 +1,265 @@ #include "filesystem.h" - -Filesystem::Directory::Directory( std::string PathName, std::string BasePath ) { +Filesystem::Directory::Directory(std::string PathName, std::string BasePath){ MyBase = BasePath; - if( PathName[0] == '/' ) { PathName.erase(0,1); } - if( BasePath[BasePath.size()-1] != '/' ) { BasePath += "/"; } + if (PathName[0] == '/'){ + PathName.erase(0, 1); + } + if (BasePath[BasePath.size() - 1] != '/'){ + BasePath += "/"; + } MyPath = PathName; - FillEntries( ); + FillEntries(); } -Filesystem::Directory::~Directory( ) { } +Filesystem::Directory::~Directory(){ +} -void Filesystem::Directory::FillEntries( ) { - fprintf( stderr, "Filling Entries of %s:\n", (MyBase + MyPath).c_str() ); +void Filesystem::Directory::FillEntries(){ + fprintf(stderr, "Filling Entries of %s:\n", (MyBase + MyPath).c_str()); ValidDir = true; struct stat StatBuf; Entries.clear(); - DIR * Dirp = opendir( (MyBase + MyPath).c_str() ); - if( !Dirp ) { + DIR * Dirp = opendir((MyBase + MyPath).c_str()); + if ( !Dirp){ ValidDir = false; - } else { + }else{ dirent * entry; - while( entry = readdir( Dirp ) ) { - if( stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1 ) { - fprintf( stderr, "\tSkipping %s\n\t\tReason: %s\n", entry->d_name, strerror(errno) ); + while ((entry = readdir(Dirp))){ + if (stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){ + fprintf(stderr, "\tSkipping %s\n\t\tReason: %s\n", entry->d_name, strerror(errno)); continue; } ///Convert stat to string - Entries[ std::string( entry->d_name ) ] = StatBuf; + Entries[std::string(entry->d_name)] = StatBuf; } } - fprintf( stderr, "Valid dir: %d\n", ValidDir ); - fprintf( stderr, "#Entries: %d\n", Entries.size() ); + fprintf(stderr, "Valid dir: %d\n", ValidDir); + fprintf(stderr, "#Entries: %d\n", Entries.size()); } -void Filesystem::Directory::Print( ) { - if( !ValidDir ) { - printf( "%s is not a valid directory\n", (MyBase + MyPath).c_str() ); +void Filesystem::Directory::Print(){ + if ( !ValidDir){ + printf("%s is not a valid directory\n", (MyBase + MyPath).c_str()); return; } - printf( "%s:\n", (MyBase + MyPath).c_str() ); - for( std::map::iterator it = Entries.begin(); it != Entries.end(); it++ ) { - printf( "\t%s\n", (*it).first.c_str() ); + printf("%s:\n", (MyBase + MyPath).c_str()); + for (std::map::iterator it = Entries.begin(); it != Entries.end(); it++){ + printf("\t%s\n", ( *it).first.c_str()); } - printf( "\n" ); + printf("\n"); } -bool Filesystem::Directory::IsDir( ) { +bool Filesystem::Directory::IsDir(){ return ValidDir; } -std::string Filesystem::Directory::PWD( ) { +std::string Filesystem::Directory::PWD(){ return "/" + MyPath; } -std::string Filesystem::Directory::LIST( std::vector ActiveStreams ) { - FillEntries( ); +std::string Filesystem::Directory::LIST(std::vector ActiveStreams){ + FillEntries(); int MyPermissions; std::stringstream Converter; - passwd* pwd;//For Username - group* grp;//For Groupname - tm* tm;//For time localisation - char datestring[256];//For time localisation - + passwd* pwd; //For Username + group* grp; //For Groupname + tm* tm; //For time localisation + char datestring[256]; //For time localisation + std::string MyLoc = MyBase + MyPath; - if( MyLoc[MyLoc.size()-1] != '/' ) { MyLoc += "/"; } - - for( std::map::iterator it = Entries.begin(); it != Entries.end(); it++ ) { - - bool Active = ( std::find( ActiveStreams.begin(), ActiveStreams.end(), (*it).first ) != ActiveStreams.end() ); - fprintf( stderr, "%s active?: %d\n", (*it).first.c_str(), Active ); - fprintf( stderr, "\tMyPath: %s\n\tVisible: %d\n", MyPath.c_str(), MyVisible[MyPath] ); - fprintf( stderr, "\t\tBitmask S_ACTIVE: %d\n\t\tBitmask S_INACTIVE: %d\n", MyVisible[MyPath] & S_ACTIVE, MyVisible[MyPath] & S_INACTIVE ); - if( ( Active && ( MyVisible[MyPath] & S_ACTIVE ) ) || ( (!Active) && ( MyVisible[MyPath] & S_INACTIVE ) ) || ( ((*it).second.st_mode / 010000 ) == 4 ) ) { - if( ((*it).second.st_mode / 010000) == 4 ) { Converter << 'd'; } else { Converter << '-'; } - MyPermissions = ( ( (*it).second.st_mode % 010000 ) / 0100 ); - if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; } - if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; } - if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; } - MyPermissions = ( ( (*it).second.st_mode % 0100 ) / 010 ); - if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; } - if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; } - if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; } - MyPermissions = ( (*it).second.st_mode % 010 ); - if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; } - if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; } - if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; } + if (MyLoc[MyLoc.size() - 1] != '/'){ + MyLoc += "/"; + } + + for (std::map::iterator it = Entries.begin(); it != Entries.end(); it++){ + + bool Active = (std::find(ActiveStreams.begin(), ActiveStreams.end(), ( *it).first) != ActiveStreams.end()); + fprintf(stderr, "%s active?: %d\n", ( *it).first.c_str(), Active); + fprintf(stderr, "\tMyPath: %s\n\tVisible: %d\n", MyPath.c_str(), MyVisible[MyPath]); + fprintf(stderr, "\t\tBitmask S_ACTIVE: %d\n\t\tBitmask S_INACTIVE: %d\n", MyVisible[MyPath] & S_ACTIVE, MyVisible[MyPath] & S_INACTIVE); + if ((Active && (MyVisible[MyPath] & S_ACTIVE)) || (( !Active) && (MyVisible[MyPath] & S_INACTIVE)) || ((( *it).second.st_mode / 010000) == 4)){ + if ((( *it).second.st_mode / 010000) == 4){ + Converter << 'd'; + }else{ + Converter << '-'; + } + MyPermissions = ((( *it).second.st_mode % 010000) / 0100); + if (MyPermissions & 4){ + Converter << 'r'; + }else{ + Converter << '-'; + } + if (MyPermissions & 2){ + Converter << 'w'; + }else{ + Converter << '-'; + } + if (MyPermissions & 1){ + Converter << 'x'; + }else{ + Converter << '-'; + } + MyPermissions = ((( *it).second.st_mode % 0100) / 010); + if (MyPermissions & 4){ + Converter << 'r'; + }else{ + Converter << '-'; + } + if (MyPermissions & 2){ + Converter << 'w'; + }else{ + Converter << '-'; + } + if (MyPermissions & 1){ + Converter << 'x'; + }else{ + Converter << '-'; + } + MyPermissions = (( *it).second.st_mode % 010); + if (MyPermissions & 4){ + Converter << 'r'; + }else{ + Converter << '-'; + } + if (MyPermissions & 2){ + Converter << 'w'; + }else{ + Converter << '-'; + } + if (MyPermissions & 1){ + Converter << 'x'; + }else{ + Converter << '-'; + } Converter << ' '; - Converter << (*it).second.st_nlink; + Converter << ( *it).second.st_nlink; Converter << ' '; - if( (pwd = getpwuid((*it).second.st_uid)) ) { + if ((pwd = getpwuid(( *it).second.st_uid))){ Converter << pwd->pw_name; - } else { - Converter << (*it).second.st_uid; + }else{ + Converter << ( *it).second.st_uid; } Converter << ' '; - if( (grp = getgrgid((*it).second.st_gid) ) ) { + if ((grp = getgrgid(( *it).second.st_gid))){ Converter << grp->gr_name; - } else { - Converter << (*it).second.st_gid; + }else{ + Converter << ( *it).second.st_gid; } Converter << ' '; - Converter << (*it).second.st_size; + Converter << ( *it).second.st_size; Converter << ' '; - tm = localtime(&((*it).second.st_mtime)); + tm = localtime( &(( *it).second.st_mtime)); strftime(datestring, sizeof(datestring), "%b %d %H:%M", tm); Converter << datestring; Converter << ' '; - Converter << (*it).first; + Converter << ( *it).first; Converter << '\n'; } } return Converter.str(); } -bool Filesystem::Directory::CWD( std::string Path ) { - if( Path[0] == '/' ) { - Path.erase(0,1); +bool Filesystem::Directory::CWD(std::string Path){ + if (Path[0] == '/'){ + Path.erase(0, 1); MyPath = Path; - } else { - if( MyPath != "" ) { + }else{ + if (MyPath != ""){ MyPath += "/"; } MyPath += Path; } FillEntries(); - printf( "New Path: %s\n", MyPath.c_str() ); - if( MyPermissions.find( MyPath ) != MyPermissions.end() ) { - printf( "\tPermissions: %d\n", MyPermissions[MyPath] ); + printf("New Path: %s\n", MyPath.c_str()); + if (MyPermissions.find(MyPath) != MyPermissions.end()){ + printf("\tPermissions: %d\n", MyPermissions[MyPath]); } - return SimplifyPath( ); + return SimplifyPath(); } -bool Filesystem::Directory::CDUP( ) { - return CWD( ".." ); +bool Filesystem::Directory::CDUP(){ + return CWD(".."); } -std::string Filesystem::Directory::RETR( std::string Path ) { +std::string Filesystem::Directory::RETR(std::string Path){ std::string Result; std::string FileName; - if( Path[0] == '/' ) { - Path.erase(0,1); + if (Path[0] == '/'){ + Path.erase(0, 1); FileName = MyBase + Path; - } else { + }else{ FileName = MyBase + MyPath + "/" + Path; } std::ifstream File; - File.open( FileName.c_str() ); - while( File.good() ) { Result += File.get(); } + File.open(FileName.c_str()); + while (File.good()){ + Result += File.get(); + } File.close(); return Result; } -void Filesystem::Directory::STOR( std::string Path, std::string Data ) { - if( MyPermissions.find( MyPath ) == MyPermissions.end() || ( MyPermissions[MyPath] & P_STOR ) ) { +void Filesystem::Directory::STOR(std::string Path, std::string Data){ + if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_STOR)){ std::string FileName; - if( Path[0] == '/' ) { - Path.erase(0,1); + if (Path[0] == '/'){ + Path.erase(0, 1); FileName = MyBase + Path; - } else { + }else{ FileName = MyBase + MyPath + "/" + Path; } std::ofstream File; - File.open( FileName.c_str() ); + File.open(FileName.c_str()); File << Data; File.close(); } } -bool Filesystem::Directory::SimplifyPath( ) { +bool Filesystem::Directory::SimplifyPath(){ MyPath += "/"; - fprintf( stderr, "MyPath: %s\n", MyPath.c_str() ); + fprintf(stderr, "MyPath: %s\n", MyPath.c_str()); std::vector TempPath; std::string TempString; - for( std::string::iterator it = MyPath.begin(); it != MyPath.end(); it ++ ) { - if( (*it) == '/' ) { - if( TempString == ".." ) { - if( !TempPath.size() ) { + for (std::string::iterator it = MyPath.begin(); it != MyPath.end(); it++){ + if (( *it) == '/'){ + if (TempString == ".."){ + if ( !TempPath.size()){ return false; } - TempPath.erase( (TempPath.end()-1) ); - } else if ( TempString != "." && TempString != "" ) { - TempPath.push_back( TempString ); + TempPath.erase((TempPath.end() - 1)); + }else if (TempString != "." && TempString != ""){ + TempPath.push_back(TempString); } TempString = ""; - } else { - TempString += (*it); + }else{ + TempString += ( *it); } } MyPath = ""; - for( std::vector::iterator it = TempPath.begin(); it != TempPath.end(); it++ ) { - MyPath += (*it); - if( it != ( TempPath.end() - 1 ) ) { MyPath += "/"; } + for (std::vector::iterator it = TempPath.begin(); it != TempPath.end(); it++){ + MyPath += ( *it); + if (it != (TempPath.end() - 1)){ + MyPath += "/"; + } } - if( MyVisible.find( MyPath ) == MyVisible.end() ) { + if (MyVisible.find(MyPath) == MyVisible.end()){ MyVisible[MyPath] = S_ALL; } return true; } -bool Filesystem::Directory::DELE( std::string Path ) { - if( MyPermissions.find( MyPath ) == MyPermissions.end() || ( MyPermissions[MyPath] & P_DELE ) ) { +bool Filesystem::Directory::DELE(std::string Path){ + if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_DELE)){ std::string FileName; - if( Path[0] == '/' ) { - Path.erase(0,1); + if (Path[0] == '/'){ + Path.erase(0, 1); FileName = MyBase + Path; - } else { + }else{ FileName = MyBase + MyPath + "/" + Path; } - if( std::remove( FileName.c_str() ) ) { - fprintf( stderr, "Removing file %s unsuccesfull\n", FileName.c_str() ); + if (std::remove(FileName.c_str())){ + fprintf(stderr, "Removing file %s unsuccesfull\n", FileName.c_str()); return false; } return true; @@ -217,39 +267,39 @@ bool Filesystem::Directory::DELE( std::string Path ) { return false; } -bool Filesystem::Directory::MKD( std::string Path ) { +bool Filesystem::Directory::MKD(std::string Path){ std::string FileName; - if( Path[0] == '/' ) { - Path.erase(0,1); + if (Path[0] == '/'){ + Path.erase(0, 1); FileName = MyBase + Path; - } else { + }else{ FileName = MyBase + MyPath + "/" + Path; } - if( mkdir( FileName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) ) { - fprintf( stderr, "Creating directory %s unsuccesfull\n", FileName.c_str() ); + if (mkdir(FileName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)){ + fprintf(stderr, "Creating directory %s unsuccesfull\n", FileName.c_str()); return false; } MyVisible[FileName] = S_ALL; return true; } -bool Filesystem::Directory::Rename( std::string From, std::string To ) { - if( MyPermissions.find( MyPath ) == MyPermissions.end() || ( MyPermissions[MyPath] & P_RNFT ) ) { +bool Filesystem::Directory::Rename(std::string From, std::string To){ + if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_RNFT)){ std::string FileFrom; - if( From[0] == '/' ) { - From.erase(0,1); + if (From[0] == '/'){ + From.erase(0, 1); FileFrom = MyBase + From; - } else { + }else{ FileFrom = MyBase + MyPath + "/" + From; } std::string FileTo; - if( To[0] == '/' ) { + if (To[0] == '/'){ FileTo = MyBase + To; - } else { + }else{ FileTo = MyBase + MyPath + "/" + To; } - if( std::rename( FileFrom.c_str(), FileTo.c_str() ) ) { - fprintf( stderr, "Renaming file %s to %s unsuccesfull\n", FileFrom.c_str(), FileTo.c_str() ); + if (std::rename(FileFrom.c_str(), FileTo.c_str())){ + fprintf(stderr, "Renaming file %s to %s unsuccesfull\n", FileFrom.c_str(), FileTo.c_str()); return false; } return true; @@ -257,17 +307,17 @@ bool Filesystem::Directory::Rename( std::string From, std::string To ) { return false; } -void Filesystem::Directory::SetPermissions( std::string Path, char Permissions ) { +void Filesystem::Directory::SetPermissions(std::string Path, char Permissions){ MyPermissions[Path] = Permissions; } -bool Filesystem::Directory::HasPermission( char Permission ) { - if( MyPermissions.find( MyPath ) == MyPermissions.end() || ( MyPermissions[MyPath] & Permission ) ) { +bool Filesystem::Directory::HasPermission(char Permission){ + if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & Permission)){ return true; } return false; } -void Filesystem::Directory::SetVisibility( std::string Pathname, char Visible ) { +void Filesystem::Directory::SetVisibility(std::string Pathname, char Visible){ MyVisible[Pathname] = Visible; } diff --git a/lib/filesystem.h b/lib/filesystem.h index f20e91a0..204449d3 100644 --- a/lib/filesystem.h +++ b/lib/filesystem.h @@ -21,49 +21,47 @@ #include namespace Filesystem { - enum DIR_Permissions { - P_LIST = 0x01,//List - P_RETR = 0x02,//Retrieve - P_STOR = 0x04,//Store - P_RNFT = 0x08,//Rename From/To - P_DELE = 0x10,//Delete - P_MKD = 0x20,//Make directory - P_RMD = 0x40,//Remove directory + enum DIR_Permissions{ + P_LIST = 0x01, //List + P_RETR = 0x02, //Retrieve + P_STOR = 0x04, //Store + P_RNFT = 0x08, //Rename From/To + P_DELE = 0x10, //Delete + P_MKD = 0x20, //Make directory + P_RMD = 0x40, //Remove directory }; - - enum DIR_Show { - S_NONE = 0x00, - S_ACTIVE = 0x01, - S_INACTIVE = 0x02, - S_ALL = 0x03, + + enum DIR_Show{ + S_NONE = 0x00, S_ACTIVE = 0x01, S_INACTIVE = 0x02, S_ALL = 0x03, }; - - class Directory { + + class Directory{ public: - Directory( std::string PathName = "", std::string BasePath = "."); - ~Directory( ); - void Print( ); - bool IsDir( ); - std::string PWD( ); - std::string LIST( std::vector ActiveStreams = std::vector() ); - bool CWD( std::string Path ); - bool CDUP( ); - bool DELE( std::string Path ); - bool MKD( std::string Path ); - std::string RETR( std::string Path ); - void STOR( std::string Path, std::string Data ); - bool Rename( std::string From, std::string To ); - void SetPermissions( std::string PathName, char Permissions ); - bool HasPermission( char Permission ); - void SetVisibility( std::string Pathname, char Visible ); + Directory(std::string PathName = "", std::string BasePath = "."); + ~Directory(); + void Print(); + bool IsDir(); + std::string PWD(); + std::string LIST(std::vector ActiveStreams = std::vector()); + bool CWD(std::string Path); + bool CDUP(); + bool DELE(std::string Path); + bool MKD(std::string Path); + std::string RETR(std::string Path); + void STOR(std::string Path, std::string Data); + bool Rename(std::string From, std::string To); + void SetPermissions(std::string PathName, char Permissions); + bool HasPermission(char Permission); + void SetVisibility(std::string Pathname, char Visible); private: bool ValidDir; - bool SimplifyPath( ); - void FillEntries( ); + bool SimplifyPath(); + void FillEntries(); std::string MyBase; std::string MyPath; - std::map< std::string, struct stat > Entries; - std::map< std::string, char > MyPermissions; - std::map< std::string, char > MyVisible; - };//Directory Class -};//Filesystem namespace + std::map Entries; + std::map MyPermissions; + std::map MyVisible; + }; +//Directory Class +}//Filesystem namespace diff --git a/lib/flv_tag.cpp b/lib/flv_tag.cpp index 20ed3d36..e8204076 100644 --- a/lib/flv_tag.cpp +++ b/lib/flv_tag.cpp @@ -1,9 +1,9 @@ /// \file flv_tag.cpp /// Holds all code for the FLV namespace. -#include "flv_tag.h" #include "amf.h" #include "rtmpchunks.h" +#include "flv_tag.h" #include //for Tag::FileLoader #include //for Tag::FileLoader #include //for Tag::FileLoader @@ -38,7 +38,7 @@ bool FLV::check_header(char * header){ if (header[11] != 0) return false; if (header[12] != 0) return false; return true; -}//FLV::check_header +} //FLV::check_header /// Checks the first 3 bytes for the string "FLV". Implementing a basic FLV header check, /// returning true if it is, false if not. @@ -47,7 +47,7 @@ bool FLV::is_header(char * header){ if (header[1] != 'L') return false; if (header[2] != 'V') return false; return true; -}//FLV::is_header +} //FLV::is_header /// True if this media type requires init data. /// Will always return false if the tag type is not 0x08 or 0x09. @@ -57,21 +57,35 @@ bool FLV::Tag::needsInitData(){ switch (data[0]){ case 0x09: switch (data[11] & 0x0F){ - case 2: return true; break;//H263 requires init data - case 7: return true; break;//AVC requires init data - default: return false; break;//other formats do not + case 2: + return true; + break; //H263 requires init data + case 7: + return true; + break; //AVC requires init data + default: + return false; + break; //other formats do not } break; case 0x08: switch (data[11] & 0xF0){ - case 0x20: return false; break;//MP3 does not...? Unsure. - case 0xA0: return true; break;//AAC requires init data - case 0xE0: return false; break;//MP38kHz does not...? - default: return false; break;//other formats do not + case 0x20: + return false; + break; //MP3 does not...? Unsure. + case 0xA0: + return true; + break; //AAC requires init data + case 0xE0: + return false; + break; //MP38kHz does not...? + default: + return false; + break; //other formats do not } break; } - return false;//only audio/video can require init data + return false; //only audio/video can require init data } /// True if current tag is init data for this media type. @@ -79,11 +93,15 @@ bool FLV::Tag::isInitData(){ switch (data[0]){ case 0x09: switch (data[11] & 0xF0){ - case 0x50: return true; break; + case 0x50: + return true; + break; } if ((data[11] & 0x0F) == 7){ switch (data[12]){ - case 0: return true; break; + case 0: + return true; + break; } } break; @@ -106,71 +124,149 @@ std::string FLV::Tag::tagType(){ switch (data[0]){ case 0x09: switch (data[11] & 0x0F){ - case 1: R << "JPEG"; break; - case 2: R << "H263"; break; - case 3: R << "ScreenVideo1"; break; - case 4: R << "VP6"; break; - case 5: R << "VP6Alpha"; break; - case 6: R << "ScreenVideo2"; break; - case 7: R << "H264"; break; - default: R << "unknown"; break; + case 1: + R << "JPEG"; + break; + case 2: + R << "H263"; + break; + case 3: + R << "ScreenVideo1"; + break; + case 4: + R << "VP6"; + break; + case 5: + R << "VP6Alpha"; + break; + case 6: + R << "ScreenVideo2"; + break; + case 7: + R << "H264"; + break; + default: + R << "unknown"; + break; } - R << " video "; - switch (data[11] & 0xF0){ - case 0x10: R << "keyframe"; break; - case 0x20: R << "iframe"; break; - case 0x30: R << "disposableiframe"; break; - case 0x40: R << "generatedkeyframe"; break; - case 0x50: R << "videoinfo"; break; + R << " video "; + switch (data[11] & 0xF0){ + case 0x10: + R << "keyframe"; + break; + case 0x20: + R << "iframe"; + break; + case 0x30: + R << "disposableiframe"; + break; + case 0x40: + R << "generatedkeyframe"; + break; + case 0x50: + R << "videoinfo"; + break; } if ((data[11] & 0x0F) == 7){ switch (data[12]){ - case 0: R << " header"; break; - case 1: R << " NALU"; break; - case 2: R << " endofsequence"; break; + case 0: + R << " header"; + break; + case 1: + R << " NALU"; + break; + case 2: + R << " endofsequence"; + break; } } break; case 0x08: switch (data[11] & 0xF0){ - case 0x00: R << "linear PCM PE"; break; - case 0x10: R << "ADPCM"; break; - case 0x20: R << "MP3"; break; - case 0x30: R << "linear PCM LE"; break; - case 0x40: R << "Nelly16kHz"; break; - case 0x50: R << "Nelly8kHz"; break; - case 0x60: R << "Nelly"; break; - case 0x70: R << "G711A-law"; break; - case 0x80: R << "G711mu-law"; break; - case 0x90: R << "reserved"; break; - case 0xA0: R << "AAC"; break; - case 0xB0: R << "Speex"; break; - case 0xE0: R << "MP38kHz"; break; - case 0xF0: R << "DeviceSpecific"; break; - default: R << "unknown"; break; + case 0x00: + R << "linear PCM PE"; + break; + case 0x10: + R << "ADPCM"; + break; + case 0x20: + R << "MP3"; + break; + case 0x30: + R << "linear PCM LE"; + break; + case 0x40: + R << "Nelly16kHz"; + break; + case 0x50: + R << "Nelly8kHz"; + break; + case 0x60: + R << "Nelly"; + break; + case 0x70: + R << "G711A-law"; + break; + case 0x80: + R << "G711mu-law"; + break; + case 0x90: + R << "reserved"; + break; + case 0xA0: + R << "AAC"; + break; + case 0xB0: + R << "Speex"; + break; + case 0xE0: + R << "MP38kHz"; + break; + case 0xF0: + R << "DeviceSpecific"; + break; + default: + R << "unknown"; + break; } switch (data[11] & 0x0C){ - case 0x0: R << " 5.5kHz"; break; - case 0x4: R << " 11kHz"; break; - case 0x8: R << " 22kHz"; break; - case 0xC: R << " 44kHz"; break; + case 0x0: + R << " 5.5kHz"; + break; + case 0x4: + R << " 11kHz"; + break; + case 0x8: + R << " 22kHz"; + break; + case 0xC: + R << " 44kHz"; + break; } switch (data[11] & 0x02){ - case 0: R << " 8bit"; break; - case 2: R << " 16bit"; break; + case 0: + R << " 8bit"; + break; + case 2: + R << " 16bit"; + break; } switch (data[11] & 0x01){ - case 0: R << " mono"; break; - case 1: R << " stereo"; break; + case 0: + R << " mono"; + break; + case 1: + R << " stereo"; + break; } R << " audio"; if ((data[12] == 0) && ((data[11] & 0xF0) == 0xA0)){ R << " initdata"; } break; - case 0x12:{ + case 0x12: { R << "(meta)data: "; - AMF::Object metadata = AMF::parse((unsigned char*)data+11, len-15); + AMF::Object metadata = AMF::parse((unsigned char*)data + 11, len - 15); R << metadata.Print(); break; } @@ -179,12 +275,12 @@ std::string FLV::Tag::tagType(){ break; } return R.str(); -}//FLV::Tag::tagtype +} //FLV::Tag::tagtype /// Returns the 32-bit timestamp of this tag. unsigned int FLV::Tag::tagTime(){ return (data[4] << 16) + (data[5] << 8) + data[6] + (data[7] << 24); -}//tagTime getter +} //tagTime getter /// Sets the 32-bit timestamp of this tag. void FLV::Tag::tagTime(unsigned int T){ @@ -192,14 +288,19 @@ void FLV::Tag::tagTime(unsigned int T){ data[5] = ((T >> 8) & 0xFF); data[6] = (T & 0xFF); data[7] = ((T >> 24) & 0xFF); -}//tagTime setter +} //tagTime setter /// Constructor for a new, empty, tag. /// The buffer length is initialized to 0, and later automatically /// increased if neccesary. FLV::Tag::Tag(){ - len = 0; buf = 0; data = 0; isKeyframe = false; done = true; sofar = 0; -}//empty constructor + len = 0; + buf = 0; + data = 0; + isKeyframe = false; + done = true; + sofar = 0; +} //empty constructor /// Copy constructor, copies the contents of an existing tag. /// The buffer length is initialized to the actual size of the tag @@ -217,25 +318,29 @@ FLV::Tag::Tag(const Tag& O){ data = 0; } isKeyframe = O.isKeyframe; -}//copy constructor - +} //copy constructor /// Copy constructor from a RTMP chunk. /// Copies the contents of a RTMP chunk into a valid FLV tag. /// Exactly the same as making a chunk by through the default (empty) constructor /// and then calling FLV::Tag::ChunkLoader with the chunk as argument. FLV::Tag::Tag(const RTMPStream::Chunk& O){ - len = 0; buf = 0; data = 0; isKeyframe = false; done = true; sofar = 0; + len = 0; + buf = 0; + data = 0; + isKeyframe = false; + done = true; + sofar = 0; ChunkLoader(O); } /// Assignment operator - works exactly like the copy constructor. /// This operator checks for self-assignment. -FLV::Tag & FLV::Tag::operator= (const FLV::Tag& O){ - if (this != &O){//no self-assignment +FLV::Tag & FLV::Tag::operator=(const FLV::Tag& O){ + if (this != &O){ //no self-assignment len = O.len; if (len > 0){ - if (!data){ + if ( !data){ data = (char*)malloc(len); buf = len; }else{ @@ -249,7 +354,7 @@ FLV::Tag & FLV::Tag::operator= (const FLV::Tag& O){ isKeyframe = O.isKeyframe; } return *this; -}//assignment operator +} //assignment operator /// FLV loader function from DTSC. /// Takes the DTSC data and makes it into FLV. @@ -258,23 +363,27 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){ case DTSC::VIDEO: len = S.lastData().length() + 16; if (S.metadata.isMember("video") && S.metadata["video"].isMember("codec")){ - if (S.metadata["video"]["codec"].asString() == "H264"){len += 4;} + if (S.metadata["video"]["codec"].asString() == "H264"){ + len += 4; + } } break; case DTSC::AUDIO: len = S.lastData().length() + 16; if (S.metadata.isMember("audio") && S.metadata["audio"].isMember("codec")){ - if (S.metadata["audio"]["codec"].asString() == "AAC"){len += 1;} + if (S.metadata["audio"]["codec"].asString() == "AAC"){ + len += 1; + } } break; case DTSC::META: len = S.lastData().length() + 15; break; - default://ignore all other types (there are currently no other types...) + default: //ignore all other types (there are currently no other types...) break; } if (len > 0){ - if (!data){ + if ( !data){ data = (char*)malloc(len); buf = len; }else{ @@ -286,60 +395,90 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){ switch (S.lastType()){ case DTSC::VIDEO: if ((unsigned int)len == S.lastData().length() + 16){ - memcpy(data+12, S.lastData().c_str(), S.lastData().length()); + memcpy(data + 12, S.lastData().c_str(), S.lastData().length()); }else{ - memcpy(data+16, S.lastData().c_str(), S.lastData().length()); - if (S.getPacket().isMember("nalu")){data[12] = 1;}else{data[12] = 2;} + memcpy(data + 16, S.lastData().c_str(), S.lastData().length()); + if (S.getPacket().isMember("nalu")){ + data[12] = 1; + }else{ + data[12] = 2; + } int offset = S.getPacket()["offset"].asInt(); data[13] = (offset >> 16) & 0xFF; data[14] = (offset >> 8) & 0XFF; data[15] = offset & 0xFF; } data[11] = 0; - if (S.metadata["video"]["codec"].asString() == "H264"){data[11] += 7;} - if (S.metadata["video"]["codec"].asString() == "H263"){data[11] += 2;} - if (S.getPacket().isMember("keyframe")){data[11] += 0x10;} - if (S.getPacket().isMember("interframe")){data[11] += 0x20;} - if (S.getPacket().isMember("disposableframe")){data[11] += 0x30;} + if (S.metadata["video"]["codec"].asString() == "H264"){ + data[11] += 7; + } + if (S.metadata["video"]["codec"].asString() == "H263"){ + data[11] += 2; + } + if (S.getPacket().isMember("keyframe")){ + data[11] += 0x10; + } + if (S.getPacket().isMember("interframe")){ + data[11] += 0x20; + } + if (S.getPacket().isMember("disposableframe")){ + data[11] += 0x30; + } break; - case DTSC::AUDIO:{ + case DTSC::AUDIO: { if ((unsigned int)len == S.lastData().length() + 16){ - memcpy(data+12, S.lastData().c_str(), S.lastData().length()); + memcpy(data + 12, S.lastData().c_str(), S.lastData().length()); }else{ - memcpy(data+13, S.lastData().c_str(), S.lastData().length()); - data[12] = 1;//raw AAC data, not sequence header + memcpy(data + 13, S.lastData().c_str(), S.lastData().length()); + data[12] = 1; //raw AAC data, not sequence header } data[11] = 0; - if (S.metadata["audio"]["codec"].asString() == "AAC"){data[11] += 0xA0;} - if (S.metadata["audio"]["codec"].asString() == "MP3"){data[11] += 0x20;} + if (S.metadata["audio"]["codec"].asString() == "AAC"){ + data[11] += 0xA0; + } + if (S.metadata["audio"]["codec"].asString() == "MP3"){ + data[11] += 0x20; + } unsigned int datarate = S.metadata["audio"]["rate"].asInt(); if (datarate >= 44100){ data[11] += 0x0C; - }else if(datarate >= 22050){ + }else if (datarate >= 22050){ data[11] += 0x08; - }else if(datarate >= 11025){ + }else if (datarate >= 11025){ data[11] += 0x04; } - if (S.metadata["audio"]["size"].asInt() == 16){data[11] += 0x02;} - if (S.metadata["audio"]["channels"].asInt() > 1){data[11] += 0x01;} + if (S.metadata["audio"]["size"].asInt() == 16){ + data[11] += 0x02; + } + if (S.metadata["audio"]["channels"].asInt() > 1){ + data[11] += 0x01; + } break; } case DTSC::META: - memcpy(data+11, S.lastData().c_str(), S.lastData().length()); + memcpy(data + 11, S.lastData().c_str(), S.lastData().length()); + break; + default: break; - default: break; } } setLen(); switch (S.lastType()){ - case DTSC::VIDEO: data[0] = 0x09; break; - case DTSC::AUDIO: data[0] = 0x08; break; - case DTSC::META: data[0] = 0x12; break; - default: break; + case DTSC::VIDEO: + data[0] = 0x09; + break; + case DTSC::AUDIO: + data[0] = 0x08; + break; + case DTSC::META: + data[0] = 0x12; + break; + default: + break; } - data[1] = ((len-15) >> 16) & 0xFF; - data[2] = ((len-15) >> 8) & 0xFF; - data[3] = (len-15) & 0xFF; + data[1] = ((len - 15) >> 16) & 0xFF; + data[2] = ((len - 15) >> 8) & 0xFF; + data[3] = (len - 15) & 0xFF; data[8] = 0; data[9] = 0; data[10] = 0; @@ -351,13 +490,13 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){ void FLV::Tag::setLen(){ int len4 = len - 4; int i = len; - data[--i] = (len4) & 0xFF; + data[ --i] = (len4) & 0xFF; len4 >>= 8; - data[--i] = (len4) & 0xFF; + data[ --i] = (len4) & 0xFF; len4 >>= 8; - data[--i] = (len4) & 0xFF; + data[ --i] = (len4) & 0xFF; len4 >>= 8; - data[--i] = (len4) & 0xFF; + data[ --i] = (len4) & 0xFF; } /// FLV Video init data loader function from DTSC. @@ -372,7 +511,7 @@ bool FLV::Tag::DTSCVideoInit(DTSC::Stream & S){ len = S.metadata["video"]["init"].asString().length() + 20; } if (len > 0){ - if (!data){ + if ( !data){ data = (char*)malloc(len); buf = len; }else{ @@ -381,18 +520,18 @@ bool FLV::Tag::DTSCVideoInit(DTSC::Stream & S){ buf = len; } } - memcpy(data+16, S.metadata["video"]["init"].asString().c_str(), len-20); - data[12] = 0;//H264 sequence header + memcpy(data + 16, S.metadata["video"]["init"].asString().c_str(), len - 20); + data[12] = 0; //H264 sequence header data[13] = 0; data[14] = 0; data[15] = 0; - data[11] = 0x17;//H264 keyframe (0x07 & 0x10) + data[11] = 0x17; //H264 keyframe (0x07 & 0x10) } setLen(); data[0] = 0x09; - data[1] = ((len-15) >> 16) & 0xFF; - data[2] = ((len-15) >> 8) & 0xFF; - data[3] = (len-15) & 0xFF; + data[1] = ((len - 15) >> 16) & 0xFF; + data[2] = ((len - 15) >> 8) & 0xFF; + data[3] = (len - 15) & 0xFF; data[8] = 0; data[9] = 0; data[10] = 0; @@ -413,7 +552,7 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){ len = S.metadata["audio"]["init"].asString().length() + 17; } if (len > 0){ - if (!data){ + if ( !data){ data = (char*)malloc(len); buf = len; }else{ @@ -422,27 +561,35 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){ buf = len; } } - memcpy(data+13, S.metadata["audio"]["init"].asString().c_str(), len-17); - data[12] = 0;//AAC sequence header + memcpy(data + 13, S.metadata["audio"]["init"].asString().c_str(), len - 17); + data[12] = 0; //AAC sequence header data[11] = 0; - if (S.metadata["audio"]["codec"].asString() == "AAC"){data[11] += 0xA0;} - if (S.metadata["audio"]["codec"].asString() == "MP3"){data[11] += 0x20;} + if (S.metadata["audio"]["codec"].asString() == "AAC"){ + data[11] += 0xA0; + } + if (S.metadata["audio"]["codec"].asString() == "MP3"){ + data[11] += 0x20; + } unsigned int datarate = S.metadata["audio"]["rate"].asInt(); if (datarate >= 44100){ data[11] += 0x0C; - }else if(datarate >= 22050){ + }else if (datarate >= 22050){ data[11] += 0x08; - }else if(datarate >= 11025){ + }else if (datarate >= 11025){ data[11] += 0x04; } - if (S.metadata["audio"]["size"].asInt() == 16){data[11] += 0x02;} - if (S.metadata["audio"]["channels"].asInt() > 1){data[11] += 0x01;} + if (S.metadata["audio"]["size"].asInt() == 16){ + data[11] += 0x02; + } + if (S.metadata["audio"]["channels"].asInt() > 1){ + data[11] += 0x01; + } } setLen(); data[0] = 0x08; - data[1] = ((len-15) >> 16) & 0xFF; - data[2] = ((len-15) >> 8) & 0xFF; - data[3] = (len-15) & 0xFF; + data[1] = ((len - 15) >> 16) & 0xFF; + data[2] = ((len - 15) >> 8) & 0xFF; + data[3] = (len - 15) & 0xFF; data[8] = 0; data[9] = 0; data[10] = 0; @@ -462,7 +609,7 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ if (S.metadata["video"]["codec"].asString() == "?"){ S.metadata["video"]["codec"] = "H264"; } - + AMF::Object amfdata("root", AMF::AMF0_DDV_CONTAINER); amfdata.addContent(AMF::Object("", "onMetaData")); @@ -480,9 +627,9 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ if (S.metadata.isMember("audio")){ total_byterate += S.metadata["audio"]["bps"].asInt(); } - for (int i = 0; i < S.metadata["length"].asInt(); ++i){//for each second in the file - keys.getContentP(0)->addContent(AMF::Object("", i * total_byterate, AMF::AMF0_NUMBER));//multiply by byterate for fake byte positions - keys.getContentP(1)->addContent(AMF::Object("", i, AMF::AMF0_NUMBER));//seconds + for (int i = 0; i < S.metadata["length"].asInt(); ++i){ //for each second in the file + keys.getContentP(0)->addContent(AMF::Object("", i * total_byterate, AMF::AMF0_NUMBER)); //multiply by byterate for fake byte positions + keys.getContentP(1)->addContent(AMF::Object("", i, AMF::AMF0_NUMBER)); //seconds } amfdata.getContentP(1)->addContent(keys); } @@ -536,7 +683,8 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ int i = 0; if (S.metadata.isMember("audio")){ trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT)); - trinfo.getContentP(i)->addContent(AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["audio"]["rate"].asInt()), AMF::AMF0_NUMBER)); + trinfo.getContentP(i)->addContent( + AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["audio"]["rate"].asInt()), AMF::AMF0_NUMBER)); trinfo.getContentP(i)->addContent(AMF::Object("timescale", S.metadata["audio"]["rate"].asInt(), AMF::AMF0_NUMBER)); trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY)); if (S.metadata["audio"]["codec"].asString() == "AAC"){ @@ -549,7 +697,8 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ } if (S.metadata.isMember("video")){ trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT)); - trinfo.getContentP(i)->addContent(AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["video"]["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER)); + trinfo.getContentP(i)->addContent( + AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["video"]["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER)); trinfo.getContentP(i)->addContent(AMF::Object("timescale", ((double)S.metadata["video"]["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER)); trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY)); if (S.metadata["video"]["codec"].asString() == "H264"){ @@ -568,7 +717,7 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ std::string tmp = amfdata.Pack(); len = tmp.length() + 15; if (len > 0){ - if (!data){ + if ( !data){ data = (char*)malloc(len); buf = len; }else{ @@ -577,13 +726,13 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ buf = len; } } - memcpy(data+11, tmp.c_str(), len-15); + memcpy(data + 11, tmp.c_str(), len - 15); } setLen(); data[0] = 0x12; - data[1] = ((len-15) >> 16) & 0xFF; - data[2] = ((len-15) >> 8) & 0xFF; - data[3] = (len-15) & 0xFF; + data[1] = ((len - 15) >> 16) & 0xFF; + data[2] = ((len - 15) >> 8) & 0xFF; + data[3] = (len - 15) & 0xFF; data[8] = 0; data[9] = 0; data[10] = 0; @@ -596,7 +745,7 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ bool FLV::Tag::ChunkLoader(const RTMPStream::Chunk& O){ len = O.len + 15; if (len > 0){ - if (!data){ + if ( !data){ data = (char*)malloc(len); buf = len; }else{ @@ -605,7 +754,7 @@ bool FLV::Tag::ChunkLoader(const RTMPStream::Chunk& O){ buf = len; } } - memcpy(data+11, &(O.data[0]), O.len); + memcpy(data + 11, &(O.data[0]), O.len); } setLen(); data[0] = O.msg_type_id; @@ -616,7 +765,6 @@ bool FLV::Tag::ChunkLoader(const RTMPStream::Chunk& O){ return true; } - /// Helper function for FLV::MemLoader. /// This function will try to read count bytes from data buffer D into buffer. /// This function should be called repeatedly until true. @@ -629,16 +777,23 @@ bool FLV::Tag::ChunkLoader(const RTMPStream::Chunk& O){ /// \param P The current position in the data buffer. Will be updated to reflect new position. /// \return True if count bytes are read succesfully, false otherwise. bool FLV::Tag::MemReadUntil(char * buffer, unsigned int count, unsigned int & sofar, char * D, unsigned int S, unsigned int & P){ - if (sofar >= count){return true;} + if (sofar >= count){ + return true; + } int r = 0; - if (P+(count-sofar) > S){r = S-P;}else{r = count-sofar;} - memcpy(buffer+sofar, D+P, r); + if (P + (count - sofar) > S){ + r = S - P; + }else{ + r = count - sofar; + } + memcpy(buffer + sofar, D + P, r); P += r; sofar += r; - if (sofar >= count){return true;} + if (sofar >= count){ + return true; + } return false; -}//Tag::MemReadUntil - +} //Tag::MemReadUntil /// Try to load a tag from a data buffer in memory. /// This is a stateful function - if fed incorrect data, it will most likely never return true again! @@ -648,7 +803,10 @@ bool FLV::Tag::MemReadUntil(char * buffer, unsigned int count, unsigned int & so /// \param P The current position in the data buffer. Will be updated to reflect new position. /// \return True if a whole tag is succesfully read, false otherwise. bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){ - if (buf < 15){data = (char*)realloc(data, 15); buf = 15;} + if (buf < 15){ + data = (char*)realloc(data, 15); + buf = 15; + } if (done){ //read a header if (MemReadUntil(data, 11, sofar, D, S, P)){ @@ -658,14 +816,21 @@ bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){ if (FLV::check_header(data)){ sofar = 0; memcpy(FLV::Header, data, 13); - }else{FLV::Parse_Error = true; Error_Str = "Invalid header received."; return false;} + }else{ + FLV::Parse_Error = true; + Error_Str = "Invalid header received."; + return false; + } } }else{ //if a tag header, calculate length and read tag body len = data[3] + 15; len += (data[2] << 8); len += (data[1] << 16); - if (buf < len){data = (char*)realloc(data, len); buf = len;} + if (buf < len){ + data = (char*)realloc(data, len); + buf = len; + } if (data[0] > 0x12){ data[0] += 32; FLV::Parse_Error = true; @@ -681,15 +846,18 @@ bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){ //read tag body if (MemReadUntil(data, len, sofar, D, S, P)){ //calculate keyframeness, next time read header again, return true - if ((data[0] == 0x09) && (((data[11] & 0xf0) >> 4) == 1)){isKeyframe = true;}else{isKeyframe = false;} + if ((data[0] == 0x09) && (((data[11] & 0xf0) >> 4) == 1)){ + isKeyframe = true; + }else{ + isKeyframe = false; + } done = true; sofar = 0; return true; } } return false; -}//Tag::MemLoader - +} //Tag::MemLoader /// Helper function for FLV::FileLoader. /// This function will try to read count bytes from file f into buffer. @@ -700,12 +868,20 @@ bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){ /// \param f File to read from. /// \return True if count bytes are read succesfully, false otherwise. bool FLV::Tag::FileReadUntil(char * buffer, unsigned int count, unsigned int & sofar, FILE * f){ - if (sofar >= count){return true;} + if (sofar >= count){ + return true; + } int r = 0; - r = fread(buffer + sofar,1,count-sofar,f); - if (r < 0){FLV::Parse_Error = true; Error_Str = "File reading error."; return false;} + r = fread(buffer + sofar, 1, count - sofar, f); + if (r < 0){ + FLV::Parse_Error = true; + Error_Str = "File reading error."; + return false; + } sofar += r; - if (sofar >= count){return true;} + if (sofar >= count){ + return true; + } return false; } @@ -718,7 +894,10 @@ bool FLV::Tag::FileLoader(FILE * f){ int preflags = fcntl(fileno(f), F_GETFL, 0); int postflags = preflags | O_NONBLOCK; fcntl(fileno(f), F_SETFL, postflags); - if (buf < 15){data = (char*)realloc(data, 15); buf = 15;} + if (buf < 15){ + data = (char*)realloc(data, 15); + buf = 15; + } if (done){ //read a header @@ -729,14 +908,21 @@ bool FLV::Tag::FileLoader(FILE * f){ if (FLV::check_header(data)){ sofar = 0; memcpy(FLV::Header, data, 13); - }else{FLV::Parse_Error = true; Error_Str = "Invalid header received."; return false;} + }else{ + FLV::Parse_Error = true; + Error_Str = "Invalid header received."; + return false; + } } }else{ //if a tag header, calculate length and read tag body len = data[3] + 15; len += (data[2] << 8); len += (data[1] << 16); - if (buf < len){data = (char*)realloc(data, len); buf = len;} + if (buf < len){ + data = (char*)realloc(data, len); + buf = len; + } if (data[0] > 0x12){ data[0] += 32; FLV::Parse_Error = true; @@ -752,7 +938,11 @@ bool FLV::Tag::FileLoader(FILE * f){ //read tag body if (FileReadUntil(data, len, sofar, f)){ //calculate keyframeness, next time read header again, return true - if ((data[0] == 0x09) && (((data[11] & 0xf0) >> 4) == 1)){isKeyframe = true;}else{isKeyframe = false;} + if ((data[0] == 0x09) && (((data[11] & 0xf0) >> 4) == 1)){ + isKeyframe = true; + }else{ + isKeyframe = false; + } done = true; sofar = 0; fcntl(fileno(f), F_SETFL, preflags); @@ -761,28 +951,42 @@ bool FLV::Tag::FileLoader(FILE * f){ } fcntl(fileno(f), F_SETFL, preflags); return false; -}//FLV_GetPacket +} //FLV_GetPacket JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){ JSON::Value pack_out; // Storage for outgoing metadata. if (data[0] == 0x12){ - AMF::Object meta_in = AMF::parse((unsigned char*)data+11, len-15); + AMF::Object meta_in = AMF::parse((unsigned char*)data + 11, len - 15); if (meta_in.getContentP(0) && (meta_in.getContentP(0)->StrValue() == "onMetaData") && meta_in.getContentP(1)){ AMF::Object * tmp = meta_in.getContentP(1); if (tmp->getContentP("videocodecid")){ switch ((unsigned int)tmp->getContentP("videocodecid")->NumValue()){ - case 2: metadata["video"]["codec"] = "H263"; break; - case 4: metadata["video"]["codec"] = "VP6"; break; - case 7: metadata["video"]["codec"] = "H264"; break; - default: metadata["video"]["codec"] = "?"; break; + case 2: + metadata["video"]["codec"] = "H263"; + break; + case 4: + metadata["video"]["codec"] = "VP6"; + break; + case 7: + metadata["video"]["codec"] = "H264"; + break; + default: + metadata["video"]["codec"] = "?"; + break; } } if (tmp->getContentP("audiocodecid")){ switch ((unsigned int)tmp->getContentP("audiocodecid")->NumValue()){ - case 2: metadata["audio"]["codec"] = "MP3"; break; - case 10: metadata["audio"]["codec"] = "AAC"; break; - default: metadata["audio"]["codec"] = "?"; break; + case 2: + metadata["audio"]["codec"] = "MP3"; + break; + case 10: + metadata["audio"]["codec"] = "AAC"; + break; + default: + metadata["audio"]["codec"] = "?"; + break; } } if (tmp->getContentP("width")){ @@ -792,13 +996,13 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){ metadata["video"]["height"] = (long long int)tmp->getContentP("height")->NumValue(); } if (tmp->getContentP("framerate")){ - metadata["video"]["fpks"] = (long long int)tmp->getContentP("framerate")->NumValue()*1000; + metadata["video"]["fpks"] = (long long int)tmp->getContentP("framerate")->NumValue() * 1000; } if (tmp->getContentP("videodatarate")){ - metadata["video"]["bps"] = (long long int)(tmp->getContentP("videodatarate")->NumValue()*1024)/8; + metadata["video"]["bps"] = (long long int)(tmp->getContentP("videodatarate")->NumValue() * 1024) / 8; } if (tmp->getContentP("audiodatarate")){ - metadata["audio"]["bps"] = (long long int)(tmp->getContentP("audiodatarate")->NumValue()*1024)/8; + metadata["audio"]["bps"] = (long long int)(tmp->getContentP("audiodatarate")->NumValue() * 1024) / 8; } if (tmp->getContentP("audiosamplerate")){ metadata["audio"]["rate"] = (long long int)tmp->getContentP("audiosamplerate")->NumValue(); @@ -814,61 +1018,99 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){ } } } - if (!metadata.isMember("length")){metadata["length"] = 0;} - if (metadata.isMember("video")){ - if (!metadata["video"].isMember("width")){metadata["video"]["width"] = 0;} - if (!metadata["video"].isMember("height")){metadata["video"]["height"] = 0;} - if (!metadata["video"].isMember("fpks")){metadata["video"]["fpks"] = 0;} - if (!metadata["video"].isMember("bps")){metadata["video"]["bps"] = 0;} - if (!metadata["video"].isMember("keyms")){metadata["video"]["keyms"] = 0;} - if (!metadata["video"].isMember("keyvar")){metadata["video"]["keyvar"] = 0;} + if ( !metadata.isMember("length")){ + metadata["length"] = 0; } - return pack_out;//empty + if (metadata.isMember("video")){ + if ( !metadata["video"].isMember("width")){ + metadata["video"]["width"] = 0; + } + if ( !metadata["video"].isMember("height")){ + metadata["video"]["height"] = 0; + } + if ( !metadata["video"].isMember("fpks")){ + metadata["video"]["fpks"] = 0; + } + if ( !metadata["video"].isMember("bps")){ + metadata["video"]["bps"] = 0; + } + if ( !metadata["video"].isMember("keyms")){ + metadata["video"]["keyms"] = 0; + } + if ( !metadata["video"].isMember("keyvar")){ + metadata["video"]["keyvar"] = 0; + } + } + return pack_out; //empty } if (data[0] == 0x08){ char audiodata = data[11]; if (needsInitData() && isInitData()){ if ((audiodata & 0xF0) == 0xA0){ - metadata["audio"]["init"] = std::string((char*)data+13, (size_t)len-17); + metadata["audio"]["init"] = std::string((char*)data + 13, (size_t)len - 17); }else{ - metadata["audio"]["init"] = std::string((char*)data+12, (size_t)len-16); + metadata["audio"]["init"] = std::string((char*)data + 12, (size_t)len - 16); } - return pack_out;//skip rest of parsing, get next tag. + return pack_out; //skip rest of parsing, get next tag. } pack_out["datatype"] = "audio"; pack_out["time"] = tagTime(); - if (!metadata["audio"].isMember("codec") || metadata["audio"]["size"].asString() == ""){ + if ( !metadata["audio"].isMember("codec") || metadata["audio"]["size"].asString() == ""){ switch (audiodata & 0xF0){ - case 0x20: metadata["audio"]["codec"] = "MP3"; break; - case 0xA0: metadata["audio"]["codec"] = "AAC"; break; + case 0x20: + metadata["audio"]["codec"] = "MP3"; + break; + case 0xA0: + metadata["audio"]["codec"] = "AAC"; + break; } } - if (!metadata["audio"].isMember("rate") || metadata["audio"]["rate"].asInt() < 1){ + if ( !metadata["audio"].isMember("rate") || metadata["audio"]["rate"].asInt() < 1){ switch (audiodata & 0x0C){ - case 0x0: metadata["audio"]["rate"] = 5512; break; - case 0x4: metadata["audio"]["rate"] = 11025; break; - case 0x8: metadata["audio"]["rate"] = 22050; break; - case 0xC: metadata["audio"]["rate"] = 44100; break; + case 0x0: + metadata["audio"]["rate"] = 5512; + break; + case 0x4: + metadata["audio"]["rate"] = 11025; + break; + case 0x8: + metadata["audio"]["rate"] = 22050; + break; + case 0xC: + metadata["audio"]["rate"] = 44100; + break; } } - if (!metadata["audio"].isMember("size") || metadata["audio"]["size"].asInt() < 1){ + if ( !metadata["audio"].isMember("size") || metadata["audio"]["size"].asInt() < 1){ switch (audiodata & 0x02){ - case 0x0: metadata["audio"]["size"] = 8; break; - case 0x2: metadata["audio"]["size"] = 16; break; + case 0x0: + metadata["audio"]["size"] = 8; + break; + case 0x2: + metadata["audio"]["size"] = 16; + break; } } - if (!metadata["audio"].isMember("channels") || metadata["audio"]["channels"].asInt() < 1){ + if ( !metadata["audio"].isMember("channels") || metadata["audio"]["channels"].asInt() < 1){ switch (audiodata & 0x01){ - case 0x0: metadata["audio"]["channels"] = 1; break; - case 0x1: metadata["audio"]["channels"] = 2; break; + case 0x0: + metadata["audio"]["channels"] = 1; + break; + case 0x1: + metadata["audio"]["channels"] = 2; + break; } } if ((audiodata & 0xF0) == 0xA0){ - if (len < 18){return JSON::Value();} - pack_out["data"] = std::string((char*)data+13, (size_t)len-17); + if (len < 18){ + return JSON::Value(); + } + pack_out["data"] = std::string((char*)data + 13, (size_t)len - 17); }else{ - if (len < 17){return JSON::Value();} - pack_out["data"] = std::string((char*)data+12, (size_t)len-16); + if (len < 17){ + return JSON::Value(); + } + pack_out["data"] = std::string((char*)data + 12, (size_t)len - 16); } return pack_out; } @@ -876,45 +1118,73 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){ char videodata = data[11]; if (needsInitData() && isInitData()){ if ((videodata & 0x0F) == 7){ - if (len < 21){return JSON::Value();} - metadata["video"]["init"] = std::string((char*)data+16, (size_t)len-20); + if (len < 21){ + return JSON::Value(); + } + metadata["video"]["init"] = std::string((char*)data + 16, (size_t)len - 20); }else{ - if (len < 17){return JSON::Value();} - metadata["video"]["init"] = std::string((char*)data+12, (size_t)len-16); + if (len < 17){ + return JSON::Value(); + } + metadata["video"]["init"] = std::string((char*)data + 12, (size_t)len - 16); } - return pack_out;//skip rest of parsing, get next tag. + return pack_out; //skip rest of parsing, get next tag. } - if (!metadata["video"].isMember("codec") || metadata["video"]["codec"].asString() == ""){ + if ( !metadata["video"].isMember("codec") || metadata["video"]["codec"].asString() == ""){ switch (videodata & 0x0F){ - case 2: metadata["video"]["codec"] = "H263"; break; - case 4: metadata["video"]["codec"] = "VP6"; break; - case 7: metadata["video"]["codec"] = "H264"; break; + case 2: + metadata["video"]["codec"] = "H263"; + break; + case 4: + metadata["video"]["codec"] = "VP6"; + break; + case 7: + metadata["video"]["codec"] = "H264"; + break; } } pack_out["datatype"] = "video"; switch (videodata & 0xF0){ - case 0x10: pack_out["keyframe"] = 1; break; - case 0x20: pack_out["interframe"] = 1; break; - case 0x30: pack_out["disposableframe"] = 1; break; - case 0x40: pack_out["keyframe"] = 1; break; - case 0x50: return JSON::Value(); break;//the video info byte we just throw away - useless to us... + case 0x10: + pack_out["keyframe"] = 1; + break; + case 0x20: + pack_out["interframe"] = 1; + break; + case 0x30: + pack_out["disposableframe"] = 1; + break; + case 0x40: + pack_out["keyframe"] = 1; + break; + case 0x50: + return JSON::Value(); + break; //the video info byte we just throw away - useless to us... } pack_out["time"] = tagTime(); if ((videodata & 0x0F) == 7){ switch (data[12]){ - case 1: pack_out["nalu"] = 1; break; - case 2: pack_out["nalu_end"] = 1; break; + case 1: + pack_out["nalu"] = 1; + break; + case 2: + pack_out["nalu_end"] = 1; + break; } int offset = (data[13] << 16) + (data[14] << 8) + data[15]; offset = (offset << 8) >> 8; pack_out["offset"] = offset; - if (len < 21){return JSON::Value();} - pack_out["data"] = std::string((char*)data+16, (size_t)len-20); + if (len < 21){ + return JSON::Value(); + } + pack_out["data"] = std::string((char*)data + 16, (size_t)len - 20); }else{ - if (len < 17){return JSON::Value();} - pack_out["data"] = std::string((char*)data+12, (size_t)len-16); + if (len < 17){ + return JSON::Value(); + } + pack_out["data"] = std::string((char*)data + 12, (size_t)len - 16); } return pack_out; } - return pack_out;//should never get here -}//FLV::Tag::toJSON + return pack_out; //should never get here +} //FLV::Tag::toJSON diff --git a/lib/flv_tag.h b/lib/flv_tag.h index 8de48eb5..b4bb5198 100644 --- a/lib/flv_tag.h +++ b/lib/flv_tag.h @@ -7,10 +7,11 @@ #include "json.h" #include + //forward declaration of RTMPStream::Chunk to avoid circular dependencies. -namespace RTMPStream{ +namespace RTMPStream { class Chunk; -}; +} /// This namespace holds all FLV-parsing related functionality. namespace FLV { @@ -24,7 +25,7 @@ namespace FLV { bool is_header(char * header); ///< Checks the first 3 bytes for the string "FLV". /// This class is used to hold, work with and get information about a single FLV tag. - class Tag { + class Tag{ public: int len; ///< Actual length of tag. bool isKeyframe; ///< True if current tag is a video keyframe. @@ -36,7 +37,7 @@ namespace FLV { void tagTime(unsigned int T); ///< Sets the 32-bit timestamp of this tag. Tag(); ///< Constructor for a new, empty, tag. Tag(const Tag& O); ///< Copy constructor, copies the contents of an existing tag. - Tag & operator= (const Tag& O); ///< Assignment operator - works exactly like the copy constructor. + Tag & operator=(const Tag& O); ///< Assignment operator - works exactly like the copy constructor. Tag(const RTMPStream::Chunk& O); /// Credentials ) { +FTP::User::User(Socket::Connection NewConnection, std::map Credentials){ Conn = NewConnection; + MyPassivePort = 0; USER = ""; PASS = ""; MODE = MODE_STREAM; @@ -10,78 +11,150 @@ FTP::User::User( Socket::Connection NewConnection, std::map 1 ) { - if( Command[1] != ' ' ) { return 501; }//Syntax error in parameters or arguments. - if( Command[2] != 'N' ) { return 504; }//Command not implemented for that parameter. + if (Command.size() > 1){ + if (Command[1] != ' '){ + return 501; + } //Syntax error in parameters or arguments. + if (Command[2] != 'N'){ + return 504; + } //Command not implemented for that parameter. } TYPE = TYPE_ASCII_NONPRINT; break; } case 'I': { - if( Command.size() > 1 ) { - if( Command[1] != ' ' ) { return 501; }//Syntax error in parameters or arguments. - if( Command[2] != 'N' ) { return 504; }//Command not implemented for that parameter. + if (Command.size() > 1){ + if (Command[1] != ' '){ + return 501; + } //Syntax error in parameters or arguments. + if (Command[2] != 'N'){ + return 504; + } //Command not implemented for that parameter. } TYPE = TYPE_IMAGE_NONPRINT; break; } default: { - return 504;//Command not implemented for that parameter. + return 504; //Command not implemented for that parameter. break; } } - return 200;//Command okay. + return 200; //Command okay. break; } case CMD_MODE: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. - if( Command == "" ) { return 501; }//Syntax error in parameters or arguments. - if( Command.size() != 1 ) { return 501; }//Syntax error in parameters or arguments. - if( Command[0] != 'S' ) { return 504; }//Command not implemented for that parameter. + if ( !LoggedIn()){ + return 530; + } //Not logged in. + if (Command == ""){ + return 501; + } //Syntax error in parameters or arguments. + if (Command.size() != 1){ + return 501; + } //Syntax error in parameters or arguments. + if (Command[0] != 'S'){ + return 504; + } //Command not implemented for that parameter. MODE = MODE_STREAM; - return 200;//Command okay. + return 200; //Command okay. break; } case CMD_STRU: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. - if( Command == "" ) { return 501; }//Syntax error in parameters or arguments. - if( Command.size() != 1 ) { return 501; }//Syntax error in parameters or arguments. - switch( Command[0] ) { + if ( !LoggedIn()){ + return 530; + } //Not logged in. + if (Command == ""){ + return 501; + } //Syntax error in parameters or arguments. + if (Command.size() != 1){ + return 501; + } //Syntax error in parameters or arguments. + switch (Command[0]){ case 'F': { STRU = STRU_FILE; break; @@ -227,24 +349,30 @@ int FTP::User::ParseCommand( std::string Command ) { break; } default: { - return 504;//Command not implemented for that parameter. + return 504; //Command not implemented for that parameter. break; } } - return 200;//Command okay. + return 200; //Command okay. break; } case CMD_PWD: { - if( !LoggedIn( ) ) { return 550; }//Not logged in. - if( Command != "" ) { return 501; }//Syntax error in parameters or arguments. - return 2570;//257 -- 0 to indicate PWD over MKD + if ( !LoggedIn()){ + return 550; + } //Not logged in. + if (Command != ""){ + return 501; + } //Syntax error in parameters or arguments. + return 2570; //257 -- 0 to indicate PWD over MKD break; } case CMD_CWD: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. + if ( !LoggedIn()){ + return 530; + } //Not logged in. Filesystem::Directory TmpDir = MyDir; - if( TmpDir.CWD( Command ) ) { - if( TmpDir.IsDir( ) ) { + if (TmpDir.CWD(Command)){ + if (TmpDir.IsDir()){ MyDir = TmpDir; return 250; } @@ -253,11 +381,15 @@ int FTP::User::ParseCommand( std::string Command ) { break; } case CMD_CDUP: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. - if( Command != "" ) { return 501; }//Syntax error in parameters or arguments. + if ( !LoggedIn()){ + return 530; + } //Not logged in. + if (Command != ""){ + return 501; + } //Syntax error in parameters or arguments. Filesystem::Directory TmpDir = MyDir; - if( TmpDir.CDUP( ) ) { - if( TmpDir.IsDir( ) ) { + if (TmpDir.CDUP()){ + if (TmpDir.IsDir()){ MyDir = TmpDir; return 250; } @@ -266,62 +398,98 @@ int FTP::User::ParseCommand( std::string Command ) { break; } case CMD_DELE: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. - if( Command == "" ) { return 501; }//Syntax error in parameters or arguments. - if( !MyDir.DELE( Command ) ) { return 550; } + if ( !LoggedIn()){ + return 530; + } //Not logged in. + if (Command == ""){ + return 501; + } //Syntax error in parameters or arguments. + if ( !MyDir.DELE(Command)){ + return 550; + } return 250; break; } case CMD_RMD: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. - if( Command == "" ) { return 501; }//Syntax error in parameters or arguments. - if( !MyDir.HasPermission( Filesystem::P_RMD ) ) { return 550; } - if( !MyDir.DELE( Command ) ) { return 550; } + if ( !LoggedIn()){ + return 530; + } //Not logged in. + if (Command == ""){ + return 501; + } //Syntax error in parameters or arguments. + if ( !MyDir.HasPermission(Filesystem::P_RMD)){ + return 550; + } + if ( !MyDir.DELE(Command)){ + return 550; + } return 250; break; } case CMD_MKD: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. - if( Command == "" ) { return 501; }//Syntax error in parameters or arguments. - if( !MyDir.HasPermission( Filesystem::P_MKD ) ) { return 550; } - if( !MyDir.MKD( Command ) ) { return 550; } + if ( !LoggedIn()){ + return 530; + } //Not logged in. + if (Command == ""){ + return 501; + } //Syntax error in parameters or arguments. + if ( !MyDir.HasPermission(Filesystem::P_MKD)){ + return 550; + } + if ( !MyDir.MKD(Command)){ + return 550; + } return 2571; break; } case CMD_RNFR: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. - if( Command == "" ) { return 501; }//Syntax error in parameters or arguments. + if ( !LoggedIn()){ + return 530; + } //Not logged in. + if (Command == ""){ + return 501; + } //Syntax error in parameters or arguments. RNFR = Command; - return 350;//Awaiting further information + return 350; //Awaiting further information } case CMD_RNTO: { - if( !LoggedIn( ) ) { return 530; }//Not logged in. - if( Command == "" ) { return 501; }//Syntax error in parameters or arguments. - if( RNFR == "" ) { return 503; } //Bad sequence of commands - if( !MyDir.Rename( RNFR, Command ) ) { return 550; } + if ( !LoggedIn()){ + return 530; + } //Not logged in. + if (Command == ""){ + return 501; + } //Syntax error in parameters or arguments. + if (RNFR == ""){ + return 503; + } //Bad sequence of commands + if ( !MyDir.Rename(RNFR, Command)){ + return 550; + } return 250; } default: { - return 502;//Command not implemented. + return 502; //Command not implemented. break; } } } -bool FTP::User::LoggedIn( ) { - if( USER == "" || PASS == "" ) { return false; } - if( !AllCredentials.size() ) { +bool FTP::User::LoggedIn(){ + if (USER == "" || PASS == ""){ + return false; + } + if ( !AllCredentials.size()){ return true; } - if( ( AllCredentials.find( USER ) != AllCredentials.end() ) && AllCredentials[USER] == PASS ) { + if ((AllCredentials.find(USER) != AllCredentials.end()) && AllCredentials[USER] == PASS){ return true; } return false; } -std::string FTP::User::NumToMsg( int MsgNum ) { +std::string FTP::User::NumToMsg(int MsgNum){ std::string Result; - switch( MsgNum ) { + switch (MsgNum){ case 200: { Result = "200 Message okay.\n"; break; @@ -335,15 +503,15 @@ std::string FTP::User::NumToMsg( int MsgNum ) { break; } case 227: { - std::stringstream sstr; + std::stringstream sstr; sstr << "227 Entering passive mode (0,0,0,0,"; sstr << (MyPassivePort >> 8) % 256; sstr << ","; sstr << MyPassivePort % 256; sstr << ").\n"; Result = sstr.str(); - break; - } + break; + } case 229: { std::stringstream sstr; sstr << "229 Entering extended passive mode (|||"; @@ -360,12 +528,12 @@ std::string FTP::User::NumToMsg( int MsgNum ) { Result = "250 Requested file action okay, completed.\n"; break; } - case 2570: {//PWD - Result = "257 \"" + MyDir.PWD( ) + "\" selected as PWD\n"; + case 2570: { //PWD + Result = "257 \"" + MyDir.PWD() + "\" selected as PWD\n"; break; } - case 2571: {//MKD - Result = "257 \"" + MyDir.PWD( ) + "\" created\n"; + case 2571: { //MKD + Result = "257 \"" + MyDir.PWD() + "\" created\n"; break; } case 331: { diff --git a/lib/ftp.h b/lib/ftp.h index fb5b35d2..2c2e59bd 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -13,22 +13,23 @@ namespace FTP { static std::string FTPBasePath = "/tmp/mist/OnDemand/"; - - enum Mode { + + enum Mode{ MODE_STREAM, - };//FTP::Mode enumeration - - enum Structure { - STRU_FILE, - STRU_RECORD, - };//FTP::Structure enumeration - - enum Type { - TYPE_ASCII_NONPRINT, - TYPE_IMAGE_NONPRINT, - };//FTP::Type enumeration - - enum Commands { + }; + //FTP::Mode enumeration + + enum Structure{ + STRU_FILE, STRU_RECORD, + }; + //FTP::Structure enumeration + + enum Type{ + TYPE_ASCII_NONPRINT, TYPE_IMAGE_NONPRINT, + }; + //FTP::Type enumeration + + enum Commands{ CMD_NOCMD, CMD_NOOP, CMD_USER, @@ -51,18 +52,19 @@ namespace FTP { CMD_MKD, CMD_RNFR, CMD_RNTO, - };//FTP::Commands enumeration - - class User { + }; + //FTP::Commands enumeration + + class User{ public: - User( Socket::Connection NewConnection, std::map Credentials); - ~User( ); - int ParseCommand( std::string Command ); - bool LoggedIn( ); - std::string NumToMsg( int MsgNum ); + User(Socket::Connection NewConnection, std::map Credentials); + ~User(); + int ParseCommand(std::string Command); + bool LoggedIn(); + std::string NumToMsg(int MsgNum); Socket::Connection Conn; private: - std::map AllCredentials; + std::map AllCredentials; std::string USER; std::string PASS; Mode MODE; @@ -73,7 +75,8 @@ namespace FTP { int MyPassivePort; Filesystem::Directory MyDir; std::string RNFR; - std::vector< std::string > ActiveStreams; - };//FTP::User class - -};//FTP Namespace + std::vector ActiveStreams; + }; +//FTP::User class + +}//FTP Namespace diff --git a/lib/http_parser.cpp b/lib/http_parser.cpp index a3144b10..2f8ebb72 100644 --- a/lib/http_parser.cpp +++ b/lib/http_parser.cpp @@ -5,7 +5,9 @@ /// This constructor creates an empty HTTP::Parser, ready for use for either reading or writing. /// All this constructor does is call HTTP::Parser::Clean(). -HTTP::Parser::Parser(){Clean();} +HTTP::Parser::Parser(){ + Clean(); +} /// Completely re-initializes the HTTP::Parser, leaving it ready for either reading or writing usage. void HTTP::Parser::Clean(){ @@ -27,11 +29,13 @@ void HTTP::Parser::Clean(){ std::string & HTTP::Parser::BuildRequest(){ /// \todo Include GET/POST variable parsing? std::map::iterator it; - if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){protocol = "HTTP/1.0";} - builder = method+" "+url+" "+protocol+"\r\n"; - for (it=headers.begin(); it != headers.end(); it++){ - if ((*it).first != "" && (*it).second != ""){ - builder += (*it).first + ": " + (*it).second + "\r\n"; + if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){ + protocol = "HTTP/1.0"; + } + builder = method + " " + url + " " + protocol + "\r\n"; + for (it = headers.begin(); it != headers.end(); it++){ + if (( *it).first != "" && ( *it).second != ""){ + builder += ( *it).first + ": " + ( *it).second + "\r\n"; } } builder += "\r\n" + body; @@ -47,12 +51,14 @@ std::string & HTTP::Parser::BuildRequest(){ std::string & HTTP::Parser::BuildResponse(std::string code, std::string message){ /// \todo Include GET/POST variable parsing? std::map::iterator it; - if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){protocol = "HTTP/1.0";} - builder = protocol+" "+code+" "+message+"\r\n"; - for (it=headers.begin(); it != headers.end(); it++){ - if ((*it).first != "" && (*it).second != ""){ - if ((*it).first != "Content-Length" || (*it).second != "0"){ - builder += (*it).first + ": " + (*it).second + "\r\n"; + if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){ + protocol = "HTTP/1.0"; + } + builder = protocol + " " + code + " " + message + "\r\n"; + for (it = headers.begin(); it != headers.end(); it++){ + if (( *it).first != "" && ( *it).second != ""){ + if (( *it).first != "Content-Length" || ( *it).second != "0"){ + builder += ( *it).first + ": " + ( *it).second + "\r\n"; } } } @@ -67,7 +73,11 @@ std::string & HTTP::Parser::BuildResponse(std::string code, std::string message) void HTTP::Parser::Trim(std::string & s){ size_t startpos = s.find_first_not_of(" \t"); size_t endpos = s.find_last_not_of(" \t"); - if ((std::string::npos == startpos) || (std::string::npos == endpos)){s = "";}else{s = s.substr(startpos, endpos-startpos+1);} + if ((std::string::npos == startpos) || (std::string::npos == endpos)){ + s = ""; + }else{ + s = s.substr(startpos, endpos - startpos + 1); + } } /// Function that sets the body of a response or request, along with the correct Content-Length header. @@ -96,9 +106,13 @@ std::string HTTP::Parser::getUrl(){ } /// Returns header i, if set. -std::string HTTP::Parser::GetHeader(std::string i){return headers[i];} +std::string HTTP::Parser::GetHeader(std::string i){ + return headers[i]; +} /// Returns POST variable i, if set. -std::string HTTP::Parser::GetVar(std::string i){return vars[i];} +std::string HTTP::Parser::GetVar(std::string i){ + return vars[i]; +} /// Sets header i to string value v. void HTTP::Parser::SetHeader(std::string i, std::string v){ @@ -110,7 +124,7 @@ void HTTP::Parser::SetHeader(std::string i, std::string v){ /// Sets header i to integer value v. void HTTP::Parser::SetHeader(std::string i, int v){ Trim(i); - char val[23];//ints are never bigger than 22 chars as decimal + char val[23]; //ints are never bigger than 22 chars as decimal sprintf(val, "%i", v); headers[i] = val; } @@ -120,7 +134,7 @@ void HTTP::Parser::SetVar(std::string i, std::string v){ Trim(i); Trim(v); //only set if there is actually a key - if(!i.empty()){ + if ( !i.empty()){ vars[i] = v; } } @@ -131,7 +145,7 @@ void HTTP::Parser::SetVar(std::string i, std::string v){ /// \return True if a whole request or response was read, false otherwise. bool HTTP::Parser::Read(std::string & strbuf){ return parse(strbuf); -}//HTTPReader::Read +} //HTTPReader::Read #include /// Attempt to read a whole HTTP response or request from a data buffer. @@ -143,44 +157,54 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){ size_t f; std::string tmpA, tmpB, tmpC; /// \todo Make this not resize HTTPbuffer in parts, but read all at once and then remove the entire request, like doxygen claims it does? - while (!HTTPbuffer.empty()){ - if (!seenHeaders){ + while ( !HTTPbuffer.empty()){ + if ( !seenHeaders){ f = HTTPbuffer.find('\n'); if (f == std::string::npos) return false; tmpA = HTTPbuffer.substr(0, f); - if (f+1 == HTTPbuffer.size()){ + if (f + 1 == HTTPbuffer.size()){ HTTPbuffer.clear(); }else{ - HTTPbuffer.erase(0, f+1); + HTTPbuffer.erase(0, f + 1); } - while (tmpA.find('\r') != std::string::npos){tmpA.erase(tmpA.find('\r'));} - if (!seenReq){ + while (tmpA.find('\r') != std::string::npos){ + tmpA.erase(tmpA.find('\r')); + } + if ( !seenReq){ seenReq = true; f = tmpA.find(' '); if (f != std::string::npos){ - method = tmpA.substr(0, f); tmpA.erase(0, f+1); + method = tmpA.substr(0, f); + tmpA.erase(0, f + 1); f = tmpA.find(' '); if (f != std::string::npos){ - url = tmpA.substr(0, f); tmpA.erase(0, f+1); + url = tmpA.substr(0, f); + tmpA.erase(0, f + 1); protocol = tmpA; if (url.find('?') != std::string::npos){ - parseVars(url.substr(url.find('?')+1)); //parse GET variables + parseVars(url.substr(url.find('?') + 1)); //parse GET variables } - }else{seenReq = false;} - }else{seenReq = false;} + }else{ + seenReq = false; + } + }else{ + seenReq = false; + } }else{ if (tmpA.size() == 0){ seenHeaders = true; body.clear(); if (GetHeader("Content-Length") != ""){ length = atoi(GetHeader("Content-Length").c_str()); - if (body.capacity() < length){body.reserve(length);} + if (body.capacity() < length){ + body.reserve(length); + } } }else{ f = tmpA.find(':'); if (f == std::string::npos) continue; tmpB = tmpA.substr(0, f); - tmpC = tmpA.substr(f+1); + tmpC = tmpA.substr(f + 1); SetHeader(tmpB, tmpC); } } @@ -204,7 +228,7 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){ } } return false; //empty input -}//HTTPReader::parse +} //HTTPReader::parse /// Parses GET or POST-style variable data. /// Saves to internal variable structure using HTTP::Parser::SetVar. @@ -266,8 +290,12 @@ std::string HTTP::Parser::urlunescape(const std::string & in){ tmp += unhex(in[i]); } out += tmp; - } else { - if (in[i] == '+'){out += ' ';}else{out += in[i];} + }else{ + if (in[i] == '+'){ + out += ' '; + }else{ + out += in[i]; + } } } return out; @@ -276,15 +304,16 @@ std::string HTTP::Parser::urlunescape(const std::string & in){ /// Helper function for urlunescape. /// Takes a single char input and outputs its integer hex value. int HTTP::Parser::unhex(char c){ - return( c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10 ); + return (c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10); } /// URLencodes std::string data. std::string HTTP::Parser::urlencode(const std::string &c){ - std::string escaped=""; + std::string escaped = ""; int max = c.length(); - for(int i=0; i>4; - char dig2 = (dec&0x0F); - if (dig1<= 9) dig1+=48; - if (10<= dig1 && dig1<=15) dig1+=97-10; - if (dig2<= 9) dig2+=48; - if (10<= dig2 && dig2<=15) dig2+=97-10; + char dig1 = (dec & 0xF0) >> 4; + char dig2 = (dec & 0x0F); + if (dig1 <= 9) dig1 += 48; + if (10 <= dig1 && dig1 <= 15) dig1 += 97 - 10; + if (dig2 <= 9) dig2 += 48; + if (10 <= dig2 && dig2 <= 15) dig2 += 97 - 10; std::string r; - r.append(&dig1, 1); - r.append(&dig2, 1); + r.append( &dig1, 1); + r.append( &dig2, 1); return r; } diff --git a/lib/http_parser.h b/lib/http_parser.h index ae235a2e..77b12aed 100644 --- a/lib/http_parser.h +++ b/lib/http_parser.h @@ -8,7 +8,7 @@ #include /// Holds all HTTP processing related code. -namespace HTTP{ +namespace HTTP { /// Simple class for reading and writing HTTP 1.0 and 1.1. class Parser{ public: @@ -45,5 +45,7 @@ namespace HTTP{ void Trim(std::string & s); static int unhex(char c); static std::string hex(char dec); - };//HTTP::Parser class -};//HTTP namespace + }; +//HTTP::Parser class + +}//HTTP namespace diff --git a/lib/json.cpp b/lib/json.cpp index c7a0557f..68596e90 100644 --- a/lib/json.cpp +++ b/lib/json.cpp @@ -7,7 +7,6 @@ #include //for uint64_t #include //for memcpy #include //for htonl - int JSON::Value::c2hex(int c){ if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; @@ -15,7 +14,6 @@ int JSON::Value::c2hex(int c){ return 0; } - std::string JSON::Value::read_string(int separator, std::istream & fromstream){ std::string out; bool escaped = false; @@ -27,17 +25,28 @@ std::string JSON::Value::read_string(int separator, std::istream & fromstream){ } if (escaped){ switch (c){ - case 'b': out += '\b'; break; - case 'f': out += '\f'; break; - case 'n': out += '\n'; break; - case 'r': out += '\r'; break; - case 't': out += '\t'; break; - case 'u':{ - int d1 = fromstream.get(); - int d2 = fromstream.get(); - int d3 = fromstream.get(); - int d4 = fromstream.get(); - c = c2hex(d4) + (c2hex(d3) << 4) + (c2hex(d2) << 8) + (c2hex(d1) << 16); + case 'b': + out += '\b'; + break; + case 'f': + out += '\f'; + break; + case 'n': + out += '\n'; + break; + case 'r': + out += '\r'; + break; + case 't': + out += '\t'; + break; + case 'u': { + int d1 = fromstream.get(); + int d2 = fromstream.get(); + int d3 = fromstream.get(); + int d4 = fromstream.get(); + c = c2hex(d4) + (c2hex(d3) << 4) + (c2hex(d2) << 8) + (c2hex(d1) << 16); + break; } default: out += (char)c; @@ -58,14 +67,30 @@ std::string JSON::Value::string_escape(std::string val){ std::string out = "\""; for (unsigned int i = 0; i < val.size(); ++i){ switch (val[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: out += val[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: + out += val[i]; + break; } } out += "\""; @@ -76,9 +101,15 @@ std::string JSON::Value::string_escape(std::string val){ void JSON::Value::skipToEnd(std::istream & fromstream){ while (fromstream.good()){ char peek = fromstream.peek(); - if (peek == ','){return;} - if (peek == ']'){return;} - if (peek == '}'){return;} + if (peek == ','){ + return; + } + if (peek == ']'){ + return; + } + if (peek == '}'){ + return; + } peek = fromstream.get(); } } @@ -101,7 +132,7 @@ JSON::Value::Value(std::istream & fromstream){ c = fromstream.get(); myType = OBJECT; break; - case '[':{ + case '[': { reading_array = true; c = fromstream.get(); myType = ARRAY; @@ -114,13 +145,13 @@ JSON::Value::Value(std::istream & fromstream){ case '\'': case '"': c = fromstream.get(); - if (!reading_object){ + if ( !reading_object){ myType = STRING; strVal = read_string(c, fromstream); return; }else{ std::string tmpstr = read_string(c, fromstream); - (*this)[tmpstr] = JSON::Value(fromstream); + ( *this)[tmpstr] = JSON::Value(fromstream); } break; case '0': @@ -139,18 +170,22 @@ JSON::Value::Value(std::istream & fromstream){ intVal += c - '0'; break; case ',': - if (!reading_object && !reading_array) return; + if ( !reading_object && !reading_array) return; c = fromstream.get(); if (reading_array){ append(JSON::Value(fromstream)); } break; case '}': - if (reading_object){c = fromstream.get();} + if (reading_object){ + c = fromstream.get(); + } return; break; case ']': - if (reading_array){c = fromstream.get();} + if (reading_array){ + c = fromstream.get(); + } return; break; case 't': @@ -174,7 +209,7 @@ JSON::Value::Value(std::istream & fromstream){ return; break; default: - c = fromstream.get();//ignore this character + c = fromstream.get(); //ignore this character continue; break; } @@ -185,12 +220,14 @@ JSON::Value::Value(std::istream & fromstream){ JSON::Value::Value(const std::string & val){ myType = STRING; strVal = val; + intVal = 0; } /// Sets this JSON::Value to the given string. JSON::Value::Value(const char * val){ myType = STRING; strVal = val; + intVal = 0; } /// Sets this JSON::Value to the given integer. @@ -202,14 +239,24 @@ JSON::Value::Value(long long int val){ /// Compares a JSON::Value to another for equality. bool JSON::Value::operator==(const JSON::Value & rhs) const{ if (myType != rhs.myType) return false; - if (myType == INTEGER || myType == BOOL){return intVal == rhs.intVal;} - if (myType == STRING){return strVal == rhs.strVal;} - if (myType == EMPTY){return true;} + if (myType == INTEGER || myType == BOOL){ + return intVal == rhs.intVal; + } + if (myType == STRING){ + return strVal == rhs.strVal; + } + if (myType == EMPTY){ + return true; + } if (myType == OBJECT){ if (objVal.size() != rhs.objVal.size()) return false; for (std::map::const_iterator it = objVal.begin(); it != objVal.end(); ++it){ - if (!rhs.isMember(it->first)){return false;} - if (it->second != rhs.objVal.find(it->first)->second){return false;} + if ( !rhs.isMember(it->first)){ + return false; + } + if (it->second != rhs.objVal.find(it->first)->second){ + return false; + } } return true; } @@ -217,7 +264,9 @@ bool JSON::Value::operator==(const JSON::Value & rhs) const{ if (arrVal.size() != rhs.arrVal.size()) return false; int i = 0; for (std::deque::const_iterator it = arrVal.begin(); it != arrVal.end(); ++it){ - if (*it != rhs.arrVal[i]){return false;} + if ( *it != rhs.arrVal[i]){ + return false; + } i++; } return true; @@ -227,7 +276,7 @@ bool JSON::Value::operator==(const JSON::Value & rhs) const{ /// Compares a JSON::Value to another for equality. bool JSON::Value::operator!=(const JSON::Value & rhs) const{ - return !((*this) == rhs); + return !(( *this) == rhs); } /// Sets this JSON::Value to the given boolean. @@ -248,7 +297,7 @@ JSON::Value & JSON::Value::operator=(const std::string &rhs){ /// Sets this JSON::Value to the given string. JSON::Value & JSON::Value::operator=(const char * rhs){ - return ((*this) = (std::string)rhs); + return (( *this) = (std::string)rhs); } /// Sets this JSON::Value to the given integer. @@ -261,12 +310,12 @@ JSON::Value & JSON::Value::operator=(const long long int &rhs){ /// Sets this JSON::Value to the given integer. JSON::Value & JSON::Value::operator=(const int &rhs){ - return ((*this) = (long long int)rhs); + return (( *this) = (long long int)rhs); } /// Sets this JSON::Value to the given integer. JSON::Value & JSON::Value::operator=(const unsigned int &rhs){ - return ((*this) = (long long int)rhs); + return (( *this) = (long long int)rhs); } /// Automatic conversion to long long int - returns 0 if not convertable. @@ -280,7 +329,6 @@ JSON::Value::operator long long int(){ return 0; } - /// Automatic conversion to std::string. /// Returns the raw string value if available, otherwise calls toString(). JSON::Value::operator std::string(){ @@ -298,29 +346,40 @@ JSON::Value::operator std::string(){ /// Automatic conversion to bool. /// Returns true if there is anything meaningful stored into this value. JSON::Value::operator bool(){ - if (myType == STRING){return strVal != "";} - if (myType == INTEGER){return intVal != 0;} - if (myType == BOOL){return intVal != 0;} - if (myType == OBJECT){return size() > 0;} - if (myType == ARRAY){return size() > 0;} - if (myType == EMPTY){return false;} - return false;//unimplemented? should never happen... + if (myType == STRING){ + return strVal != ""; + } + if (myType == INTEGER){ + return intVal != 0; + } + if (myType == BOOL){ + return intVal != 0; + } + if (myType == OBJECT){ + return size() > 0; + } + if (myType == ARRAY){ + return size() > 0; + } + if (myType == EMPTY){ + return false; + } + return false; //unimplemented? should never happen... } /// Explicit conversion to std::string. const std::string JSON::Value::asString(){ - return (std::string)*this; + return (std::string) *this; } /// Explicit conversion to long long int. const long long int JSON::Value::asInt(){ - return (long long int)*this; + return (long long int) *this; } /// Explicit conversion to bool. const bool JSON::Value::asBool(){ - return (bool)*this; + return (bool) *this; } - /// Retrieves or sets the JSON::Value at this position in the object. /// Converts destructively to object if not already an object. JSON::Value & JSON::Value::operator[](const std::string i){ @@ -362,15 +421,19 @@ std::string JSON::Value::toPacked(){ if (isInt() || isNull() || isBool()){ r += 0x01; uint64_t numval = intVal; - r += *(((char*)&numval)+7); r += *(((char*)&numval)+6); - r += *(((char*)&numval)+5); r += *(((char*)&numval)+4); - r += *(((char*)&numval)+3); r += *(((char*)&numval)+2); - r += *(((char*)&numval)+1); r += *(((char*)&numval)); + r += *(((char*) &numval) + 7); + r += *(((char*) &numval) + 6); + r += *(((char*) &numval) + 5); + r += *(((char*) &numval) + 4); + r += *(((char*) &numval) + 3); + r += *(((char*) &numval) + 2); + r += *(((char*) &numval) + 1); + r += *(((char*) &numval)); } if (isString()){ r += 0x02; - r += strVal.size() / (256*256*256); - r += strVal.size() / (256*256); + r += strVal.size() / (256 * 256 * 256); + r += strVal.size() / (256 * 256); r += strVal.size() / 256; r += strVal.size() % 256; r += strVal; @@ -385,7 +448,9 @@ std::string JSON::Value::toPacked(){ r += it->second.toPacked(); } } - r += (char)0x0; r += (char)0x0; r += (char)0xEE; + r += (char)0x0; + r += (char)0x0; + r += (char)0xEE; strVal.clear(); } if (isArray()){ @@ -393,11 +458,14 @@ std::string JSON::Value::toPacked(){ for (JSON::ArrIter it = arrVal.begin(); it != arrVal.end(); it++){ r += it->toPacked(); } - r += (char)0x0; r += (char)0x0; r += (char)0xEE; + r += (char)0x0; + r += (char)0x0; + r += (char)0xEE; } return r; -};//toPacked - +} +; +//toPacked /// Packs any object-type JSON::Value to a std::string for transfer over the network, including proper DTMI header. /// Non-object-types will print an error to stderr and return an empty string. @@ -422,14 +490,13 @@ std::string & JSON::Value::toNetPacked(){ } //insert the packet length at bytes 4-7 unsigned int size = htonl(packed.size()); - memcpy((void*)(strVal.c_str() + 4), (void*)&size, 4); + memcpy((void*)(strVal.c_str() + 4), (void*) &size, 4); //copy the rest of the string memcpy((void*)(strVal.c_str() + 8), packed.c_str(), packed.size()); } return strVal; } - /// Converts this JSON::Value to valid JSON notation and returns it. /// Makes absolutely no attempts to pretty-print anything. :-) std::string JSON::Value::toString(){ @@ -449,7 +516,9 @@ std::string JSON::Value::toString(){ if (arrVal.size() > 0){ for (ArrIter it = ArrBegin(); it != ArrEnd(); it++){ tmp += it->toString(); - if (it + 1 != ArrEnd()){tmp += ",";} + if (it + 1 != ArrEnd()){ + tmp += ","; + } } } tmp += "]"; @@ -464,7 +533,9 @@ std::string JSON::Value::toString(){ for (ObjIter it2 = ObjBegin(); it2 != ObjEnd(); it2++){ tmp2 += "\"" + it2->first + "\":"; tmp2 += it2->second.toString(); - if (it2 != it3){tmp2 += ",";} + if (it2 != it3){ + tmp2 += ","; + } } } tmp2 += "}"; @@ -475,7 +546,7 @@ std::string JSON::Value::toString(){ default: return "null"; } - return "null";//should never get here... + return "null"; //should never get here... } /// Converts this JSON::Value to valid JSON notation and returns it. @@ -491,7 +562,7 @@ std::string JSON::Value::toPrettyString(int indentation){ case STRING: { for (unsigned int i = 0; i < 5 && i < strVal.size(); ++i){ if (strVal[i] < 32 || strVal[i] > 125){ - return JSON::Value((long long int)strVal.size()).asString()+" bytes of binary data"; + return JSON::Value((long long int)strVal.size()).asString() + " bytes of binary data"; } } return string_escape(strVal); @@ -501,10 +572,12 @@ std::string JSON::Value::toPrettyString(int indentation){ if (arrVal.size() > 0){ std::string tmp = "[\n"; for (ArrIter it = ArrBegin(); it != ArrEnd(); it++){ - tmp += std::string(indentation+2, ' ')+it->toPrettyString(indentation+2); - if (it + 1 != ArrEnd()){tmp += ",\n";} + tmp += std::string(indentation + 2, ' ') + it->toPrettyString(indentation + 2); + if (it + 1 != ArrEnd()){ + tmp += ",\n"; + } } - tmp += "\n"+std::string(indentation, ' ')+"]"; + tmp += "\n" + std::string(indentation, ' ') + "]"; return tmp; }else{ return "[]"; @@ -517,11 +590,13 @@ std::string JSON::Value::toPrettyString(int indentation){ ObjIter it3 = ObjEnd(); --it3; for (ObjIter it2 = ObjBegin(); it2 != ObjEnd(); it2++){ - tmp2 += std::string(indentation+2, ' ')+"\"" + it2->first + "\":"; - tmp2 += it2->second.toPrettyString(indentation+2); - if (it2 != it3){tmp2 += ",\n";} + tmp2 += std::string(indentation + 2, ' ') + "\"" + it2->first + "\":"; + tmp2 += it2->second.toPrettyString(indentation + 2); + if (it2 != it3){ + tmp2 += ",\n"; + } } - tmp2 += "\n"+std::string(indentation, ' ')+"}"; + tmp2 += "\n" + std::string(indentation, ' ') + "}"; return tmp2; }else{ return "{}"; @@ -532,7 +607,7 @@ std::string JSON::Value::toPrettyString(int indentation){ default: return "null"; } - return "null";//should never get here... + return "null"; //should never get here... } /// Appends the given value to the end of this JSON::Value array. @@ -563,11 +638,15 @@ void JSON::Value::prepend(const JSON::Value & rhs){ /// given size. void JSON::Value::shrink(unsigned int size){ if (myType == ARRAY){ - while (arrVal.size() > size){arrVal.pop_front();} + while (arrVal.size() > size){ + arrVal.pop_front(); + } return; } if (myType == OBJECT){ - while (objVal.size() > size){objVal.erase(objVal.begin());} + while (objVal.size() > size){ + objVal.erase(objVal.begin()); + } return; } } @@ -671,62 +750,66 @@ JSON::Value JSON::fromFile(std::string filename){ /// \param i Current parsing position in the raw data (defaults to 0). /// \returns A single JSON::Value, parsed from the raw data. JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigned int &i){ - #if DEBUG >= 10 +#if DEBUG >= 10 fprintf(stderr, "Note: AMF type %hhx found. %i bytes left\n", data[i], len-i); - #endif +#endif switch (data[i]){ - case 0x01:{//integer + case 0x01: { //integer unsigned char tmpdbl[8]; - tmpdbl[7] = data[i+1]; - tmpdbl[6] = data[i+2]; - tmpdbl[5] = data[i+3]; - tmpdbl[4] = data[i+4]; - tmpdbl[3] = data[i+5]; - tmpdbl[2] = data[i+6]; - tmpdbl[1] = data[i+7]; - tmpdbl[0] = data[i+8]; - i+=9;//skip 8(an uint64_t)+1 forwards + tmpdbl[7] = data[i + 1]; + tmpdbl[6] = data[i + 2]; + tmpdbl[5] = data[i + 3]; + tmpdbl[4] = data[i + 4]; + tmpdbl[3] = data[i + 5]; + tmpdbl[2] = data[i + 6]; + tmpdbl[1] = data[i + 7]; + tmpdbl[0] = data[i + 8]; + i += 9; //skip 8(an uint64_t)+1 forwards uint64_t * d = (uint64_t*)tmpdbl; - return JSON::Value((long long int)*d); - } break; - case 0x02:{//string - unsigned int tmpi = data[i+1]*256*256*256+data[i+2]*256*256+data[i+3]*256+data[i+4];//set tmpi to UTF-8-long length - std::string tmpstr = std::string((const char *)data+i+5, (size_t)tmpi);//set the string data - i += tmpi + 5;//skip length+size+1 forwards + return JSON::Value((long long int) *d); + } + break; + case 0x02: { //string + unsigned int tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; //set tmpi to UTF-8-long length + std::string tmpstr = std::string((const char *)data + i + 5, (size_t)tmpi); //set the string data + i += tmpi + 5; //skip length+size+1 forwards return JSON::Value(tmpstr); - } break; - case 0xFF://also object - case 0xE0:{//object + } + break; + case 0xFF: //also object + case 0xE0: { //object ++i; JSON::Value ret; - while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x0000EE) - unsigned int tmpi = data[i]*256+data[i+1];//set tmpi to the UTF-8 length - std::string tmpstr = std::string((const char *)data+i+2, (size_t)tmpi);//set the string data - i += tmpi + 2;//skip length+size forwards - ret[tmpstr] = fromDTMI(data, len, i);//add content, recursively parsed, updating i, setting indice to tmpstr + while (data[i] + data[i + 1] != 0){ //while not encountering 0x0000 (we assume 0x0000EE) + unsigned int tmpi = data[i] * 256 + data[i + 1]; //set tmpi to the UTF-8 length + std::string tmpstr = std::string((const char *)data + i + 2, (size_t)tmpi); //set the string data + i += tmpi + 2; //skip length+size forwards + ret[tmpstr] = fromDTMI(data, len, i); //add content, recursively parsed, updating i, setting indice to tmpstr } - i += 3;//skip 0x0000EE + i += 3; //skip 0x0000EE return ret; - } break; - case 0x0A:{//array + } + break; + case 0x0A: { //array JSON::Value ret; ++i; - while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x0000EE) - ret.append(fromDTMI(data, len, i));//add content, recursively parsed, updating i + while (data[i] + data[i + 1] != 0){ //while not encountering 0x0000 (we assume 0x0000EE) + ret.append(fromDTMI(data, len, i)); //add content, recursively parsed, updating i } - i += 3;//skip 0x0000EE + i += 3; //skip 0x0000EE return ret; - } break; + } + break; } - #if DEBUG >= 2 +#if DEBUG >= 2 fprintf(stderr, "Error: Unimplemented DTMI type %hhx - returning.\n", data[i]); - #endif +#endif return JSON::Value(); -}//fromOneDTMI +} //fromOneDTMI /// Parses a std::string to a valid JSON::Value. /// This function will find one DTMI object in the string and return it. JSON::Value JSON::fromDTMI(std::string data){ unsigned int i = 0; return fromDTMI((const unsigned char*)data.c_str(), data.size(), i); -}//fromDTMI +} //fromDTMI diff --git a/lib/json.h b/lib/json.h index fee192f2..a2db4845 100644 --- a/lib/json.h +++ b/lib/json.h @@ -7,19 +7,24 @@ #include //empty definition of DTSC::Stream so it can be a friend. -namespace DTSC{class Stream;} +namespace DTSC { + class Stream; +} /// JSON-related classes and functions -namespace JSON{ +namespace JSON { /// Lists all types of JSON::Value. - enum ValueType{ EMPTY, BOOL, INTEGER, STRING, ARRAY, OBJECT }; + enum ValueType{ + EMPTY, BOOL, INTEGER, STRING, ARRAY, OBJECT + }; - class Value;//forward declaration for below typedef + class Value; + //forward declaration for below typedef typedef std::map::iterator ObjIter; typedef std::deque::iterator ArrIter; - + /// A JSON::Value is either a string or an integer, but may also be an object, array or null. class Value{ private: @@ -34,7 +39,7 @@ namespace JSON{ static void skipToEnd(std::istream & fromstream); public: //friends - friend class DTSC::Stream;//for access to strVal + friend class DTSC::Stream; //for access to strVal //constructors Value(); Value(std::istream & fromstream); @@ -91,5 +96,5 @@ namespace JSON{ Value fromDTMI(const unsigned char * data, unsigned int len, unsigned int &i); Value fromString(std::string json); Value fromFile(std::string filename); - -}; + +} diff --git a/lib/mp4.cpp b/lib/mp4.cpp index 36d9d986..e2681cac 100644 --- a/lib/mp4.cpp +++ b/lib/mp4.cpp @@ -7,7 +7,7 @@ #define Int64 long long int /// Contains all MP4 format related code. -namespace MP4{ +namespace MP4 { /// Creates a new box, optionally using the indicated pointer for storage. /// If manage is set to true, the pointer will be realloc'ed when the box needs to be resized. @@ -33,39 +33,43 @@ namespace MP4{ } /// Returns the values at byte positions 4 through 7. - std::string Box::getType() { - return std::string(data+4,4); + std::string Box::getType(){ + return std::string(data + 4, 4); } /// Returns true if the given 4-byte boxtype is equal to the values at byte positions 4 through 7. - bool Box::isType( char* boxType ) { + bool Box::isType(const char* boxType){ return !memcmp(boxType, data + 4, 4); } /// Reads out a whole box (if possible) from newData, copying to the internal data storage and removing from the input string. /// \returns True on success, false otherwise. bool Box::read(std::string & newData){ - if (!managed){return false;} + if ( !managed){ + return false; + } if (newData.size() > 4){ payloadOffset = 8; - long long int size = ntohl( ((int*)newData.c_str())[0] ); - if( size == 1) { - if( newData.size() > 16) { - size = 0 + ntohl( ((int*)newData.c_str())[2] ); + long long int size = ntohl(((int*)newData.c_str())[0]); + if (size == 1){ + if (newData.size() > 16){ + size = 0 + ntohl(((int*)newData.c_str())[2]); size <<= 32; - size += ntohl( ((int*)newData.c_str())[3] ); + size += ntohl(((int*)newData.c_str())[3]); payloadOffset = 16; - } else { + }else{ return false; } } if (newData.size() >= size){ void * ret = malloc(size); - if (!ret){return false;} + if ( !ret){ + return false; + } free(data); data = (char*)ret; memcpy(data, newData.c_str(), size); - newData.erase( 0, size ); + newData.erase(0, size); return true; } } @@ -73,33 +77,35 @@ namespace MP4{ } /// Returns the total boxed size of this box, including the header. - long long int Box::boxedSize() { - if( payloadOffset == 16 ) { - return ((long long int)ntohl( ((int*)data)[2] ) << 32) + ntohl( ((int*)data)[3] ); + long long int Box::boxedSize(){ + if (payloadOffset == 16){ + return ((long long int)ntohl(((int*)data)[2]) << 32) + ntohl(((int*)data)[3]); } - return ntohl( ((int*)data)[0] ); + return ntohl(((int*)data)[0]); } /// Retruns the size of the payload of thix box, excluding the header. /// This value is defined as boxedSize() - 8. - long long int Box::payloadSize() { + long long int Box::payloadSize(){ return boxedSize() - payloadOffset; } /// Returns a copy of the data pointer. - char * Box::asBox() { + char * Box::asBox(){ return data; } - - char * Box::payload() { + + char * Box::payload(){ return data + payloadOffset; } /// Makes this box managed if it wasn't already, resetting the internal storage to 8 bytes (the minimum). /// If this box wasn't managed, the original data is left intact - otherwise it is free'd. /// If it was somehow impossible to allocate 8 bytes (should never happen), this will cause segfaults later. - void Box::clear() { - if (data && managed){free(data);} + void Box::clear(){ + if (data && managed){ + free(data); + } managed = true; payloadOffset = 8; data = (char*)malloc(8); @@ -114,28 +120,52 @@ namespace MP4{ /// Attempts to typecast this Box to a more specific type and call the toPrettyString() function of that type. /// If this failed, it will print out a message saying pretty-printing is not implemented for . std::string Box::toPrettyString(int indent){ - switch (ntohl( *((int*)(data+4)) )){ //type is at this address - case 0x6D666864: return ((MFHD*)this)->toPrettyString(indent); break; - case 0x6D6F6F66: return ((MOOF*)this)->toPrettyString(indent); break; - case 0x61627374: return ((ABST*)this)->toPrettyString(indent); break; - case 0x61667274: return ((AFRT*)this)->toPrettyString(indent); break; - case 0x61667261: return ((AFRA*)this)->toPrettyString(indent); break; - case 0x61737274: return ((ASRT*)this)->toPrettyString(indent); break; - case 0x7472756E: return ((TRUN*)this)->toPrettyString(indent); break; - case 0x74726166: return ((TRAF*)this)->toPrettyString(indent); break; - case 0x74666864: return ((TFHD*)this)->toPrettyString(indent); break; - case 0x61766343: return ((AVCC*)this)->toPrettyString(indent); break; - default: return std::string(indent, ' ')+"Unimplemented pretty-printing for box "+std::string(data+4,4)+"\n"; break; + switch (ntohl( *((int*)(data + 4)))){ //type is at this address + case 0x6D666864: + return ((MFHD*)this)->toPrettyString(indent); + break; + case 0x6D6F6F66: + return ((MOOF*)this)->toPrettyString(indent); + break; + case 0x61627374: + return ((ABST*)this)->toPrettyString(indent); + break; + case 0x61667274: + return ((AFRT*)this)->toPrettyString(indent); + break; + case 0x61667261: + return ((AFRA*)this)->toPrettyString(indent); + break; + case 0x61737274: + return ((ASRT*)this)->toPrettyString(indent); + break; + case 0x7472756E: + return ((TRUN*)this)->toPrettyString(indent); + break; + case 0x74726166: + return ((TRAF*)this)->toPrettyString(indent); + break; + case 0x74666864: + return ((TFHD*)this)->toPrettyString(indent); + break; + case 0x61766343: + return ((AVCC*)this)->toPrettyString(indent); + break; + default: + break; } + return std::string(indent, ' ') + "Unimplemented pretty-printing for box " + std::string(data + 4, 4) + "\n"; } /// Sets the 8 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Fails silently if resizing failed. - void Box::setInt8( char newData, size_t index ) { + void Box::setInt8(char newData, size_t index){ index += payloadOffset; if (index >= boxedSize()){ - if (!reserve(index, 0, 1)){return;} + if ( !reserve(index, 0, 1)){ + return; + } } data[index] = newData; } @@ -143,11 +173,13 @@ namespace MP4{ /// Gets the 8 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Returns zero if resizing failed. - char Box::getInt8( size_t index ) { + char Box::getInt8(size_t index){ index += payloadOffset; if (index >= boxedSize()){ - if (!reserve(index, 0, 1)){return 0;} - setInt8(0, index-payloadOffset); + if ( !reserve(index, 0, 1)){ + return 0; + } + setInt8(0, index - payloadOffset); } return data[index]; } @@ -155,132 +187,152 @@ namespace MP4{ /// Sets the 16 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Fails silently if resizing failed. - void Box::setInt16( short newData, size_t index ) { + void Box::setInt16(short newData, size_t index){ index += payloadOffset; - if (index+1 >= boxedSize()){ - if (!reserve(index, 0, 2)){return;} + if (index + 1 >= boxedSize()){ + if ( !reserve(index, 0, 2)){ + return; + } } - newData = htons( newData ); - memcpy( data + index, (char*)&newData, 2 ); + newData = htons(newData); + memcpy(data + index, (char*) &newData, 2); } /// Gets the 16 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Returns zero if resizing failed. - short Box::getInt16( size_t index ) { + short Box::getInt16(size_t index){ index += payloadOffset; - if (index+1 >= boxedSize()){ - if (!reserve(index, 0, 2)){return 0;} - setInt16(0, index-payloadOffset); + if (index + 1 >= boxedSize()){ + if ( !reserve(index, 0, 2)){ + return 0; + } + setInt16(0, index - payloadOffset); } short result; - memcpy( (char*)&result, data + index, 2 ); + memcpy((char*) &result, data + index, 2); return ntohs(result); } - + /// Sets the 24 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Fails silently if resizing failed. - void Box::setInt24( long newData, size_t index ) { + void Box::setInt24(long newData, size_t index){ index += payloadOffset; - if (index+2 >= boxedSize()){ - if (!reserve(index, 0, 3)){return;} + if (index + 2 >= boxedSize()){ + if ( !reserve(index, 0, 3)){ + return; + } } data[index] = (newData & 0x00FF0000) >> 16; - data[index+1] = (newData & 0x0000FF00) >> 8; - data[index+2] = (newData & 0x000000FF); + data[index + 1] = (newData & 0x0000FF00) >> 8; + data[index + 2] = (newData & 0x000000FF); } /// Gets the 24 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Returns zero if resizing failed. - long Box::getInt24( size_t index ) { + long Box::getInt24(size_t index){ index += payloadOffset; - if (index+2 >= boxedSize()){ - if (!reserve(index, 0, 3)){return 0;} - setInt24(0, index-payloadOffset); + if (index + 2 >= boxedSize()){ + if ( !reserve(index, 0, 3)){ + return 0; + } + setInt24(0, index - payloadOffset); } long result = data[index]; result <<= 8; - result += data[index+1]; + result += data[index + 1]; result <<= 8; - result += data[index+2]; + result += data[index + 2]; return result; } /// Sets the 32 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Fails silently if resizing failed. - void Box::setInt32( long newData, size_t index ) { + void Box::setInt32(long newData, size_t index){ index += payloadOffset; - if (index+3 >= boxedSize()){ - if (!reserve(index, 0, 4)){return;} + if (index + 3 >= boxedSize()){ + if ( !reserve(index, 0, 4)){ + return; + } } - newData = htonl( newData ); - memcpy( data + index, (char*)&newData, 4 ); + newData = htonl(newData); + memcpy(data + index, (char*) &newData, 4); } /// Gets the 32 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Returns zero if resizing failed. - long Box::getInt32( size_t index ) { + long Box::getInt32(size_t index){ index += payloadOffset; - if (index+3 >= boxedSize()){ - if (!reserve(index, 0, 4)){return 0;} - setInt32(0, index-payloadOffset); + if (index + 3 >= boxedSize()){ + if ( !reserve(index, 0, 4)){ + return 0; + } + setInt32(0, index - payloadOffset); } long result; - memcpy( (char*)&result, data + index, 4 ); + memcpy((char*) &result, data + index, 4); return ntohl(result); } /// Sets the 64 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Fails silently if resizing failed. - void Box::setInt64( Int64 newData, size_t index ) { + void Box::setInt64(Int64 newData, size_t index){ index += payloadOffset; - if (index+7 >= boxedSize()){ - if (!reserve(index, 0, 8)){return;} + if (index + 7 >= boxedSize()){ + if ( !reserve(index, 0, 8)){ + return; + } } - ((int*)(data+index))[0] = htonl((int)(newData>>32)); - ((int*)(data+index))[1] = htonl((int)(newData & 0xFFFFFFFF)); + ((int*)(data + index))[0] = htonl((int)(newData >> 32)); + ((int*)(data + index))[1] = htonl((int)(newData & 0xFFFFFFFF)); } /// Gets the 64 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Returns zero if resizing failed. - Int64 Box::getInt64( size_t index ) { + Int64 Box::getInt64(size_t index){ index += payloadOffset; - if (index+7 >= boxedSize()){ - if (!reserve(index, 0, 8)){return 0;} - setInt64(0, index-payloadOffset); + if (index + 7 >= boxedSize()){ + if ( !reserve(index, 0, 8)){ + return 0; + } + setInt64(0, index - payloadOffset); } - Int64 result = ntohl( ((int*)(data+index))[0] ); + Int64 result = ntohl(((int*)(data + index))[0]); result <<= 32; - result += ntohl( ((int*)(data+index))[1] ); + result += ntohl(((int*)(data + index))[1]); return result; } /// Sets the NULL-terminated string at the given index. /// Will attempt to resize if the string doesn't fit. /// Fails silently if resizing failed. - void Box::setString(std::string newData, size_t index ) { - setString( (char*)newData.c_str(), newData.size(), index ); + void Box::setString(std::string newData, size_t index){ + setString((char*)newData.c_str(), newData.size(), index); } /// Sets the NULL-terminated string at the given index. /// Will attempt to resize if the string doesn't fit. /// Fails silently if resizing failed. - void Box::setString(char* newData, size_t size, size_t index ) { + void Box::setString(char* newData, size_t size, size_t index){ index += payloadOffset; if (index >= boxedSize()){ - if (!reserve(index, 0, 1)){return;} + if ( !reserve(index, 0, 1)){ + return; + } data[index] = 0; } if (getStringLen(index) != size){ - if (!reserve(index, getStringLen(index)+1, size+1)){return;} + if ( !reserve(index, getStringLen(index) + 1, size + 1)){ + return; + } } - memcpy(data + index, newData, size+1); + memcpy(data + index, newData, size + 1); } /// Gets the NULL-terminated string at the given index. @@ -289,18 +341,22 @@ namespace MP4{ char * Box::getString(size_t index){ index += payloadOffset; if (index >= boxedSize()){ - if (!reserve(index, 0, 1)){return 0;} + if ( !reserve(index, 0, 1)){ + return 0; + } data[index] = 0; } - return data+index; + return data + index; } /// Returns the length of the NULL-terminated string at the given index. /// Returns 0 if out of range. size_t Box::getStringLen(size_t index){ index += payloadOffset; - if (index >= boxedSize()){return 0;} - return strlen(data+index); + if (index >= boxedSize()){ + return 0; + } + return strlen(data + index); } /// Gets a reference to the box at the given index. @@ -310,14 +366,14 @@ namespace MP4{ Box & Box::getBox(size_t index){ static Box retbox; index += payloadOffset; - if (index+8 > boxedSize()){ - if (!reserve(index, 0, 8)){ + if (index + 8 > boxedSize()){ + if ( !reserve(index, 0, 8)){ retbox = Box((char*)"\000\000\000\010erro", false); return retbox; } - memcpy(data+index, "\000\000\000\010erro", 8); + memcpy(data + index, "\000\000\000\010erro", 8); } - retbox = Box(data+index, false); + retbox = Box(data + index, false); return retbox; } @@ -325,7 +381,9 @@ namespace MP4{ /// Returns undefined values if there is no box at the given position. /// Returns 0 if out of range. size_t Box::getBoxLen(size_t index){ - if (index+payloadOffset+8 > boxedSize()){return 0;} + if (index + payloadOffset + 8 > boxedSize()){ + return 0; + } return getBox(index).boxedSize(); } @@ -334,648 +392,830 @@ namespace MP4{ void Box::setBox(Box & newEntry, size_t index){ int oldlen = getBoxLen(index); int newlen = newEntry.boxedSize(); - if (oldlen != newlen && !reserve(index+payloadOffset, oldlen, newlen)){return;} - memcpy(data+index+payloadOffset, newEntry.asBox(), newlen); + if (oldlen != newlen && !reserve(index + payloadOffset, oldlen, newlen)){ + return; + } + memcpy(data + index + payloadOffset, newEntry.asBox(), newlen); } /// Attempts to reserve enough space for wanted bytes of data at given position, where current bytes of data is now reserved. /// This will move any existing data behind the currently reserved space to the proper location after reserving. /// \returns True on success, false otherwise. bool Box::reserve(size_t position, size_t current, size_t wanted){ - if (current == wanted){return true;} + if (current == wanted){ + return true; + } if (position > boxedSize()){ wanted += position - boxedSize(); } if (current < wanted){ //make bigger - if (boxedSize() + (wanted-current) > data_size){ + if (boxedSize() + (wanted - current) > data_size){ //realloc if managed, otherwise fail - if (!managed){return false;} - void * ret = realloc(data, boxedSize() + (wanted-current)); - if (!ret){return false;} + if ( !managed){ + return false; + } + void * ret = realloc(data, boxedSize() + (wanted - current)); + if ( !ret){ + return false; + } data = (char*)ret; - memset(data+boxedSize(), 0, wanted-current);//initialize to 0 - data_size = boxedSize() + (wanted-current); + memset(data + boxedSize(), 0, wanted - current); //initialize to 0 + data_size = boxedSize() + (wanted - current); } } //move data behind, if any - if (boxedSize() > (position+current)){ - memmove(data+position+wanted, data+position+current, boxedSize() - (position+current)); + if (boxedSize() > (position + current)){ + memmove(data + position + wanted, data + position + current, boxedSize() - (position + current)); } //calculate and set new size - if (payloadOffset != 16) { - int newSize = boxedSize() + (wanted-current); + if (payloadOffset != 16){ + int newSize = boxedSize() + (wanted - current); ((int*)data)[0] = htonl(newSize); } return true; } - ABST::ABST( ) { + ABST::ABST(){ memcpy(data + 4, "abst", 4); - setVersion( 0 ); - setFlags( 0 ); - setBootstrapinfoVersion( 0 ); - setProfile( 0 ); - setLive( 1 ); - setUpdate( 0 ); - setTimeScale( 1000 ); - setCurrentMediaTime( 0 ); - setSmpteTimeCodeOffset( 0 ); + setVersion(0); + setFlags(0); + setBootstrapinfoVersion(0); + setProfile(0); + setLive(1); + setUpdate(0); + setTimeScale(1000); + setCurrentMediaTime(0); + setSmpteTimeCodeOffset(0); std::string empty; - setMovieIdentifier( empty ); - setInt8(0, 30);//set serverentrycount to 0 - setInt8(0, 31);//set qualityentrycount to 0 - setDrmData( empty ); - setMetaData( empty ); + setMovieIdentifier(empty); + setInt8(0, 30); //set serverentrycount to 0 + setInt8(0, 31); //set qualityentrycount to 0 + setDrmData(empty); + setMetaData(empty); } - - void ABST::setVersion(char newVersion){setInt8(newVersion, 0);} - - char ABST::getVersion(){return getInt8(0);} - - void ABST::setFlags(long newFlags){setInt24(newFlags, 1);} - - long ABST::getFlags(){return getInt24(1);} - void ABST::setBootstrapinfoVersion(long newVersion){setInt32(newVersion, 4);} - - long ABST::getBootstrapinfoVersion(){return getInt32(4);} + void ABST::setVersion(char newVersion){ + setInt8(newVersion, 0); + } + + char ABST::getVersion(){ + return getInt8(0); + } + + void ABST::setFlags(long newFlags){ + setInt24(newFlags, 1); + } + + long ABST::getFlags(){ + return getInt24(1); + } + + void ABST::setBootstrapinfoVersion(long newVersion){ + setInt32(newVersion, 4); + } + + long ABST::getBootstrapinfoVersion(){ + return getInt32(4); + } void ABST::setProfile(char newProfile){ //profile = bit 1 and 2 of byte 8. setInt8((getInt8(8) & 0x3F) + ((newProfile & 0x03) << 6), 8); } - - char ABST::getProfile(){return (getInt8(8) & 0xC0);}; + + char ABST::getProfile(){ + return (getInt8(8) & 0xC0); + } + ; void ABST::setLive(bool newLive){ //live = bit 4 of byte 8. - setInt8((getInt8(8) & 0xDF) + (newLive ? 0x10 : 0 ), 8); + setInt8((getInt8(8) & 0xDF) + (newLive ? 0x10 : 0), 8); } - - bool ABST::getLive(){return (getInt8(8) & 0x10);} - void ABST::setUpdate(bool newUpdate) { + bool ABST::getLive(){ + return (getInt8(8) & 0x10); + } + + void ABST::setUpdate(bool newUpdate){ //update = bit 5 of byte 8. setInt8((getInt8(8) & 0xEF) + (newUpdate ? 0x08 : 0), 8); } - - bool ABST::getUpdate(){return (getInt8(8) & 0x08);} - void ABST::setTimeScale(long newScale){setInt32(newScale, 9);} - - long ABST::getTimeScale(){return getInt32(9);} - - void ABST::setCurrentMediaTime(Int64 newTime){setInt64(newTime, 13);} - - Int64 ABST::getCurrentMediaTime(){return getInt64(13);} + bool ABST::getUpdate(){ + return (getInt8(8) & 0x08); + } - void ABST::setSmpteTimeCodeOffset(Int64 newTime){setInt64(newTime, 21);} - - Int64 ABST::getSmpteTimeCodeOffset(){return getInt64(21);} + void ABST::setTimeScale(long newScale){ + setInt32(newScale, 9); + } - void ABST::setMovieIdentifier(std::string & newIdentifier){setString(newIdentifier, 29);} - - char* ABST::getMovieIdentifier(){return getString(29);} + long ABST::getTimeScale(){ + return getInt32(9); + } + + void ABST::setCurrentMediaTime(Int64 newTime){ + setInt64(newTime, 13); + } + + Int64 ABST::getCurrentMediaTime(){ + return getInt64(13); + } + + void ABST::setSmpteTimeCodeOffset(Int64 newTime){ + setInt64(newTime, 21); + } + + Int64 ABST::getSmpteTimeCodeOffset(){ + return getInt64(21); + } + + void ABST::setMovieIdentifier(std::string & newIdentifier){ + setString(newIdentifier, 29); + } + + char* ABST::getMovieIdentifier(){ + return getString(29); + } long ABST::getServerEntryCount(){ - int countLoc = 29 + getStringLen(29)+1; + int countLoc = 29 + getStringLen(29) + 1; return getInt8(countLoc); } void ABST::setServerEntry(std::string & newEntry, long no){ - int countLoc = 29 + getStringLen(29)+1; - int tempLoc = countLoc+1; + int countLoc = 29 + getStringLen(29) + 1; + int tempLoc = countLoc + 1; //attempt to reach the wanted position int i; for (i = 0; i < getInt8(countLoc) && i < no; ++i){ - tempLoc += getStringLen(tempLoc)+1; + tempLoc += getStringLen(tempLoc) + 1; } //we are now either at the end, or at the right position //let's reserve any unreserved space... - if (no+1 > getInt8(countLoc)){ - int amount = no+1-getInt8(countLoc); - if(!reserve(payloadOffset+tempLoc, 0, amount)){return;}; - memset(data+payloadOffset+tempLoc, 0, amount); - setInt8(no+1, countLoc);//set new qualityEntryCount - tempLoc += no-i; + if (no + 1 > getInt8(countLoc)){ + int amount = no + 1 - getInt8(countLoc); + if ( !reserve(payloadOffset + tempLoc, 0, amount)){ + return; + }; + memset(data + payloadOffset + tempLoc, 0, amount); + setInt8(no + 1, countLoc); //set new qualityEntryCount + tempLoc += no - i; } //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. setString(newEntry, tempLoc); } - + ///\return Empty string if no > serverEntryCount(), serverEntry[no] otherwise. const char* ABST::getServerEntry(long no){ - if (no+1 > getServerEntryCount()){return "";} - int tempLoc = 29+getStringLen(29)+1 + 1;//position of first entry - for (int i = 0; i < no; i++){tempLoc += getStringLen(tempLoc)+1;} - return getString(tempLoc); - } - - long ABST::getQualityEntryCount(){ - int countLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){countLoc += getStringLen(countLoc)+1;} - return getInt8(countLoc); - } - - void ABST::setQualityEntry(std::string & newEntry, long no){ - int countLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){countLoc += getStringLen(countLoc)+1;} - int tempLoc = countLoc+1; - //attempt to reach the wanted position - int i; - for (i = 0; i < getInt8(countLoc) && i < no; ++i){ - tempLoc += getStringLen(tempLoc)+1; + if (no + 1 > getServerEntryCount()){ + return ""; } - //we are now either at the end, or at the right position - //let's reserve any unreserved space... - if (no+1 > getInt8(countLoc)){ - int amount = no+1-getInt8(countLoc); - if(!reserve(payloadOffset+tempLoc, 0, amount)){return;}; - memset(data+payloadOffset+tempLoc, 0, amount); - setInt8(no+1, countLoc);//set new qualityEntryCount - tempLoc += no-i; + int tempLoc = 29 + getStringLen(29) + 1 + 1; //position of first entry + for (int i = 0; i < no; i++){ + tempLoc += getStringLen(tempLoc) + 1; } - //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. - setString(newEntry, tempLoc); - } - - const char* ABST::getQualityEntry(long no){ - if (no > getQualityEntryCount()){return "";} - int tempLoc = 29+getStringLen(29)+1 + 1;//position of serverentries; - for (int i = 0; i < getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc += 1;//first qualityentry - for (int i = 0; i < no; i++){tempLoc += getStringLen(tempLoc)+1;} - return getString(tempLoc); - } - - void ABST::setDrmData( std::string newDrm ) { - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - setString(newDrm, tempLoc); - } - - char* ABST::getDrmData() { - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} return getString(tempLoc); } - void ABST::setMetaData( std::string newMetaData ) { - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + long ABST::getQualityEntryCount(){ + int countLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + countLoc += getStringLen(countLoc) + 1; + } + return getInt8(countLoc); + } + + void ABST::setQualityEntry(std::string & newEntry, long no){ + int countLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + countLoc += getStringLen(countLoc) + 1; + } + int tempLoc = countLoc + 1; + //attempt to reach the wanted position + int i; + for (i = 0; i < getInt8(countLoc) && i < no; ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } + //we are now either at the end, or at the right position + //let's reserve any unreserved space... + if (no + 1 > getInt8(countLoc)){ + int amount = no + 1 - getInt8(countLoc); + if ( !reserve(payloadOffset + tempLoc, 0, amount)){ + return; + }; + memset(data + payloadOffset + tempLoc, 0, amount); + setInt8(no + 1, countLoc); //set new qualityEntryCount + tempLoc += no - i; + } + //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. + setString(newEntry, tempLoc); + } + + const char* ABST::getQualityEntry(long no){ + if (no > getQualityEntryCount()){ + return ""; + } + int tempLoc = 29 + getStringLen(29) + 1 + 1; //position of serverentries; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += 1; //first qualityentry + for (int i = 0; i < no; i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getString(tempLoc); + } + + void ABST::setDrmData(std::string newDrm){ + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc += getStringLen(tempLoc)+1; + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + setString(newDrm, tempLoc); + } + + char* ABST::getDrmData(){ + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getString(tempLoc); + } + + void ABST::setMetaData(std::string newMetaData){ + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; setString(newMetaData, tempLoc); } - - char* ABST::getMetaData() { - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + + char* ABST::getMetaData(){ + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc += getStringLen(tempLoc)+1; + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; return getString(tempLoc); } long ABST::getSegmentRunTableCount(){ - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc+=getStringLen(tempLoc)+1;//DrmData - tempLoc+=getStringLen(tempLoc)+1;//MetaData + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData return getInt8(tempLoc); } - - void ABST::setSegmentRunTable( ASRT & newSegment, long no ) { - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + + void ABST::setSegmentRunTable(ASRT & newSegment, long no){ + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc+=getStringLen(tempLoc)+1;//DrmData - tempLoc+=getStringLen(tempLoc)+1;//MetaData + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData int countLoc = tempLoc; - tempLoc++;//skip segmentRuntableCount + tempLoc++; //skip segmentRuntableCount //attempt to reach the wanted position int i; - for (i = 0; i < getInt8(countLoc) && i < no; ++i){tempLoc += getBoxLen(tempLoc);} + for (i = 0; i < getInt8(countLoc) && i < no; ++i){ + tempLoc += getBoxLen(tempLoc); + } //we are now either at the end, or at the right position //let's reserve any unreserved space... - if (no+1 > getInt8(countLoc)){ - int amount = no+1-getInt8(countLoc); - if(!reserve(payloadOffset+tempLoc, 0, amount*8)){return;}; + if (no + 1 > getInt8(countLoc)){ + int amount = no + 1 - getInt8(countLoc); + if ( !reserve(payloadOffset + tempLoc, 0, amount * 8)){ + return; + }; //set empty erro boxes as contents for (int j = 0; j < amount; ++j){ - memcpy(data+payloadOffset+tempLoc+j*8, "\000\000\000\010erro", 8); + memcpy(data + payloadOffset + tempLoc + j * 8, "\000\000\000\010erro", 8); } - setInt8(no+1, countLoc);//set new count - tempLoc += (no-i)*8; + setInt8(no + 1, countLoc); //set new count + tempLoc += (no - i) * 8; } //now, tempLoc is at position for string number no, and we have at least an erro box reserved. setBox(newSegment, tempLoc); } - - ASRT & ABST::getSegmentRunTable( long no ) { + + ASRT & ABST::getSegmentRunTable(long no){ static Box result; - if( no > getSegmentRunTableCount() ) { + if (no > getSegmentRunTableCount()){ static Box res; return (ASRT&)res; } - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc+=getStringLen(tempLoc)+1;//DrmData - tempLoc+=getStringLen(tempLoc)+1;//MetaData + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData int countLoc = tempLoc; - tempLoc++;//segmentRuntableCount - for (int i = 0; i < no; ++i){tempLoc += getBoxLen(tempLoc);} + tempLoc++; //segmentRuntableCount + for (int i = 0; i < no; ++i){ + tempLoc += getBoxLen(tempLoc); + } return (ASRT&)getBox(tempLoc); } - - long ABST::getFragmentRunTableCount() { - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + + long ABST::getFragmentRunTableCount(){ + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc+=getStringLen(tempLoc)+1;//DrmData - tempLoc+=getStringLen(tempLoc)+1;//MetaData - for (int i = getInt8(tempLoc++); i != 0; --i){tempLoc += getBoxLen(tempLoc);} - return getInt8( tempLoc ); + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + for (int i = getInt8(tempLoc++); i != 0; --i){ + tempLoc += getBoxLen(tempLoc); + } + return getInt8(tempLoc); } - - void ABST::setFragmentRunTable( AFRT & newFragment, long no ) { - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + + void ABST::setFragmentRunTable(AFRT & newFragment, long no){ + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc+=getStringLen(tempLoc)+1;//DrmData - tempLoc+=getStringLen(tempLoc)+1;//MetaData - for (int i = getInt8(tempLoc++); i != 0; --i){tempLoc += getBoxLen(tempLoc);} + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + for (int i = getInt8(tempLoc++); i != 0; --i){ + tempLoc += getBoxLen(tempLoc); + } int countLoc = tempLoc; tempLoc++; //attempt to reach the wanted position int i; - for (i = 0; i < getInt8(countLoc) && i < no; ++i){tempLoc += getBoxLen(tempLoc);} + for (i = 0; i < getInt8(countLoc) && i < no; ++i){ + tempLoc += getBoxLen(tempLoc); + } //we are now either at the end, or at the right position //let's reserve any unreserved space... - if (no+1 > getInt8(countLoc)){ - int amount = no+1-getInt8(countLoc); - if(!reserve(payloadOffset+tempLoc, 0, amount*8)){return;}; + if (no + 1 > getInt8(countLoc)){ + int amount = no + 1 - getInt8(countLoc); + if ( !reserve(payloadOffset + tempLoc, 0, amount * 8)){ + return; + }; //set empty erro boxes as contents for (int j = 0; j < amount; ++j){ - memcpy(data+payloadOffset+tempLoc+j*8, "\000\000\000\010erro", 8); + memcpy(data + payloadOffset + tempLoc + j * 8, "\000\000\000\010erro", 8); } - setInt8(no+1, countLoc);//set new count - tempLoc += (no-i)*8; + setInt8(no + 1, countLoc); //set new count + tempLoc += (no - i) * 8; } //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. setBox(newFragment, tempLoc); } - AFRT & ABST::getFragmentRunTable( long no ) { + AFRT & ABST::getFragmentRunTable(long no){ static Box result; if (no >= getFragmentRunTableCount()){ static Box res; return (AFRT&)res; } - long tempLoc = 29 + getStringLen(29)+1 + 1; - for (int i = 0; i< getServerEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + long tempLoc = 29 + getStringLen(29) + 1 + 1; + for (int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } tempLoc++; - for (int i = 0; i< getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - tempLoc+=getStringLen(tempLoc)+1;//DrmData - tempLoc+=getStringLen(tempLoc)+1;//MetaData - for (int i = getInt8(tempLoc++); i != 0; --i){tempLoc += getBoxLen(tempLoc);} + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + for (int i = getInt8(tempLoc++); i != 0; --i){ + tempLoc += getBoxLen(tempLoc); + } int countLoc = tempLoc; tempLoc++; - for (int i = 0; i < no; i++){tempLoc += getBoxLen(tempLoc);} + for (int i = 0; i < no; i++){ + tempLoc += getBoxLen(tempLoc); + } return (AFRT&)getBox(tempLoc); } - - std::string ABST::toPrettyString( long indent ) { + + std::string ABST::toPrettyString(long indent){ std::stringstream r; r << std::string(indent, ' ') << "[abst] Bootstrap Info (" << boxedSize() << ")" << std::endl; - r << std::string(indent+1, ' ') << "Version " << (int)getVersion() << std::endl; - r << std::string(indent+1, ' ') << "BootstrapinfoVersion " << getBootstrapinfoVersion() << std::endl; - r << std::string(indent+1, ' ') << "Profile " << (int)getProfile() << std::endl; - if( getLive() ) { - r << std::string(indent+1, ' ' ) << "Live" << std::endl; + r << std::string(indent + 1, ' ') << "Version " << (int)getVersion() << std::endl; + r << std::string(indent + 1, ' ') << "BootstrapinfoVersion " << getBootstrapinfoVersion() << std::endl; + r << std::string(indent + 1, ' ') << "Profile " << (int)getProfile() << std::endl; + if (getLive()){ + r << std::string(indent + 1, ' ') << "Live" << std::endl; }else{ - r << std::string(indent+1, ' ' ) << "Recorded" << std::endl; + r << std::string(indent + 1, ' ') << "Recorded" << std::endl; } - if( getUpdate() ) { - r << std::string(indent+1, ' ') << "Update" << std::endl; - } else { - r << std::string(indent+1, ' ') << "Replacement or new table" << std::endl; + if (getUpdate()){ + r << std::string(indent + 1, ' ') << "Update" << std::endl; + }else{ + r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; } - r << std::string(indent+1, ' ') << "Timescale " << getTimeScale() << std::endl; - r << std::string(indent+1, ' ') << "CurrMediaTime " << getCurrentMediaTime() << std::endl; - r << std::string(indent+1, ' ') << "SmpteTimeCodeOffset " << getSmpteTimeCodeOffset() << std::endl; - r << std::string(indent+1, ' ') << "MovieIdentifier " << getMovieIdentifier() << std::endl; - r << std::string(indent+1, ' ') << "ServerEntryTable (" << getServerEntryCount() << ")" << std::endl; - for( int i = 0; i < getServerEntryCount(); i++ ) { - r << std::string(indent+2, ' ') << i << ": " << getServerEntry(i) << std::endl; + r << std::string(indent + 1, ' ') << "Timescale " << getTimeScale() << std::endl; + r << std::string(indent + 1, ' ') << "CurrMediaTime " << getCurrentMediaTime() << std::endl; + r << std::string(indent + 1, ' ') << "SmpteTimeCodeOffset " << getSmpteTimeCodeOffset() << std::endl; + r << std::string(indent + 1, ' ') << "MovieIdentifier " << getMovieIdentifier() << std::endl; + r << std::string(indent + 1, ' ') << "ServerEntryTable (" << getServerEntryCount() << ")" << std::endl; + for (int i = 0; i < getServerEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": " << getServerEntry(i) << std::endl; } - r << std::string(indent+1, ' ') << "QualityEntryTable (" << getQualityEntryCount() << ")" << std::endl; - for( int i = 0; i < getQualityEntryCount(); i++ ) { - r << std::string(indent+2, ' ') << i << ": " << getQualityEntry(i) << std::endl; + r << std::string(indent + 1, ' ') << "QualityEntryTable (" << getQualityEntryCount() << ")" << std::endl; + for (int i = 0; i < getQualityEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; } - r << std::string(indent+1, ' ') << "DrmData " << getDrmData() << std::endl; - r << std::string(indent+1, ' ') << "MetaData " << getMetaData() << std::endl; - r << std::string(indent+1, ' ') << "SegmentRunTableEntries (" << getSegmentRunTableCount() << ")" << std::endl; - for( uint32_t i = 0; i < getSegmentRunTableCount(); i++ ) { - r << ((Box)getSegmentRunTable(i)).toPrettyString(indent+2); + r << std::string(indent + 1, ' ') << "DrmData " << getDrmData() << std::endl; + r << std::string(indent + 1, ' ') << "MetaData " << getMetaData() << std::endl; + r << std::string(indent + 1, ' ') << "SegmentRunTableEntries (" << getSegmentRunTableCount() << ")" << std::endl; + for (uint32_t i = 0; i < getSegmentRunTableCount(); i++){ + r << ((Box)getSegmentRunTable(i)).toPrettyString(indent + 2); } - r << std::string(indent+1, ' ')+"FragmentRunTableEntries (" << getFragmentRunTableCount() << ")" << std::endl; - for( uint32_t i = 0; i < getFragmentRunTableCount(); i++ ) { - r << ((Box)getFragmentRunTable(i)).toPrettyString(indent+2); + r << std::string(indent + 1, ' ') + "FragmentRunTableEntries (" << getFragmentRunTableCount() << ")" << std::endl; + for (uint32_t i = 0; i < getFragmentRunTableCount(); i++){ + r << ((Box)getFragmentRunTable(i)).toPrettyString(indent + 2); } return r.str(); } - + AFRT::AFRT(){ memcpy(data + 4, "afrt", 4); setVersion(0); setUpdate(0); setTimeScale(1000); } - - void AFRT::setVersion(char newVersion){setInt8(newVersion, 0);} - - long AFRT::getVersion(){return getInt8(0);} - - void AFRT::setUpdate(long newUpdate){setInt24(newUpdate, 1);} - - long AFRT::getUpdate(){return getInt24(1);} - - void AFRT::setTimeScale(long newScale){setInt32(newScale, 4);} - - long AFRT::getTimeScale(){return getInt32(4);} - - long AFRT::getQualityEntryCount(){return getInt8(8);} - + + void AFRT::setVersion(char newVersion){ + setInt8(newVersion, 0); + } + + long AFRT::getVersion(){ + return getInt8(0); + } + + void AFRT::setUpdate(long newUpdate){ + setInt24(newUpdate, 1); + } + + long AFRT::getUpdate(){ + return getInt24(1); + } + + void AFRT::setTimeScale(long newScale){ + setInt32(newScale, 4); + } + + long AFRT::getTimeScale(){ + return getInt32(4); + } + + long AFRT::getQualityEntryCount(){ + return getInt8(8); + } + void AFRT::setQualityEntry(std::string & newEntry, long no){ int countLoc = 8; - int tempLoc = countLoc+1; + int tempLoc = countLoc + 1; //attempt to reach the wanted position int i; for (i = 0; i < getQualityEntryCount() && i < no; ++i){ - tempLoc += getStringLen(tempLoc)+1; + tempLoc += getStringLen(tempLoc) + 1; } //we are now either at the end, or at the right position //let's reserve any unreserved space... - if (no+1 > getQualityEntryCount()){ - int amount = no+1-getQualityEntryCount(); - if(!reserve(payloadOffset+tempLoc, 0, amount)){return;}; - memset(data+payloadOffset+tempLoc, 0, amount); - setInt8(no+1, countLoc);//set new qualityEntryCount - tempLoc += no-i; + if (no + 1 > getQualityEntryCount()){ + int amount = no + 1 - getQualityEntryCount(); + if ( !reserve(payloadOffset + tempLoc, 0, amount)){ + return; + }; + memset(data + payloadOffset + tempLoc, 0, amount); + setInt8(no + 1, countLoc); //set new qualityEntryCount + tempLoc += no - i; } //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. setString(newEntry, tempLoc); } - + const char* AFRT::getQualityEntry(long no){ - if (no+1 > getQualityEntryCount()){return "";} - int tempLoc = 9;//position of first quality entry - for (int i = 0; i < no; i++){tempLoc += getStringLen(tempLoc)+1;} + if (no + 1 > getQualityEntryCount()){ + return ""; + } + int tempLoc = 9; //position of first quality entry + for (int i = 0; i < no; i++){ + tempLoc += getStringLen(tempLoc) + 1; + } return getString(tempLoc); } - + long AFRT::getFragmentRunCount(){ int tempLoc = 9; - for (int i = 0; i < getQualityEntryCount(); ++i){tempLoc += getStringLen(tempLoc)+1;} + for (int i = 0; i < getQualityEntryCount(); ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } return getInt32(tempLoc); } - - void AFRT::setFragmentRun( afrt_runtable newRun, long no ) { + + void AFRT::setFragmentRun(afrt_runtable newRun, long no){ int tempLoc = 9; for (int i = 0; i < getQualityEntryCount(); ++i){ - tempLoc += getStringLen(tempLoc)+1; + tempLoc += getStringLen(tempLoc) + 1; } int countLoc = tempLoc; tempLoc += 4; for (int i = 0; i < no; i++){ - if (i+1 > getInt32(countLoc)){ - setInt32(0,tempLoc); - setInt64(0,tempLoc+4); - setInt32(1,tempLoc+12); + if (i + 1 > getInt32(countLoc)){ + setInt32(0, tempLoc); + setInt64(0, tempLoc + 4); + setInt32(1, tempLoc + 12); + } + if (getInt32(tempLoc + 12) == 0){ + tempLoc += 17; + }else{ + tempLoc += 16; } - if (getInt32(tempLoc+12) == 0){tempLoc += 17;}else{tempLoc += 16;} } - setInt32(newRun.firstFragment,tempLoc); - setInt64(newRun.firstTimestamp,tempLoc+4); - setInt32(newRun.duration,tempLoc+12); + setInt32(newRun.firstFragment, tempLoc); + setInt64(newRun.firstTimestamp, tempLoc + 4); + setInt32(newRun.duration, tempLoc + 12); if (newRun.duration == 0){ - setInt8(newRun.discontinuity,tempLoc+16); + setInt8(newRun.discontinuity, tempLoc + 16); + } + if (getInt32(countLoc) < no + 1){ + setInt32(no + 1, countLoc); } - if (getInt32(countLoc) < no+1){setInt32(no+1, countLoc);} } - - afrt_runtable AFRT::getFragmentRun( long no ) { + + afrt_runtable AFRT::getFragmentRun(long no){ afrt_runtable res; - if( no > getFragmentRunCount() ){return res;} + if (no > getFragmentRunCount()){ + return res; + } int tempLoc = 9; - for( int i = 0; i < getQualityEntryCount(); i++ ){ - tempLoc += getStringLen(tempLoc)+1; + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; } int countLoc = tempLoc; tempLoc += 4; for (int i = 0; i < no; i++){ - if (getInt32(tempLoc+12) == 0){tempLoc += 17;}else{tempLoc += 16;} + if (getInt32(tempLoc + 12) == 0){ + tempLoc += 17; + }else{ + tempLoc += 16; + } } res.firstFragment = getInt32(tempLoc); - res.firstTimestamp = getInt64(tempLoc+4); - res.duration = getInt32(tempLoc+12); - if( res.duration ) { - res.discontinuity = getInt8(tempLoc+16); - } else { + res.firstTimestamp = getInt64(tempLoc + 4); + res.duration = getInt32(tempLoc + 12); + if (res.duration){ + res.discontinuity = getInt8(tempLoc + 16); + }else{ res.discontinuity = 0; } return res; } - + std::string AFRT::toPrettyString(int indent){ std::stringstream r; r << std::string(indent, ' ') << "[afrt] Fragment Run Table (" << boxedSize() << ")" << std::endl; - r << std::string(indent+1, ' ') << "Version " << (int)getVersion() << std::endl; + r << std::string(indent + 1, ' ') << "Version " << (int)getVersion() << std::endl; if (getUpdate()){ - r << std::string(indent+1, ' ') << "Update" << std::endl; + r << std::string(indent + 1, ' ') << "Update" << std::endl; }else{ - r << std::string(indent+1, ' ') << "Replacement or new table" << std::endl; + r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; } - r << std::string(indent+1, ' ') << "Timescale " << getTimeScale() << std::endl; - r << std::string(indent+1, ' ') << "QualitySegmentUrlModifiers (" << getQualityEntryCount() << ")" << std::endl; - for( int i = 0; i < getQualityEntryCount(); i++ ) { - r << std::string(indent+2, ' ') << i << ": " << getQualityEntry(i) << std::endl; + r << std::string(indent + 1, ' ') << "Timescale " << getTimeScale() << std::endl; + r << std::string(indent + 1, ' ') << "QualitySegmentUrlModifiers (" << getQualityEntryCount() << ")" << std::endl; + for (int i = 0; i < getQualityEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; } - r << std::string(indent+1, ' ') << "FragmentRunEntryTable (" << getFragmentRunCount() << ")" << std::endl; - for( int i = 0; i < getFragmentRunCount(); i ++ ) { + r << std::string(indent + 1, ' ') << "FragmentRunEntryTable (" << getFragmentRunCount() << ")" << std::endl; + for (int i = 0; i < getFragmentRunCount(); i++){ afrt_runtable myRun = getFragmentRun(i); if (myRun.duration){ - r << std::string(indent+2, ' ') << i << ": " << myRun.firstFragment << " is at " << ((double)myRun.firstTimestamp / (double)getTimeScale()) << "s, " << ((double)myRun.duration / (double)getTimeScale()) << "s per fragment." << std::endl; + r << std::string(indent + 2, ' ') << i << ": " << myRun.firstFragment << " is at " << ((double)myRun.firstTimestamp / (double)getTimeScale()) + << "s, " << ((double)myRun.duration / (double)getTimeScale()) << "s per fragment." << std::endl; }else{ - r << std::string(indent+2, ' ') << i << ": " << myRun.firstFragment << " is at " << ((double)myRun.firstTimestamp / (double)getTimeScale()) << "s, discontinuity type " << myRun.discontinuity << std::endl; + r << std::string(indent + 2, ' ') << i << ": " << myRun.firstFragment << " is at " << ((double)myRun.firstTimestamp / (double)getTimeScale()) + << "s, discontinuity type " << myRun.discontinuity << std::endl; } } return r.str(); } - + ASRT::ASRT(){ memcpy(data + 4, "asrt", 4); - setVersion( 0 ); - setUpdate( 0 ); + setVersion(0); + setUpdate(0); } - - void ASRT::setVersion( char newVersion ) { - setInt8( newVersion, 0 ); + + void ASRT::setVersion(char newVersion){ + setInt8(newVersion, 0); } - - long ASRT::getVersion(){return getInt8(0);} - - void ASRT::setUpdate( long newUpdate ) { - setInt24( newUpdate, 1 ); + + long ASRT::getVersion(){ + return getInt8(0); } - - long ASRT::getUpdate(){return getInt24(1);} - + + void ASRT::setUpdate(long newUpdate){ + setInt24(newUpdate, 1); + } + + long ASRT::getUpdate(){ + return getInt24(1); + } + long ASRT::getQualityEntryCount(){ return getInt8(4); } - + void ASRT::setQualityEntry(std::string & newEntry, long no){ int countLoc = 4; - int tempLoc = countLoc+1; + int tempLoc = countLoc + 1; //attempt to reach the wanted position int i; for (i = 0; i < getQualityEntryCount() && i < no; ++i){ - tempLoc += getStringLen(tempLoc)+1; + tempLoc += getStringLen(tempLoc) + 1; } //we are now either at the end, or at the right position //let's reserve any unreserved space... - if (no+1 > getQualityEntryCount()){ - int amount = no+1-getQualityEntryCount(); - if(!reserve(payloadOffset+tempLoc, 0, amount)){return;}; - memset(data+payloadOffset+tempLoc, 0, amount); - setInt8(no+1, countLoc);//set new qualityEntryCount - tempLoc += no-i; + if (no + 1 > getQualityEntryCount()){ + int amount = no + 1 - getQualityEntryCount(); + if ( !reserve(payloadOffset + tempLoc, 0, amount)){ + return; + }; + memset(data + payloadOffset + tempLoc, 0, amount); + setInt8(no + 1, countLoc); //set new qualityEntryCount + tempLoc += no - i; } //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. setString(newEntry, tempLoc); } - + const char* ASRT::getQualityEntry(long no){ - if (no > getQualityEntryCount()){return "";} - int tempLoc = 5;//position of qualityentry count; - for (int i = 0; i < no; i++){tempLoc += getStringLen(tempLoc)+1;} + if (no > getQualityEntryCount()){ + return ""; + } + int tempLoc = 5; //position of qualityentry count; + for (int i = 0; i < no; i++){ + tempLoc += getStringLen(tempLoc) + 1; + } return getString(tempLoc); } - - long ASRT::getSegmentRunEntryCount() { - int tempLoc = 5;//position of qualityentry count; - for (int i = 0; i < getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} + + long ASRT::getSegmentRunEntryCount(){ + int tempLoc = 5; //position of qualityentry count; + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } return getInt32(tempLoc); } - - void ASRT::setSegmentRun( long firstSegment, long fragmentsPerSegment, long no ) { - int tempLoc = 5;//position of qualityentry count; - for (int i = 0; i < getQualityEntryCount(); i++){tempLoc += getStringLen(tempLoc)+1;} - int countLoc = tempLoc; - tempLoc += 4 + no*8; - if (no+1 > getInt32(countLoc)){ - setInt32(no+1, countLoc);//set new qualityEntryCount + + void ASRT::setSegmentRun(long firstSegment, long fragmentsPerSegment, long no){ + int tempLoc = 5; //position of qualityentry count; + for (int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; } - setInt32(firstSegment,tempLoc); - setInt32(fragmentsPerSegment,tempLoc+4); - } - - asrt_runtable ASRT::getSegmentRun( long no ) { - asrt_runtable res; - if (no >= getSegmentRunEntryCount()){return res;} - int tempLoc = 5;//position of qualityentry count; - for (int i = 0; i < getQualityEntryCount(); ++i){tempLoc += getStringLen(tempLoc)+1;} int countLoc = tempLoc; - tempLoc += 4 + 8*no; + tempLoc += 4 + no * 8; + if (no + 1 > getInt32(countLoc)){ + setInt32(no + 1, countLoc); //set new qualityEntryCount + } + setInt32(firstSegment, tempLoc); + setInt32(fragmentsPerSegment, tempLoc + 4); + } + + asrt_runtable ASRT::getSegmentRun(long no){ + asrt_runtable res; + if (no >= getSegmentRunEntryCount()){ + return res; + } + int tempLoc = 5; //position of qualityentry count; + for (int i = 0; i < getQualityEntryCount(); ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } + int countLoc = tempLoc; + tempLoc += 4 + 8 * no; res.firstSegment = getInt32(tempLoc); - res.fragmentsPerSegment = getInt32(tempLoc+4); + res.fragmentsPerSegment = getInt32(tempLoc + 4); return res; } - + std::string ASRT::toPrettyString(int indent){ std::stringstream r; r << std::string(indent, ' ') << "[asrt] Segment Run Table (" << boxedSize() << ")" << std::endl; - r << std::string(indent+1, ' ') << "Version " << getVersion() << std::endl; + r << std::string(indent + 1, ' ') << "Version " << getVersion() << std::endl; if (getUpdate()){ - r << std::string(indent+1, ' ') << "Update" << std::endl; + r << std::string(indent + 1, ' ') << "Update" << std::endl; }else{ - r << std::string(indent+1, ' ') << "Replacement or new table" << std::endl; + r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; } - r << std::string(indent+1, ' ') << "QualityEntryTable (" << getQualityEntryCount() << ")" << std::endl; - for( int i = 0; i < getQualityEntryCount(); i++ ) { - r << std::string(indent+2, ' ') << i << ": " << getQualityEntry(i) << std::endl; + r << std::string(indent + 1, ' ') << "QualityEntryTable (" << getQualityEntryCount() << ")" << std::endl; + for (int i = 0; i < getQualityEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; } - r << std::string(indent+1, ' ') << "SegmentRunEntryTable (" << getSegmentRunEntryCount()<< ")" << std::endl; - for( int i = 0; i < getSegmentRunEntryCount(); i ++ ) { - r << std::string(indent+2, ' ') << i << ": First=" << getSegmentRun(i).firstSegment << ", FragmentsPerSegment=" << getSegmentRun(i).fragmentsPerSegment << std::endl; + r << std::string(indent + 1, ' ') << "SegmentRunEntryTable (" << getSegmentRunEntryCount() << ")" << std::endl; + for (int i = 0; i < getSegmentRunEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": First=" << getSegmentRun(i).firstSegment << ", FragmentsPerSegment=" + << getSegmentRun(i).fragmentsPerSegment << std::endl; } return r.str(); } - + MFHD::MFHD(){ memcpy(data + 4, "mfhd", 4); - setInt32(0,0); + setInt32(0, 0); } - - void MFHD::setSequenceNumber(long newSequenceNumber){setInt32(newSequenceNumber, 4);} - - long MFHD::getSequenceNumber(){return getInt32(4);} - - std::string MFHD::toPrettyString( int indent ) { + + void MFHD::setSequenceNumber(long newSequenceNumber){ + setInt32(newSequenceNumber, 4); + } + + long MFHD::getSequenceNumber(){ + return getInt32(4); + } + + std::string MFHD::toPrettyString(int indent){ std::stringstream r; r << std::string(indent, ' ') << "[mfhd] Movie Fragment Header (" << boxedSize() << ")" << std::endl; - r << std::string(indent+1, ' ') << "SequenceNumber " << getSequenceNumber() << std::endl; + r << std::string(indent + 1, ' ') << "SequenceNumber " << getSequenceNumber() << std::endl; return r.str(); } - + MOOF::MOOF(){ memcpy(data + 4, "moof", 4); } - - long MOOF::getContentCount() { + + long MOOF::getContentCount(){ int res = 0; int tempLoc = 0; - while (tempLoc < boxedSize()-8){ + while (tempLoc < boxedSize() - 8){ res++; tempLoc += getBoxLen(tempLoc); } return res; } - + void MOOF::setContent(Box & newContent, long no){ int tempLoc = 0; int contentCount = getContentCount(); for (int i = 0; i < no; i++){ if (i < contentCount){ tempLoc += getBoxLen(tempLoc); - } else { - if(!reserve(tempLoc, 0, (no - contentCount)*8)){return;}; - memset(data+tempLoc, 0, (no - contentCount)*8); - tempLoc += (no - contentCount)*8; + }else{ + if ( !reserve(tempLoc, 0, (no - contentCount) * 8)){ + return; + }; + memset(data + tempLoc, 0, (no - contentCount) * 8); + tempLoc += (no - contentCount) * 8; break; } } setBox(newContent, tempLoc); } - + Box & MOOF::getContent(long no){ static Box ret = Box((char*)"\000\000\000\010erro", false); - if (no > getContentCount()){return ret;} + if (no > getContentCount()){ + return ret; + } int i = 0; int tempLoc = 0; while (i < no){ @@ -984,54 +1224,58 @@ namespace MP4{ } return getBox(tempLoc); } - - std::string MOOF::toPrettyString( int indent ) { + + std::string MOOF::toPrettyString(int indent){ std::stringstream r; r << std::string(indent, ' ') << "[moof] Movie Fragment Box (" << boxedSize() << ")" << std::endl; Box curBox; int tempLoc = 0; int contentCount = getContentCount(); - for( int i = 0; i < contentCount; i++ ) { + for (int i = 0; i < contentCount; i++){ curBox = getContent(i); - r << curBox.toPrettyString(indent+1); + r << curBox.toPrettyString(indent + 1); tempLoc += getBoxLen(tempLoc); } return r.str(); } - + TRAF::TRAF(){ memcpy(data + 4, "traf", 4); } - long TRAF::getContentCount() { + long TRAF::getContentCount(){ int res = 0; int tempLoc = 0; - while (tempLoc < boxedSize()-8){ + while (tempLoc < boxedSize() - 8){ res++; tempLoc += getBoxLen(tempLoc); } return res; } - + void TRAF::setContent(Box & newContent, long no){ int tempLoc = 0; int contentCount = getContentCount(); for (int i = 0; i < no; i++){ if (i < contentCount){ tempLoc += getBoxLen(tempLoc); - } else { - if(!reserve(tempLoc, 0, (no - contentCount)*8)){return;}; - memset(data+tempLoc, 0, (no - contentCount)*8); - tempLoc += (no - contentCount)*8; + }else{ + if ( !reserve(tempLoc, 0, (no - contentCount) * 8)){ + return; + }; + memset(data + tempLoc, 0, (no - contentCount) * 8); + tempLoc += (no - contentCount) * 8; break; } } setBox(newContent, tempLoc); } - - Box & TRAF::getContent( long no ){ + + Box & TRAF::getContent(long no){ static Box ret = Box((char*)"\000\000\000\010erro", false); - if (no > getContentCount()){return ret;} + if (no > getContentCount()){ + return ret; + } int i = 0; int tempLoc = 0; while (i < no){ @@ -1040,30 +1284,27 @@ namespace MP4{ } return getBox(tempLoc); } - - std::string TRAF::toPrettyString( int indent ) { + + std::string TRAF::toPrettyString(int indent){ std::stringstream r; r << std::string(indent, ' ') << "[traf] Track Fragment Box (" << boxedSize() << ")" << std::endl; Box curBox; int tempLoc = 0; int contentCount = getContentCount(); - for( int i = 0; i < contentCount; i++ ) { + for (int i = 0; i < contentCount; i++){ curBox = getContent(i); - r << curBox.toPrettyString(indent+1); + r << curBox.toPrettyString(indent + 1); tempLoc += curBox.boxedSize(); } return r.str(); } - - - TRUN::TRUN(){ memcpy(data + 4, "trun", 4); } void TRUN::setFlags(long newFlags){ - setInt24(newFlags,1); + setInt24(newFlags, 1); } long TRUN::getFlags(){ @@ -1085,7 +1326,9 @@ namespace MP4{ } void TRUN::setFirstSampleFlags(long newSampleFlags){ - if (!(getFlags() & trunfirstSampleFlags)){return;} + if ( !(getFlags() & trunfirstSampleFlags)){ + return; + } if (getFlags() & trundataOffset){ setInt32(newSampleFlags, 12); }else{ @@ -1094,7 +1337,9 @@ namespace MP4{ } long TRUN::getFirstSampleFlags(){ - if (!(getFlags() & trunfirstSampleFlags)){return 0;} + if ( !(getFlags() & trunfirstSampleFlags)){ + return 0; + } if (getFlags() & trundataOffset){ return getInt32(12); }else{ @@ -1109,32 +1354,44 @@ namespace MP4{ void TRUN::setSampleInformation(trunSampleInformation newSample, long no){ long flags = getFlags(); long sampInfoSize = 0; - if (flags & trunsampleDuration){sampInfoSize += 4;} - if (flags & trunsampleSize){sampInfoSize += 4;} - if (flags & trunsampleFlags){sampInfoSize += 4;} - if (flags & trunsampleOffsets){sampInfoSize += 4;} + if (flags & trunsampleDuration){ + sampInfoSize += 4; + } + if (flags & trunsampleSize){ + sampInfoSize += 4; + } + if (flags & trunsampleFlags){ + sampInfoSize += 4; + } + if (flags & trunsampleOffsets){ + sampInfoSize += 4; + } long offset = 8; - if (flags & trundataOffset){offset += 4;} - if (flags & trunfirstSampleFlags){offset += 4;} + if (flags & trundataOffset){ + offset += 4; + } + if (flags & trunfirstSampleFlags){ + offset += 4; + } long innerOffset = 0; if (flags & trunsampleDuration){ - setInt32(newSample.sampleDuration, offset + no*sampInfoSize + innerOffset); + setInt32(newSample.sampleDuration, offset + no * sampInfoSize + innerOffset); innerOffset += 4; } if (flags & trunsampleSize){ - setInt32(newSample.sampleSize, offset + no*sampInfoSize + innerOffset); + setInt32(newSample.sampleSize, offset + no * sampInfoSize + innerOffset); innerOffset += 4; } if (flags & trunsampleFlags){ - setInt32(newSample.sampleFlags, offset + no*sampInfoSize + innerOffset); + setInt32(newSample.sampleFlags, offset + no * sampInfoSize + innerOffset); innerOffset += 4; } if (flags & trunsampleOffsets){ - setInt32(newSample.sampleOffset, offset + no*sampInfoSize + innerOffset); + setInt32(newSample.sampleOffset, offset + no * sampInfoSize + innerOffset); innerOffset += 4; } - if (getSampleInformationCount() < no+1){ - setInt32(no+1,4); + if (getSampleInformationCount() < no + 1){ + setInt32(no + 1, 4); } } @@ -1144,31 +1401,45 @@ namespace MP4{ ret.sampleSize = 0; ret.sampleFlags = 0; ret.sampleOffset = 0; - if (getSampleInformationCount() < no+1){return ret;} + if (getSampleInformationCount() < no + 1){ + return ret; + } long flags = getFlags(); long sampInfoSize = 0; - if (flags & trunsampleDuration){sampInfoSize += 4;} - if (flags & trunsampleSize){sampInfoSize += 4;} - if (flags & trunsampleFlags){sampInfoSize += 4;} - if (flags & trunsampleOffsets){sampInfoSize += 4;} + if (flags & trunsampleDuration){ + sampInfoSize += 4; + } + if (flags & trunsampleSize){ + sampInfoSize += 4; + } + if (flags & trunsampleFlags){ + sampInfoSize += 4; + } + if (flags & trunsampleOffsets){ + sampInfoSize += 4; + } long offset = 8; - if (flags & trundataOffset){offset += 4;} - if (flags & trunfirstSampleFlags){offset += 4;} + if (flags & trundataOffset){ + offset += 4; + } + if (flags & trunfirstSampleFlags){ + offset += 4; + } long innerOffset = 0; if (flags & trunsampleDuration){ - ret.sampleDuration = getInt32(offset + no*sampInfoSize + innerOffset); + ret.sampleDuration = getInt32(offset + no * sampInfoSize + innerOffset); innerOffset += 4; } if (flags & trunsampleSize){ - ret.sampleSize = getInt32(offset + no*sampInfoSize + innerOffset); + ret.sampleSize = getInt32(offset + no * sampInfoSize + innerOffset); innerOffset += 4; } if (flags & trunsampleFlags){ - ret.sampleFlags = getInt32(offset + no*sampInfoSize + innerOffset); + ret.sampleFlags = getInt32(offset + no * sampInfoSize + innerOffset); innerOffset += 4; } if (flags & trunsampleOffsets){ - ret.sampleOffset = getInt32(offset + no*sampInfoSize + innerOffset); + ret.sampleOffset = getInt32(offset + no * sampInfoSize + innerOffset); innerOffset += 4; } return ret; @@ -1177,36 +1448,52 @@ namespace MP4{ std::string TRUN::toPrettyString(long indent){ std::stringstream r; r << std::string(indent, ' ') << "[trun] Track Fragment Run (" << boxedSize() << ")" << std::endl; - r << std::string(indent+1, ' ') << "Version " << (int)getInt8(0) << std::endl; - - long flags = getFlags(); - r << std::string(indent+1, ' ') << "Flags"; - if (flags & trundataOffset){r << " dataOffset";} - if (flags & trunfirstSampleFlags){r << " firstSampleFlags";} - if (flags & trunsampleDuration){r << " sampleDuration";} - if (flags & trunsampleSize){r << " sampleSize";} - if (flags & trunsampleFlags){r << " sampleFlags";} - if (flags & trunsampleOffsets){r << " sampleOffsets";} - r << std::endl; - - if (flags & trundataOffset){r << std::string(indent+1, ' ') << "Data Offset " << getDataOffset() << std::endl;} - if (flags & trundataOffset){r << std::string(indent+1, ' ') << "Sample Flags" << prettySampleFlags(getFirstSampleFlags()) << std::endl;} + r << std::string(indent + 1, ' ') << "Version " << (int)getInt8(0) << std::endl; - r << std::string(indent+1, ' ') << "SampleInformation (" << getSampleInformationCount() << "):" << std::endl; + long flags = getFlags(); + r << std::string(indent + 1, ' ') << "Flags"; + if (flags & trundataOffset){ + r << " dataOffset"; + } + if (flags & trunfirstSampleFlags){ + r << " firstSampleFlags"; + } + if (flags & trunsampleDuration){ + r << " sampleDuration"; + } + if (flags & trunsampleSize){ + r << " sampleSize"; + } + if (flags & trunsampleFlags){ + r << " sampleFlags"; + } + if (flags & trunsampleOffsets){ + r << " sampleOffsets"; + } + r << std::endl; + + if (flags & trundataOffset){ + r << std::string(indent + 1, ' ') << "Data Offset " << getDataOffset() << std::endl; + } + if (flags & trundataOffset){ + r << std::string(indent + 1, ' ') << "Sample Flags" << prettySampleFlags(getFirstSampleFlags()) << std::endl; + } + + r << std::string(indent + 1, ' ') << "SampleInformation (" << getSampleInformationCount() << "):" << std::endl; for (int i = 0; i < getSampleInformationCount(); ++i){ - r << std::string(indent+2, ' ') << "[" << i << "]" << std::endl; + r << std::string(indent + 2, ' ') << "[" << i << "]" << std::endl; trunSampleInformation samp = getSampleInformation(i); if (flags & trunsampleDuration){ - r << std::string(indent+2, ' ') << "Duration " << samp.sampleDuration << std::endl; + r << std::string(indent + 2, ' ') << "Duration " << samp.sampleDuration << std::endl; } if (flags & trunsampleSize){ - r << std::string(indent+2, ' ') << "Size " << samp.sampleSize << std::endl; + r << std::string(indent + 2, ' ') << "Size " << samp.sampleSize << std::endl; } if (flags & trunsampleFlags){ - r << std::string(indent+2, ' ') << "Flags " << prettySampleFlags(samp.sampleFlags) << std::endl; + r << std::string(indent + 2, ' ') << "Flags " << prettySampleFlags(samp.sampleFlags) << std::endl; } if (flags & trunsampleOffsets){ - r << std::string(indent+2, ' ') << "Offset " << samp.sampleOffset << std::endl; + r << std::string(indent + 2, ' ') << "Offset " << samp.sampleOffset << std::endl; } } @@ -1215,13 +1502,29 @@ namespace MP4{ std::string prettySampleFlags(long flag){ std::stringstream r; - if (flag & noIPicture){r << " noIPicture";} - if (flag & isIPicture){r << " isIPicture";} - if (flag & noDisposable){r << " noDisposable";} - if (flag & isDisposable){r << " isDisposable";} - if (flag & isRedundant){r << " isRedundant";} - if (flag & noRedundant){r << " noRedundant";} - if (flag & noKeySample){r << " noKeySample";}else{r << " isKeySample";} + if (flag & noIPicture){ + r << " noIPicture"; + } + if (flag & isIPicture){ + r << " isIPicture"; + } + if (flag & noDisposable){ + r << " noDisposable"; + } + if (flag & isDisposable){ + r << " isDisposable"; + } + if (flag & isRedundant){ + r << " isRedundant"; + } + if (flag & noRedundant){ + r << " noRedundant"; + } + if (flag & noKeySample){ + r << " noKeySample"; + }else{ + r << " isKeySample"; + } return r.str(); } @@ -1230,7 +1533,7 @@ namespace MP4{ } void TFHD::setFlags(long newFlags){ - setInt24(newFlags,1); + setInt24(newFlags, 1); } long TFHD::getFlags(){ @@ -1238,7 +1541,7 @@ namespace MP4{ } void TFHD::setTrackID(long newID){ - setInt32(newID,4); + setInt32(newID, 4); } long TFHD::getTrackID(){ @@ -1250,7 +1553,7 @@ namespace MP4{ setInt64(newOffset, 8); } } - + long long TFHD::getBaseDataOffset(){ if (getFlags() & tfhdBaseOffset){ return getInt64(8); @@ -1258,123 +1561,201 @@ namespace MP4{ return 0; } } - + void TFHD::setSampleDescriptionIndex(long newIndex){ - if (!(getFlags() & tfhdSampleDesc)){return;} + if ( !(getFlags() & tfhdSampleDesc)){ + return; + } int offset = 8; - if (getFlags() & tfhdBaseOffset){offset += 8;} + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } setInt32(newIndex, offset); } - + long TFHD::getSampleDescriptionIndex(){ - if (!(getFlags() & tfhdSampleDesc)){return 0;} + if ( !(getFlags() & tfhdSampleDesc)){ + return 0; + } int offset = 8; - if (getFlags() & tfhdBaseOffset){offset += 8;} + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } return getInt32(offset); } - + void TFHD::setDefaultSampleDuration(long newDuration){ - if (!(getFlags() & tfhdSampleDura)){return;} + if ( !(getFlags() & tfhdSampleDura)){ + return; + } int offset = 8; - if (getFlags() & tfhdBaseOffset){offset += 8;} - if (getFlags() & tfhdSampleDesc){offset += 4;} + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } setInt32(newDuration, offset); } - + long TFHD::getDefaultSampleDuration(){ - if (!(getFlags() & tfhdSampleDura)){return 0;} + if ( !(getFlags() & tfhdSampleDura)){ + return 0; + } int offset = 8; - if (getFlags() & tfhdBaseOffset){offset += 8;} - if (getFlags() & tfhdSampleDesc){offset += 4;} + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } return getInt32(offset); } - + void TFHD::setDefaultSampleSize(long newSize){ - if (!(getFlags() & tfhdSampleSize)){return;} + if ( !(getFlags() & tfhdSampleSize)){ + return; + } int offset = 8; - if (getFlags() & tfhdBaseOffset){offset += 8;} - if (getFlags() & tfhdSampleDesc){offset += 4;} - if (getFlags() & tfhdSampleDura){offset += 4;} + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + if (getFlags() & tfhdSampleDura){ + offset += 4; + } setInt32(newSize, offset); } - + long TFHD::getDefaultSampleSize(){ - if (!(getFlags() & tfhdSampleSize)){return 0;} + if ( !(getFlags() & tfhdSampleSize)){ + return 0; + } int offset = 8; - if (getFlags() & tfhdBaseOffset){offset += 8;} - if (getFlags() & tfhdSampleDesc){offset += 4;} - if (getFlags() & tfhdSampleDura){offset += 4;} + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + if (getFlags() & tfhdSampleDura){ + offset += 4; + } return getInt32(offset); } - + void TFHD::setDefaultSampleFlags(long newFlags){ - if (!(getFlags() & tfhdSampleFlag)){return;} + if ( !(getFlags() & tfhdSampleFlag)){ + return; + } int offset = 8; - if (getFlags() & tfhdBaseOffset){offset += 8;} - if (getFlags() & tfhdSampleDesc){offset += 4;} - if (getFlags() & tfhdSampleDura){offset += 4;} - if (getFlags() & tfhdSampleSize){offset += 4;} + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + if (getFlags() & tfhdSampleDura){ + offset += 4; + } + if (getFlags() & tfhdSampleSize){ + offset += 4; + } setInt32(newFlags, offset); } - + long TFHD::getDefaultSampleFlags(){ - if (!(getFlags() & tfhdSampleFlag)){return 0;} + if ( !(getFlags() & tfhdSampleFlag)){ + return 0; + } int offset = 8; - if (getFlags() & tfhdBaseOffset){offset += 8;} - if (getFlags() & tfhdSampleDesc){offset += 4;} - if (getFlags() & tfhdSampleDura){offset += 4;} - if (getFlags() & tfhdSampleSize){offset += 4;} + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + if (getFlags() & tfhdSampleDura){ + offset += 4; + } + if (getFlags() & tfhdSampleSize){ + offset += 4; + } return getInt32(offset); } - + std::string TFHD::toPrettyString(long indent){ std::stringstream r; r << std::string(indent, ' ') << "[tfhd] Track Fragment Header (" << boxedSize() << ")" << std::endl; - r << std::string(indent+1, ' ') << "Version " << (int)getInt8(0) << std::endl; - - long flags = getFlags(); - r << std::string(indent+1, ' ') << "Flags"; - if (flags & tfhdBaseOffset){r << " BaseOffset";} - if (flags & tfhdSampleDesc){r << " SampleDesc";} - if (flags & tfhdSampleDura){r << " SampleDura";} - if (flags & tfhdSampleSize){r << " SampleSize";} - if (flags & tfhdSampleFlag){r << " SampleFlag";} - if (flags & tfhdNoDuration){r << " NoDuration";} - r << std::endl; - - r << std::string(indent+1, ' ') << "TrackID " << getTrackID() << std::endl; + r << std::string(indent + 1, ' ') << "Version " << (int)getInt8(0) << std::endl; + + long flags = getFlags(); + r << std::string(indent + 1, ' ') << "Flags"; + if (flags & tfhdBaseOffset){ + r << " BaseOffset"; + } + if (flags & tfhdSampleDesc){ + r << " SampleDesc"; + } + if (flags & tfhdSampleDura){ + r << " SampleDura"; + } + if (flags & tfhdSampleSize){ + r << " SampleSize"; + } + if (flags & tfhdSampleFlag){ + r << " SampleFlag"; + } + if (flags & tfhdNoDuration){ + r << " NoDuration"; + } + r << std::endl; + + r << std::string(indent + 1, ' ') << "TrackID " << getTrackID() << std::endl; + + if (flags & tfhdBaseOffset){ + r << std::string(indent + 1, ' ') << "Base Offset " << getBaseDataOffset() << std::endl; + } + if (flags & tfhdSampleDesc){ + r << std::string(indent + 1, ' ') << "Sample Description Index " << getSampleDescriptionIndex() << std::endl; + } + if (flags & tfhdSampleDura){ + r << std::string(indent + 1, ' ') << "Default Sample Duration " << getDefaultSampleDuration() << std::endl; + } + if (flags & tfhdSampleSize){ + r << std::string(indent + 1, ' ') << "Default Same Size " << getDefaultSampleSize() << std::endl; + } + if (flags & tfhdSampleFlag){ + r << std::string(indent + 1, ' ') << "Default Sample Flags " << prettySampleFlags(getDefaultSampleFlags()) << std::endl; + } - if (flags & tfhdBaseOffset){r << std::string(indent+1, ' ') << "Base Offset " << getBaseDataOffset() << std::endl;} - if (flags & tfhdSampleDesc){r << std::string(indent+1, ' ') << "Sample Description Index " << getSampleDescriptionIndex() << std::endl;} - if (flags & tfhdSampleDura){r << std::string(indent+1, ' ') << "Default Sample Duration " << getDefaultSampleDuration() << std::endl;} - if (flags & tfhdSampleSize){r << std::string(indent+1, ' ') << "Default Same Size " << getDefaultSampleSize() << std::endl;} - if (flags & tfhdSampleFlag){r << std::string(indent+1, ' ') << "Default Sample Flags " << prettySampleFlags(getDefaultSampleFlags()) << std::endl;} - return r.str(); } AFRA::AFRA(){ memcpy(data + 4, "afra", 4); - setInt32(0, 9);//entrycount = 0 + setInt32(0, 9); //entrycount = 0 setFlags(0); } - + void AFRA::setVersion(long newVersion){ setInt8(newVersion, 0); } - + long AFRA::getVersion(){ return getInt8(0); } - + void AFRA::setFlags(long newFlags){ setInt24(newFlags, 1); } - + long AFRA::getFlags(){ return getInt24(1); } - + void AFRA::setLongIDs(bool newVal){ if (newVal){ setInt8((getInt8(4) & 0x7F) + 0x80, 4); @@ -1382,7 +1763,7 @@ namespace MP4{ setInt8((getInt8(4) & 0x7F), 4); } } - + bool AFRA::getLongIDs(){ return getInt8(4) & 0x80; } @@ -1394,11 +1775,11 @@ namespace MP4{ setInt8((getInt8(4) & 0xBF), 4); } } - + bool AFRA::getLongOffsets(){ return getInt8(4) & 0x40; } - + void AFRA::setGlobalEntries(bool newVal){ if (newVal){ setInt8((getInt8(4) & 0xDF) + 0x20, 4); @@ -1406,103 +1787,127 @@ namespace MP4{ setInt8((getInt8(4) & 0xDF), 4); } } - + bool AFRA::getGlobalEntries(){ return getInt8(4) & 0x20; } - + void AFRA::setTimeScale(long newVal){ setInt32(newVal, 5); } - + long AFRA::getTimeScale(){ return getInt32(5); } - + long AFRA::getEntryCount(){ return getInt32(9); } - + void AFRA::setEntry(afraentry newEntry, long no){ int entrysize = 12; - if (getLongOffsets()){entrysize = 16;} - setInt64(newEntry.time, 13+entrysize*no); if (getLongOffsets()){ - setInt64(newEntry.offset, 21+entrysize*no); - }else{ - setInt32(newEntry.offset, 21+entrysize*no); + entrysize = 16; + } + setInt64(newEntry.time, 13 + entrysize * no); + if (getLongOffsets()){ + setInt64(newEntry.offset, 21 + entrysize * no); + }else{ + setInt32(newEntry.offset, 21 + entrysize * no); + } + if (no + 1 > getEntryCount()){ + setInt32(no + 1, 9); } - if (no+1 > getEntryCount()){setInt32(no+1, 9);} } - + afraentry AFRA::getEntry(long no){ afraentry ret; int entrysize = 12; - if (getLongOffsets()){entrysize = 16;} - ret.time = getInt64(13+entrysize*no); if (getLongOffsets()){ - ret.offset = getInt64(21+entrysize*no); + entrysize = 16; + } + ret.time = getInt64(13 + entrysize * no); + if (getLongOffsets()){ + ret.offset = getInt64(21 + entrysize * no); }else{ - ret.offset = getInt32(21+entrysize*no); + ret.offset = getInt32(21 + entrysize * no); } return ret; } - + long AFRA::getGlobalEntryCount(){ - if (!getGlobalEntries()){return 0;} + if ( !getGlobalEntries()){ + return 0; + } int entrysize = 12; - if (getLongOffsets()){entrysize = 16;} - return getInt32(13+entrysize*getEntryCount()); + if (getLongOffsets()){ + entrysize = 16; + } + return getInt32(13 + entrysize * getEntryCount()); } void AFRA::setGlobalEntry(globalafraentry newEntry, long no){ - int offset = 13+12*getEntryCount()+4; - if (getLongOffsets()){offset = 13+16*getEntryCount()+4;} + int offset = 13 + 12 * getEntryCount() + 4; + if (getLongOffsets()){ + offset = 13 + 16 * getEntryCount() + 4; + } int entrysize = 20; - if (getLongIDs()){entrysize += 4;} - if (getLongOffsets()){entrysize += 8;} - - setInt64(newEntry.time, offset+entrysize*no); if (getLongIDs()){ - setInt32(newEntry.segment, offset+entrysize*no+8); - setInt32(newEntry.fragment, offset+entrysize*no+12); - }else{ - setInt16(newEntry.segment, offset+entrysize*no+8); - setInt16(newEntry.fragment, offset+entrysize*no+10); + entrysize += 4; } if (getLongOffsets()){ - setInt64(newEntry.afraoffset, offset+entrysize*no+entrysize-16); - setInt64(newEntry.offsetfromafra, offset+entrysize*no+entrysize-8); - }else{ - setInt32(newEntry.afraoffset, offset+entrysize*no+entrysize-8); - setInt32(newEntry.offsetfromafra, offset+entrysize*no+entrysize-4); + entrysize += 8; + } + + setInt64(newEntry.time, offset + entrysize * no); + if (getLongIDs()){ + setInt32(newEntry.segment, offset + entrysize * no + 8); + setInt32(newEntry.fragment, offset + entrysize * no + 12); + }else{ + setInt16(newEntry.segment, offset + entrysize * no + 8); + setInt16(newEntry.fragment, offset + entrysize * no + 10); + } + if (getLongOffsets()){ + setInt64(newEntry.afraoffset, offset + entrysize * no + entrysize - 16); + setInt64(newEntry.offsetfromafra, offset + entrysize * no + entrysize - 8); + }else{ + setInt32(newEntry.afraoffset, offset + entrysize * no + entrysize - 8); + setInt32(newEntry.offsetfromafra, offset + entrysize * no + entrysize - 4); + } + + if (getInt32(offset - 4) < no + 1){ + setInt32(no + 1, offset - 4); } - - if (getInt32(offset-4) < no+1){setInt32(no+1, offset-4);} } globalafraentry AFRA::getGlobalEntry(long no){ globalafraentry ret; - int offset = 13+12*getEntryCount()+4; - if (getLongOffsets()){offset = 13+16*getEntryCount()+4;} + int offset = 13 + 12 * getEntryCount() + 4; + if (getLongOffsets()){ + offset = 13 + 16 * getEntryCount() + 4; + } int entrysize = 20; - if (getLongIDs()){entrysize += 4;} - if (getLongOffsets()){entrysize += 8;} - - ret.time = getInt64(offset+entrysize*no); if (getLongIDs()){ - ret.segment = getInt32(offset+entrysize*no+8); - ret.fragment = getInt32(offset+entrysize*no+12); - }else{ - ret.segment = getInt16(offset+entrysize*no+8); - ret.fragment = getInt16(offset+entrysize*no+10); + entrysize += 4; } if (getLongOffsets()){ - ret.afraoffset = getInt64(offset+entrysize*no+entrysize-16); - ret.offsetfromafra = getInt64(offset+entrysize*no+entrysize-8); + entrysize += 8; + } + + ret.time = getInt64(offset + entrysize * no); + if (getLongIDs()){ + ret.segment = getInt32(offset + entrysize * no + 8); + ret.fragment = getInt32(offset + entrysize * no + 12); }else{ - ret.afraoffset = getInt32(offset+entrysize*no+entrysize-8); - ret.offsetfromafra = getInt32(offset+entrysize*no+entrysize-4); + ret.segment = getInt16(offset + entrysize * no + 8); + ret.fragment = getInt16(offset + entrysize * no + 10); + } + if (getLongOffsets()){ + ret.afraoffset = getInt64(offset + entrysize * no + entrysize - 16); + ret.offsetfromafra = getInt64(offset + entrysize * no + entrysize - 8); + }else{ + ret.afraoffset = getInt32(offset + entrysize * no + entrysize - 8); + ret.offsetfromafra = getInt32(offset + entrysize * no + entrysize - 4); } return ret; } @@ -1510,165 +1915,168 @@ namespace MP4{ std::string AFRA::toPrettyString(long indent){ std::stringstream r; r << std::string(indent, ' ') << "[afra] Fragment Random Access (" << boxedSize() << ")" << std::endl; - r << std::string(indent+1, ' ') << "Version " << getVersion() << std::endl; - r << std::string(indent+1, ' ') << "Flags " << getFlags() << std::endl; - r << std::string(indent+1, ' ') << "Long IDs " << getLongIDs() << std::endl; - r << std::string(indent+1, ' ') << "Long Offsets " << getLongOffsets() << std::endl; - r << std::string(indent+1, ' ') << "Global Entries " << getGlobalEntries() << std::endl; - r << std::string(indent+1, ' ') << "TimeScale " << getTimeScale() << std::endl; + r << std::string(indent + 1, ' ') << "Version " << getVersion() << std::endl; + r << std::string(indent + 1, ' ') << "Flags " << getFlags() << std::endl; + r << std::string(indent + 1, ' ') << "Long IDs " << getLongIDs() << std::endl; + r << std::string(indent + 1, ' ') << "Long Offsets " << getLongOffsets() << std::endl; + r << std::string(indent + 1, ' ') << "Global Entries " << getGlobalEntries() << std::endl; + r << std::string(indent + 1, ' ') << "TimeScale " << getTimeScale() << std::endl; long count = getEntryCount(); - r << std::string(indent+1, ' ') << "Entries (" << count << ") " << std::endl; + r << std::string(indent + 1, ' ') << "Entries (" << count << ") " << std::endl; for (long i = 0; i < count; ++i){ afraentry tmpent = getEntry(i); - r << std::string(indent+1, ' ') << i << ": Time " << tmpent.time << ", Offset " << tmpent.offset << std::endl; + r << std::string(indent + 1, ' ') << i << ": Time " << tmpent.time << ", Offset " << tmpent.offset << std::endl; } if (getGlobalEntries()){ count = getGlobalEntryCount(); - r << std::string(indent+1, ' ') << "Global Entries (" << count << ") " << std::endl; + r << std::string(indent + 1, ' ') << "Global Entries (" << count << ") " << std::endl; for (long i = 0; i < count; ++i){ globalafraentry tmpent = getGlobalEntry(i); - r << std::string(indent+1, ' ') << i << ": T " << tmpent.time << ", S" << tmpent.segment << "F" << tmpent.fragment << ", " << tmpent.afraoffset << "/" << tmpent.offsetfromafra << std::endl; + r << std::string(indent + 1, ' ') << i << ": T " << tmpent.time << ", S" << tmpent.segment << "F" << tmpent.fragment << ", " + << tmpent.afraoffset << "/" << tmpent.offsetfromafra << std::endl; } } - + return r.str(); } - AVCC::AVCC() { + AVCC::AVCC(){ memcpy(data + 4, "avcC", 4); - setInt8( 0xFF, 4 );//reserved + 4-bytes NAL length + setInt8(0xFF, 4); //reserved + 4-bytes NAL length } - - void AVCC::setVersion( long newVersion ) { - setInt8( newVersion, 0 ); + + void AVCC::setVersion(long newVersion){ + setInt8(newVersion, 0); } - - long AVCC::getVersion( ) { - return getInt8( 0 ); + + long AVCC::getVersion(){ + return getInt8(0); } - - void AVCC::setProfile( long newProfile ) { - setInt8( newProfile, 1 ); + + void AVCC::setProfile(long newProfile){ + setInt8(newProfile, 1); } - - long AVCC::getProfile( ) { - return getInt8( 1 ); + + long AVCC::getProfile(){ + return getInt8(1); } - - void AVCC::setCompatibleProfiles( long newCompatibleProfiles ) { - setInt8( newCompatibleProfiles, 2 ); + + void AVCC::setCompatibleProfiles(long newCompatibleProfiles){ + setInt8(newCompatibleProfiles, 2); } - - long AVCC::getCompatibleProfiles( ) { - return getInt8( 2 ); + + long AVCC::getCompatibleProfiles(){ + return getInt8(2); } - - void AVCC::setLevel( long newLevel ) { - setInt8( newLevel, 3 ); + + void AVCC::setLevel(long newLevel){ + setInt8(newLevel, 3); } - - long AVCC::getLevel( ) { - return getInt8( 3 ); + + long AVCC::getLevel(){ + return getInt8(3); } - - void AVCC::setSPSNumber( long newSPSNumber ) { - setInt8( newSPSNumber, 5 ); + + void AVCC::setSPSNumber(long newSPSNumber){ + setInt8(newSPSNumber, 5); } - - long AVCC::getSPSNumber( ) { - return getInt8( 5 ); + + long AVCC::getSPSNumber(){ + return getInt8(5); } - - void AVCC::setSPS( std::string newSPS ) { - setInt16( newSPS.size(), 6 ); - for( int i = 0; i < newSPS.size(); i++ ) { - setInt8( newSPS[i], 8+i ); - }//not null-terminated + + void AVCC::setSPS(std::string newSPS){ + setInt16(newSPS.size(), 6); + for (int i = 0; i < newSPS.size(); i++){ + setInt8(newSPS[i], 8 + i); + } //not null-terminated } - - long AVCC::getSPSLen( ) { - return getInt16( 6 ); + + long AVCC::getSPSLen(){ + return getInt16(6); } - - char* AVCC::getSPS( ) { + + char* AVCC::getSPS(){ return payload() + 8; } - - void AVCC::setPPSNumber( long newPPSNumber ) { - int offset = 8 + getSPSLen( ); - setInt8( newPPSNumber, offset ); + + void AVCC::setPPSNumber(long newPPSNumber){ + int offset = 8 + getSPSLen(); + setInt8(newPPSNumber, offset); } - - long AVCC::getPPSNumber( ) { - int offset = 8 + getSPSLen( ); - return getInt8( offset ); + + long AVCC::getPPSNumber(){ + int offset = 8 + getSPSLen(); + return getInt8(offset); } - - void AVCC::setPPS( std::string newPPS ) { - int offset = 8 + getSPSLen( ) + 1; - setInt16( newPPS.size(), offset ); - for( int i = 0; i < newPPS.size(); i++ ) { - setInt8( newPPS[i], offset+2+i ); - }//not null-terminated + + void AVCC::setPPS(std::string newPPS){ + int offset = 8 + getSPSLen() + 1; + setInt16(newPPS.size(), offset); + for (int i = 0; i < newPPS.size(); i++){ + setInt8(newPPS[i], offset + 2 + i); + } //not null-terminated } - - long AVCC::getPPSLen( ) { - int offset = 8 + getSPSLen( ) + 1; - return getInt16( offset ); + + long AVCC::getPPSLen(){ + int offset = 8 + getSPSLen() + 1; + return getInt16(offset); } - - char* AVCC::getPPS( ) { - int offset = 8 + getSPSLen( ) + 3; + + char* AVCC::getPPS(){ + int offset = 8 + getSPSLen() + 3; return payload() + offset; } - - std::string AVCC::toPrettyString(long indent) { + + std::string AVCC::toPrettyString(long indent){ std::stringstream r; r << std::string(indent, ' ') << "[avcC] H.264 Init Data (" << boxedSize() << ")" << std::endl; - r << std::string(indent+1, ' ') << "Version: " << getVersion( ) << std::endl; - r << std::string(indent+1, ' ') << "Profile: " << getProfile( ) << std::endl; - r << std::string(indent+1, ' ') << "Compatible Profiles: " << getCompatibleProfiles( ) << std::endl; - r << std::string(indent+1, ' ') << "Level: " << getLevel( ) << std::endl; - r << std::string(indent+1, ' ') << "SPS Number: " << getSPSNumber( ) << std::endl; - r << std::string(indent+2, ' ') << getSPSLen( ) << " of SPS data" << std::endl; - r << std::string(indent+1, ' ') << "PPS Number: " << getPPSNumber( ) << std::endl; - r << std::string(indent+2, ' ') << getPPSLen( ) << " of PPS data" << std::endl; + r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl; + r << std::string(indent + 1, ' ') << "Profile: " << getProfile() << std::endl; + r << std::string(indent + 1, ' ') << "Compatible Profiles: " << getCompatibleProfiles() << std::endl; + r << std::string(indent + 1, ' ') << "Level: " << getLevel() << std::endl; + r << std::string(indent + 1, ' ') << "SPS Number: " << getSPSNumber() << std::endl; + r << std::string(indent + 2, ' ') << getSPSLen() << " of SPS data" << std::endl; + r << std::string(indent + 1, ' ') << "PPS Number: " << getPPSNumber() << std::endl; + r << std::string(indent + 2, ' ') << getPPSLen() << " of PPS data" << std::endl; return r.str(); } - - std::string AVCC::asAnnexB( ) { + + std::string AVCC::asAnnexB(){ std::stringstream r; r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01; - r.write( getSPS( ), getSPSLen() ); + r.write(getSPS(), getSPSLen()); r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01; - r.write( getPPS( ), getPPSLen() ); + r.write(getPPS(), getPPSLen()); return r.str(); } - - void AVCC::setPayload( std::string newPayload ) { - if( ! reserve( 0, payloadSize(), newPayload.size() ) ) { return; } - memcpy( (char*)payload(), (char*)newPayload.c_str(), newPayload.size() ); + + void AVCC::setPayload(std::string newPayload){ + if ( !reserve(0, payloadSize(), newPayload.size())){ + return; + } + memcpy((char*)payload(), (char*)newPayload.c_str(), newPayload.size()); } - - SDTP::SDTP() { + + SDTP::SDTP(){ memcpy(data + 4, "sdtp", 4); } - - void SDTP::setVersion( long newVersion ) { - setInt8( newVersion, 0 ); + + void SDTP::setVersion(long newVersion){ + setInt8(newVersion, 0); } - - long SDTP::getVersion( ) { - return getInt8( 0 ); + + long SDTP::getVersion(){ + return getInt8(0); } - - void SDTP::setValue( long newValue, size_t index ) { - setInt8( newValue, index ); + + void SDTP::setValue(long newValue, size_t index){ + setInt8(newValue, index); } - - long SDTP::getValue( size_t index ) { - getInt8( index ); + + long SDTP::getValue(size_t index){ + getInt8(index); } -}; +} diff --git a/lib/mp4.h b/lib/mp4.h index 2ac0c2d1..032462ef 100644 --- a/lib/mp4.h +++ b/lib/mp4.h @@ -9,36 +9,36 @@ #include "json.h" /// Contains all MP4 format related code. -namespace MP4{ +namespace MP4 { - class Box { + class Box{ public: Box(char * datapointer = 0, bool manage = true); ~Box(); std::string getType(); - bool isType( char* boxType ); + bool isType(const char* boxType); bool read(std::string & newData); long long int boxedSize(); long long int payloadSize(); char * asBox(); char * payload(); void clear(); - std::string toPrettyString( int indent = 0 ); + std::string toPrettyString(int indent = 0); protected: //integer functions - void setInt8( char newData, size_t index ); - char getInt8( size_t index ); - void setInt16( short newData, size_t index ); - short getInt16( size_t index ); - void setInt24( long newData, size_t index ); - long getInt24( size_t index ); - void setInt32( long newData, size_t index ); - long getInt32( size_t index ); - void setInt64( long long int newData, size_t index ); - long long int getInt64( size_t index ); + void setInt8(char newData, size_t index); + char getInt8(size_t index); + void setInt16(short newData, size_t index); + short getInt16(size_t index); + void setInt24(long newData, size_t index); + long getInt24(size_t index); + void setInt32(long newData, size_t index); + long getInt32(size_t index); + void setInt64(long long int newData, size_t index); + long long int getInt64(size_t index); //string functions - void setString(std::string newData, size_t index ); - void setString(char* newData, size_t size, size_t index ); + void setString(std::string newData, size_t index); + void setString(char* newData, size_t size, size_t index); char * getString(size_t index); size_t getStringLen(size_t index); //box functions @@ -51,59 +51,63 @@ namespace MP4{ char * data; ///< Holds the data of this box int data_size; ///< Currently reserved size bool managed; ///< If false, will not attempt to resize/free the data pointer. - int payloadOffset;///= 3 std::cerr << "SIGCHLD received, but no child died"; #endif @@ -41,27 +43,29 @@ void Util::Procs::childsig_handler(int signum){ exitcode = WEXITSTATUS(status); }else if (WIFSIGNALED(status)){ exitcode = -WTERMSIG(status); - }else{/* not possible */return;} + }else{/* not possible */ + return; + } - #if DEBUG >= 1 +#if DEBUG >= 1 std::string pname = plist[ret]; - #endif +#endif plist.erase(ret); - #if DEBUG >= 1 +#if DEBUG >= 1 if (isActive(pname)){ Stop(pname); - }else{ + } else{ //can this ever happen? std::cerr << "Process " << pname << " fully terminated." << std::endl; } - #endif +#endif if (exitHandlers.count(ret) > 0){ TerminationNotifier tn = exitHandlers[ret]; exitHandlers.erase(ret); - #if DEBUG >= 2 +#if DEBUG >= 2 std::cerr << "Calling termination handler for " << pname << std::endl; - #endif +#endif tn(ret, exitcode); } } @@ -84,12 +88,14 @@ void Util::Procs::runCmd(std::string & cmd){ ++i; args[i] = tmp2; } - if (i == 20){args[20] = 0;} + if (i == 20){ + args[20] = 0; + } //execute the command execvp(args[0], args); - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Error running \"" << cmd << "\": " << strerror(errno) << std::endl; - #endif +#endif _exit(42); } @@ -98,11 +104,13 @@ void Util::Procs::runCmd(std::string & cmd){ /// \arg name Name for this process - only used internally. /// \arg cmd Commandline for this process. pid_t Util::Procs::Start(std::string name, std::string cmd){ - if (isActive(name)){return getPid(name);} - if (!handler_set){ + if (isActive(name)){ + return getPid(name); + } + if ( !handler_set){ struct sigaction new_action; new_action.sa_handler = Util::Procs::childsig_handler; - sigemptyset(&new_action.sa_mask); + sigemptyset( &new_action.sa_mask); new_action.sa_flags = 0; sigaction(SIGCHLD, &new_action, NULL); handler_set = true; @@ -112,14 +120,14 @@ pid_t Util::Procs::Start(std::string name, std::string cmd){ runCmd(cmd); }else{ if (ret > 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << std::endl; - #endif +#endif plist.insert(std::pair(ret, name)); }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; - #endif +#endif return 0; } } @@ -132,20 +140,22 @@ pid_t Util::Procs::Start(std::string name, std::string cmd){ /// \arg cmd Commandline for sub (sending) process. /// \arg cmd2 Commandline for main (receiving) process. pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){ - if (isActive(name)){return getPid(name);} - if (!handler_set){ + if (isActive(name)){ + return getPid(name); + } + if ( !handler_set){ struct sigaction new_action; new_action.sa_handler = Util::Procs::childsig_handler; - sigemptyset(&new_action.sa_mask); + sigemptyset( &new_action.sa_mask); new_action.sa_flags = 0; sigaction(SIGCHLD, &new_action, NULL); handler_set = true; } int pfildes[2]; if (pipe(pfildes) == -1){ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl; - #endif +#endif return 0; } @@ -153,7 +163,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){ pid_t ret = fork(); if (ret == 0){ close(pfildes[0]); - dup2(pfildes[1],STDOUT_FILENO); + dup2(pfildes[1], STDOUT_FILENO); close(pfildes[1]); dup2(devnull, STDIN_FILENO); dup2(devnull, STDERR_FILENO); @@ -162,9 +172,9 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){ if (ret > 0){ plist.insert(std::pair(ret, name)); }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; - #endif +#endif close(pfildes[1]); close(pfildes[0]); return 0; @@ -174,21 +184,21 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){ pid_t ret2 = fork(); if (ret2 == 0){ close(pfildes[1]); - dup2(pfildes[0],STDIN_FILENO); + dup2(pfildes[0], STDIN_FILENO); close(pfildes[0]); dup2(devnull, STDOUT_FILENO); dup2(devnull, STDERR_FILENO); runCmd(cmd2); }else{ if (ret2 > 0){ - #if DEBUG >= 1 - std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl; - #endif +#if DEBUG >= 1 + std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl; +#endif plist.insert(std::pair(ret2, name)); }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; - #endif +#endif Stop(name); close(pfildes[1]); close(pfildes[0]); @@ -207,11 +217,13 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){ /// \arg cmd2 Commandline for sub (middle) process. /// \arg cmd3 Commandline for main (receiving) process. pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, std::string cmd3){ - if (isActive(name)){return getPid(name);} - if (!handler_set){ + if (isActive(name)){ + return getPid(name); + } + if ( !handler_set){ struct sigaction new_action; new_action.sa_handler = Util::Procs::childsig_handler; - sigemptyset(&new_action.sa_mask); + sigemptyset( &new_action.sa_mask); new_action.sa_flags = 0; sigaction(SIGCHLD, &new_action, NULL); handler_set = true; @@ -220,23 +232,23 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st int pfildes[2]; int pfildes2[2]; if (pipe(pfildes) == -1){ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl; - #endif +#endif return 0; } if (pipe(pfildes2) == -1){ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl; - #endif +#endif return 0; } - + int devnull = open("/dev/null", O_RDWR); pid_t ret = fork(); if (ret == 0){ close(pfildes[0]); - dup2(pfildes[1],STDOUT_FILENO); + dup2(pfildes[1], STDOUT_FILENO); close(pfildes[1]); dup2(devnull, STDIN_FILENO); dup2(devnull, STDERR_FILENO); @@ -247,9 +259,9 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st if (ret > 0){ plist.insert(std::pair(ret, name)); }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; - #endif +#endif close(pfildes[1]); close(pfildes[0]); close(pfildes2[1]); @@ -257,27 +269,27 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st return 0; } } - + pid_t ret2 = fork(); if (ret2 == 0){ close(pfildes[1]); close(pfildes2[0]); - dup2(pfildes[0],STDIN_FILENO); + dup2(pfildes[0], STDIN_FILENO); close(pfildes[0]); - dup2(pfildes2[1],STDOUT_FILENO); + dup2(pfildes2[1], STDOUT_FILENO); close(pfildes2[1]); dup2(devnull, STDERR_FILENO); runCmd(cmd2); }else{ if (ret2 > 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl; - #endif +#endif plist.insert(std::pair(ret2, name)); }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; - #endif +#endif Stop(name); close(pfildes[1]); close(pfildes[0]); @@ -294,21 +306,21 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st close(pfildes[1]); close(pfildes[0]); close(pfildes2[1]); - dup2(pfildes2[0],STDIN_FILENO); + dup2(pfildes2[0], STDIN_FILENO); close(pfildes2[0]); dup2(devnull, STDOUT_FILENO); dup2(devnull, STDERR_FILENO); runCmd(cmd3); }else{ if (ret3 > 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << ", " << ret3 << "): " << cmd << " | " << cmd2 << " | " << cmd3 << std::endl; - #endif +#endif plist.insert(std::pair(ret3, name)); }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; - #endif +#endif Stop(name); close(pfildes[1]); close(pfildes[0]); @@ -317,7 +329,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st return 0; } } - + return ret3; } @@ -329,118 +341,153 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st /// \arg fdout Same as fdin, but for stdout. /// \arg fdout Same as fdin, but for stderr. pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int * fdout, int * fderr){ - if (isActive(name)){return getPid(name);} + if (isActive(name)){ + return getPid(name); + } pid_t pid; int pipein[2], pipeout[2], pipeerr[2]; - if (!handler_set){ + if ( !handler_set){ struct sigaction new_action; new_action.sa_handler = Util::Procs::childsig_handler; - sigemptyset(&new_action.sa_mask); + sigemptyset( &new_action.sa_mask); new_action.sa_flags = 0; sigaction(SIGCHLD, &new_action, NULL); handler_set = true; } if (fdin && *fdin == -1 && pipe(pipein) < 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Pipe (in) creation failed for " << name << std::endl; - #endif +#endif return 0; } - if (fdout && *fdout == -1 && pipe(pipeout) < 0) { - #if DEBUG >= 1 + if (fdout && *fdout == -1 && pipe(pipeout) < 0){ +#if DEBUG >= 1 std::cerr << "Pipe (out) creation failed for " << name << std::endl; - #endif - if (*fdin == -1){close(pipein[0]);close(pipein[1]);} +#endif + if ( *fdin == -1){ + close(pipein[0]); + close(pipein[1]); + } return 0; } - if (fderr && *fderr == -1 && pipe(pipeerr) < 0) { - #if DEBUG >= 1 + if (fderr && *fderr == -1 && pipe(pipeerr) < 0){ +#if DEBUG >= 1 std::cerr << "Pipe (err) creation failed for " << name << std::endl; - #endif - if (*fdin == -1){close(pipein [0]);close(pipein [1]);} - if (*fdout == -1){close(pipeout[0]);close(pipeout[1]);} +#endif + if ( *fdin == -1){ + close(pipein[0]); + close(pipein[1]); + } + if ( *fdout == -1){ + close(pipeout[0]); + close(pipeout[1]); + } return 0; } int devnull = -1; - if (!fdin || !fdout || !fderr){ + if ( !fdin || !fdout || !fderr){ devnull = open("/dev/null", O_RDWR); if (devnull == -1){ - #if DEBUG >= 1 +#if DEBUG >= 1 std::cerr << "Could not open /dev/null for " << name << ": " << strerror(errno) << std::endl; - #endif - if (*fdin == -1){close(pipein [0]);close(pipein [1]);} - if (*fdout == -1){close(pipeout[0]);close(pipeout[1]);} - if (*fderr == -1){close(pipeerr[0]);close(pipeerr[1]);} +#endif + if ( *fdin == -1){ + close(pipein[0]); + close(pipein[1]); + } + if ( *fdout == -1){ + close(pipeout[0]); + close(pipeout[1]); + } + if ( *fderr == -1){ + close(pipeerr[0]); + close(pipeerr[1]); + } return 0; } } pid = fork(); - if (pid == 0){//child - if (!fdin){ + if (pid == 0){ //child + if ( !fdin){ dup2(devnull, STDIN_FILENO); - }else if (*fdin == -1){ - close(pipein[1]);// close unused write end + }else if ( *fdin == -1){ + close(pipein[1]); // close unused write end dup2(pipein[0], STDIN_FILENO); close(pipein[0]); - }else if (*fdin != STDIN_FILENO){ - dup2(*fdin, STDIN_FILENO); - close(*fdin); + }else if ( *fdin != STDIN_FILENO){ + dup2( *fdin, STDIN_FILENO); + close( *fdin); } - if (!fdout){ + if ( !fdout){ dup2(devnull, STDOUT_FILENO); - }else if (*fdout == -1){ - close(pipeout[0]);// close unused read end + }else if ( *fdout == -1){ + close(pipeout[0]); // close unused read end dup2(pipeout[1], STDOUT_FILENO); close(pipeout[1]); - }else if (*fdout != STDOUT_FILENO){ - dup2(*fdout, STDOUT_FILENO); - close(*fdout); + }else if ( *fdout != STDOUT_FILENO){ + dup2( *fdout, STDOUT_FILENO); + close( *fdout); } - if (!fderr){ + if ( !fderr){ dup2(devnull, STDERR_FILENO); - }else if (*fderr == -1){ - close(pipeerr[0]);// close unused read end + }else if ( *fderr == -1){ + close(pipeerr[0]); // close unused read end dup2(pipeerr[1], STDERR_FILENO); close(pipeerr[1]); - }else if (*fderr != STDERR_FILENO){ - dup2(*fderr, STDERR_FILENO); - close(*fderr); + }else if ( *fderr != STDERR_FILENO){ + dup2( *fderr, STDERR_FILENO); + close( *fderr); + } + if (devnull != -1){ + close(devnull); } - if (devnull != -1){close(devnull);} execvp(argv[0], argv); - #if DEBUG >= 1 +#if DEBUG >= 1 perror("execvp failed"); - #endif +#endif exit(42); - } else if (pid == -1){ - #if DEBUG >= 1 + }else if (pid == -1){ +#if DEBUG >= 1 std::cerr << "Failed to fork for pipe: " << name << std::endl; - #endif - if (fdin && *fdin == -1){close(pipein [0]);close(pipein [1]);} - if (fdout && *fdout == -1){close(pipeout[0]);close(pipeout[1]);} - if (fderr && *fderr == -1){close(pipeerr[0]);close(pipeerr[1]);} - if (devnull != -1){close(devnull);} +#endif + if (fdin && *fdin == -1){ + close(pipein[0]); + close(pipein[1]); + } + if (fdout && *fdout == -1){ + close(pipeout[0]); + close(pipeout[1]); + } + if (fderr && *fderr == -1){ + close(pipeerr[0]); + close(pipeerr[1]); + } + if (devnull != -1){ + close(devnull); + } return 0; - } else{//parent - #if DEBUG >= 1 + }else{ //parent +#if DEBUG >= 1 std::cerr << "Piped process " << name << " started"; - if (fdin ) std::cerr << " in=" << (*fdin == -1 ? pipein [1] : *fdin ); + if (fdin ) std::cerr << " in=" << (*fdin == -1 ? pipein [1] : *fdin ); if (fdout) std::cerr << " out=" << (*fdout == -1 ? pipeout[0] : *fdout); if (fderr) std::cerr << " err=" << (*fderr == -1 ? pipeerr[0] : *fderr); if (devnull != -1) std::cerr << " null=" << devnull; std::cerr << ", PID " << pid << ": " << argv[0] << std::endl; - #endif - if (devnull != -1){close(devnull);} - if (fdin && *fdin == -1){ - close(pipein[0]);// close unused end end +#endif + if (devnull != -1){ + close(devnull); + } + if (fdin && *fdin == -1){ + close(pipein[0]); // close unused end end *fdin = pipein[1]; } if (fdout && *fdout == -1){ - close(pipeout[1]);// close unused write end + close(pipeout[1]); // close unused write end *fdout = pipeout[0]; } if (fderr && *fderr == -1){ - close(pipeerr[1]);// close unused write end + close(pipeerr[1]); // close unused write end *fderr = pipeerr[0]; } plist.insert(std::pair(pid, name)); @@ -448,7 +495,6 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int * return pid; } - /// Stops the named process, if running. /// \arg name (Internal) name of process to stop void Util::Procs::Stop(std::string name){ @@ -456,7 +502,9 @@ void Util::Procs::Stop(std::string name){ while (isActive(name)){ Stop(getPid(name)); max--; - if (max <= 0){return;} + if (max <= 0){ + return; + } } } @@ -472,20 +520,22 @@ void Util::Procs::Stop(pid_t name){ void Util::Procs::StopAll(){ std::map::iterator it; for (it = plist.begin(); it != plist.end(); it++){ - Stop((*it).first); + Stop(( *it).first); } } /// Returns the number of active child processes. int Util::Procs::Count(){ - return plist.size(); + return plist.size(); } /// Returns true if a process by this name is currently active. bool Util::Procs::isActive(std::string name){ std::map::iterator it; for (it = plist.begin(); it != plist.end(); it++){ - if ((*it).second == name){return true;} + if (( *it).second == name){ + return true; + } } return false; } @@ -500,7 +550,9 @@ bool Util::Procs::isActive(pid_t name){ pid_t Util::Procs::getPid(std::string name){ std::map::iterator it; for (it = plist.begin(); it != plist.end(); it++){ - if ((*it).second == name){return (*it).first;} + if (( *it).second == name){ + return ( *it).first; + } } return 0; } diff --git a/lib/procs.h b/lib/procs.h index cc939de8..6f0166e5 100644 --- a/lib/procs.h +++ b/lib/procs.h @@ -7,7 +7,7 @@ #include /// Contains utility code, not directly related to streaming media -namespace Util{ +namespace Util { typedef void (*TerminationNotifier)(pid_t pid, int exitCode); @@ -35,4 +35,4 @@ namespace Util{ static bool SetTerminationNotifier(pid_t pid, TerminationNotifier notifier); }; -}; +} diff --git a/lib/rtmpchunks.cpp b/lib/rtmpchunks.cpp index 1084e004..b150ab97 100644 --- a/lib/rtmpchunks.cpp +++ b/lib/rtmpchunks.cpp @@ -7,7 +7,7 @@ char versionstring[] = "WWW.DDVTECH.COM "; ///< String that is repeated in the RTMP handshake std::string RTMPStream::handshake_in; ///< Input for the handshake. -std::string RTMPStream::handshake_out;///< Output for the handshake. +std::string RTMPStream::handshake_out; ///< Output for the handshake. unsigned int RTMPStream::chunk_rec_max = 128; unsigned int RTMPStream::chunk_snd_max = 128; @@ -39,19 +39,17 @@ std::map RTMPStream::Chunk::lastrecv; "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF" -uint8_t genuineFMSKey[] = { - 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, - 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, // Genuine Adobe Flash Media Server 001 - 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, - 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae -}; // 68 +uint8_t genuineFMSKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, + 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72, + 0x76, // Genuine Adobe Flash Media Server 001 + 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, + 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 68 -uint8_t genuineFPKey[] = { - 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, - 0x50, 0x6c, 0x61, 0x79, // Genuine Adobe Flash Player 001 - 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, - 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae -}; // 62 +uint8_t genuineFPKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, + 0x50, 0x6c, 0x61, + 0x79, // Genuine Adobe Flash Player 001 + 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, + 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 62 inline uint32_t GetDigestOffset(uint8_t *pBuffer, uint8_t scheme){ if (scheme == 0){ @@ -69,7 +67,7 @@ inline uint32_t GetDHOffset(uint8_t *pBuffer, uint8_t scheme){ } } -class DHWrapper { +class DHWrapper{ private: int32_t _bitsCount; DH *_pDH; @@ -89,7 +87,7 @@ class DHWrapper { bool CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength); }; -DHWrapper::DHWrapper(int32_t bitsCount) { +DHWrapper::DHWrapper(int32_t bitsCount){ _bitsCount = bitsCount; _pDH = 0; _pSharedKey = 0; @@ -97,119 +95,172 @@ DHWrapper::DHWrapper(int32_t bitsCount) { _peerPublickey = 0; } -DHWrapper::~DHWrapper() { +DHWrapper::~DHWrapper(){ Cleanup(); } -bool DHWrapper::Initialize() { +bool DHWrapper::Initialize(){ Cleanup(); _pDH = DH_new(); - if (!_pDH){Cleanup(); return false;} + if ( !_pDH){ + Cleanup(); + return false; + } _pDH->p = BN_new(); - if (!_pDH->p){Cleanup(); return false;} + if ( !_pDH->p){ + Cleanup(); + return false; + } _pDH->g = BN_new(); - if (!_pDH->g){Cleanup(); return false;} - if (BN_hex2bn(&_pDH->p, P1024) == 0){Cleanup(); return false;} - if (BN_set_word(_pDH->g, 2) != 1){Cleanup(); return false;} + if ( !_pDH->g){ + Cleanup(); + return false; + } + if (BN_hex2bn( &_pDH->p, P1024) == 0){ + Cleanup(); + return false; + } + if (BN_set_word(_pDH->g, 2) != 1){ + Cleanup(); + return false; + } _pDH->length = _bitsCount; - if (DH_generate_key(_pDH) != 1){Cleanup(); return false;} + if (DH_generate_key(_pDH) != 1){ + Cleanup(); + return false; + } return true; } -bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength) { - if (!_pDH){return false;} +bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength){ + if ( !_pDH){ + return false; + } return CopyKey(_pDH->pub_key, pDst, dstLength); } -bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength) { - if (!_pDH){return false;} +bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength){ + if ( !_pDH){ + return false; + } return CopyKey(_pDH->priv_key, pDst, dstLength); } -bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length) { - if (!_pDH){return false;} - if (_sharedKeyLength != 0 || _pSharedKey){return false;} - +bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length){ + if ( !_pDH){ + return false; + } + if (_sharedKeyLength != 0 || _pSharedKey){ + return false; + } + _sharedKeyLength = DH_size(_pDH); - if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024){return false;} - + if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024){ + return false; + } + _pSharedKey = new uint8_t[_sharedKeyLength]; _peerPublickey = BN_bin2bn(pPeerPublicKey, length, 0); - if (!_peerPublickey){return false;} - - if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength){return false;} - + if ( !_peerPublickey){ + return false; + } + + if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength){ + return false; + } + return true; } -bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength) { - if (!_pDH){return false;} - if (dstLength != _sharedKeyLength){return false;} +bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength){ + if ( !_pDH){ + return false; + } + if (dstLength != _sharedKeyLength){ + return false; + } memcpy(pDst, _pSharedKey, _sharedKeyLength); return true; } -void DHWrapper::Cleanup() { +void DHWrapper::Cleanup(){ if (_pDH){ - if (_pDH->p){BN_free(_pDH->p); _pDH->p = 0;} - if (_pDH->g){BN_free(_pDH->g); _pDH->g = 0;} - DH_free(_pDH); _pDH = 0; + if (_pDH->p){ + BN_free(_pDH->p); + _pDH->p = 0; + } + if (_pDH->g){ + BN_free(_pDH->g); + _pDH->g = 0; + } + DH_free(_pDH); + _pDH = 0; + } + if (_pSharedKey){ + delete[] _pSharedKey; + _pSharedKey = 0; } - if (_pSharedKey){delete[] _pSharedKey; _pSharedKey = 0;} _sharedKeyLength = 0; - if (_peerPublickey){BN_free(_peerPublickey); _peerPublickey = 0;} + if (_peerPublickey){ + BN_free(_peerPublickey); + _peerPublickey = 0; + } } -bool DHWrapper::CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength) { +bool DHWrapper::CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength){ int32_t keySize = BN_num_bytes(pNum); - if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)){return false;} - if (BN_bn2bin(pNum, pDst) != keySize){return false;} + if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)){ + return false; + } + if (BN_bn2bin(pNum, pDst) != keySize){ + return false; + } return true; } -void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut) { +void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut){ uint8_t digest[SHA256_DIGEST_LENGTH]; unsigned int digestLen = 0; - + HMAC_CTX ctx; - HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0); - HMAC_Update(&ctx, pubKeyIn, 128); - HMAC_Final(&ctx, digest, &digestLen); - HMAC_CTX_cleanup(&ctx); - + HMAC_CTX_init( &ctx); + HMAC_Init_ex( &ctx, secretKey, 128, EVP_sha256(), 0); + HMAC_Update( &ctx, pubKeyIn, 128); + HMAC_Final( &ctx, digest, &digestLen); + HMAC_CTX_cleanup( &ctx); + RC4_set_key(rc4keyOut, 16, digest); - - HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0); - HMAC_Update(&ctx, pubKeyOut, 128); - HMAC_Final(&ctx, digest, &digestLen); - HMAC_CTX_cleanup(&ctx); - + + HMAC_CTX_init( &ctx); + HMAC_Init_ex( &ctx, secretKey, 128, EVP_sha256(), 0); + HMAC_Update( &ctx, pubKeyOut, 128); + HMAC_Final( &ctx, digest, &digestLen); + HMAC_CTX_cleanup( &ctx); + RC4_set_key(rc4keyIn, 16, digest); } -void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult) { +void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult){ unsigned int digestLen; HMAC_CTX ctx; - HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, (unsigned char*) pKey, keyLength, EVP_sha256(), 0); - HMAC_Update(&ctx, (unsigned char *) pData, dataLength); - HMAC_Final(&ctx, (unsigned char *) pResult, &digestLen); - HMAC_CTX_cleanup(&ctx); + HMAC_CTX_init( &ctx); + HMAC_Init_ex( &ctx, (unsigned char*)pKey, keyLength, EVP_sha256(), 0); + HMAC_Update( &ctx, (unsigned char *)pData, dataLength); + HMAC_Final( &ctx, (unsigned char *)pResult, &digestLen); + HMAC_CTX_cleanup( &ctx); } -bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme) { +bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme){ uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme); uint8_t *pTempBuffer = new uint8_t[1536 - 32]; memcpy(pTempBuffer, pBuffer, clientDigestOffset); memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32); uint8_t *pTempHash = new uint8_t[512]; HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash); - bool result = (memcmp(pBuffer+clientDigestOffset, pTempHash, 32) == 0); - #if DEBUG >= 4 + bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0); +#if DEBUG >= 4 fprintf(stderr, "Client scheme validation %hhi %s\n", scheme, result?"success":"failed"); - #endif +#endif delete[] pTempBuffer; delete[] pTempHash; return result; @@ -226,23 +277,25 @@ std::string & RTMPStream::Chunk::Pack(){ unsigned char chtype = 0x00; if ((prev.msg_type_id > 0) && (prev.cs_id == cs_id)){ if (msg_stream_id == prev.msg_stream_id){ - chtype = 0x40;//do not send msg_stream_id + chtype = 0x40; //do not send msg_stream_id if (len == prev.len){ if (msg_type_id == prev.msg_type_id){ - chtype = 0x80;//do not send len and msg_type_id + chtype = 0x80; //do not send len and msg_type_id if (timestamp == prev.timestamp){ - chtype = 0xC0;//do not send timestamp + chtype = 0xC0; //do not send timestamp } } } } //override - we always sent type 0x00 if the timestamp has decreased since last chunk in this channel - if (timestamp < prev.timestamp){chtype = 0x00;} + if (timestamp < prev.timestamp){ + chtype = 0x00; + } } if (cs_id <= 63){ output += (unsigned char)(chtype | cs_id); }else{ - if (cs_id <= 255+64){ + if (cs_id <= 255 + 64){ output += (unsigned char)(chtype | 0); output += (unsigned char)(cs_id - 64); }else{ @@ -259,7 +312,10 @@ std::string & RTMPStream::Chunk::Pack(){ }else{ tmpi = timestamp - prev.timestamp; } - if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;} + if (tmpi >= 0x00ffffff){ + ntime = tmpi; + tmpi = 0x00ffffff; + } output += (unsigned char)((tmpi >> 16) & 0xff); output += (unsigned char)((tmpi >> 8) & 0xff); output += (unsigned char)(tmpi & 0xff); @@ -275,8 +331,8 @@ std::string & RTMPStream::Chunk::Pack(){ //msg stream id output += (unsigned char)(msg_stream_id % 256); output += (unsigned char)(msg_stream_id / 256); - output += (unsigned char)(msg_stream_id / (256*256)); - output += (unsigned char)(msg_stream_id / (256*256*256)); + output += (unsigned char)(msg_stream_id / (256 * 256)); + output += (unsigned char)(msg_stream_id / (256 * 256 * 256)); } } } @@ -290,14 +346,16 @@ std::string & RTMPStream::Chunk::Pack(){ len_left = 0; while (len_left < len){ tmpi = len - len_left; - if (tmpi > RTMPStream::chunk_snd_max){tmpi = RTMPStream::chunk_snd_max;} + if (tmpi > RTMPStream::chunk_snd_max){ + tmpi = RTMPStream::chunk_snd_max; + } output.append(data, len_left, tmpi); len_left += tmpi; if (len_left < len){ if (cs_id <= 63){ output += (unsigned char)(0xC0 + cs_id); }else{ - if (cs_id <= 255+64){ + if (cs_id <= 255 + 64){ output += (unsigned char)(0xC0); output += (unsigned char)(cs_id - 64); }else{ @@ -311,10 +369,11 @@ std::string & RTMPStream::Chunk::Pack(){ lastsend[cs_id] = *this; RTMPStream::snd_cnt += output.size(); return output; -}//SendChunk +} //SendChunk -/// Default contructor, creates an empty chunk with all values initialized to zero. +/// Default constructor, creates an empty chunk with all values initialized to zero. RTMPStream::Chunk::Chunk(){ + headertype = 0; cs_id = 0; timestamp = 0; len = 0; @@ -323,7 +382,7 @@ RTMPStream::Chunk::Chunk(){ msg_type_id = 0; msg_stream_id = 0; data = ""; -}//constructor +} //constructor /// Packs up a chunk with the given arguments as properties. std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data){ @@ -337,7 +396,7 @@ std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_i ch.msg_stream_id = msg_stream_id; ch.data = data; return ch.Pack(); -}//constructor +} //constructor /// Packs up a chunk with media contents. /// \param msg_type_id Type number of the media, as per FLV standard. @@ -346,7 +405,7 @@ std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_i /// \param ts Timestamp of the media data, relative to current system time. std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts){ static RTMPStream::Chunk ch; - ch.cs_id = msg_type_id+42; + ch.cs_id = msg_type_id + 42; ch.timestamp = ts; ch.len = len; ch.real_len = len; @@ -355,7 +414,7 @@ std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * d ch.msg_stream_id = 1; ch.data = std::string((char*)data, (size_t)len); return ch.Pack(); -}//SendMedia +} //SendMedia /// Packs up a chunk with media contents. /// \param tag FLV::Tag with media to send. @@ -363,14 +422,14 @@ std::string & RTMPStream::SendMedia(FLV::Tag & tag){ static RTMPStream::Chunk ch; ch.cs_id = ((unsigned char)tag.data[0]); ch.timestamp = tag.tagTime(); - ch.len = tag.len-15; - ch.real_len = tag.len-15; + ch.len = tag.len - 15; + ch.real_len = tag.len - 15; ch.len_left = 0; ch.msg_type_id = (unsigned char)tag.data[0]; ch.msg_stream_id = 1; - ch.data = std::string(tag.data+11, (size_t)(tag.len-15)); + ch.data = std::string(tag.data + 11, (size_t)(tag.len - 15)); return ch.Pack(); -}//SendMedia +} //SendMedia /// Packs up a chunk for a control message with 1 argument. std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data){ @@ -385,7 +444,7 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data){ ch.data.resize(4); *(int*)((char*)ch.data.c_str()) = htonl(data); return ch.Pack(); -}//SendCTL +} //SendCTL /// Packs up a chunk for a control message with 2 arguments. std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned char data2){ @@ -401,7 +460,7 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigne *(unsigned int*)((char*)ch.data.c_str()) = htonl(data); ch.data[4] = data2; return ch.Pack(); -}//SendCTL +} //SendCTL /// Packs up a chunk for a user control message with 1 argument. std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data){ @@ -414,11 +473,11 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data){ ch.msg_type_id = 4; ch.msg_stream_id = 0; ch.data.resize(6); - *(unsigned int*)(((char*)ch.data.c_str())+2) = htonl(data); + *(unsigned int*)(((char*)ch.data.c_str()) + 2) = htonl(data); ch.data[0] = 0; ch.data[1] = type; return ch.Pack(); -}//SendUSR +} //SendUSR /// Packs up a chunk for a user control message with 2 arguments. std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned int data2){ @@ -431,13 +490,12 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne ch.msg_type_id = 4; ch.msg_stream_id = 0; ch.data.resize(10); - *(unsigned int*)(((char*)ch.data.c_str())+2) = htonl(data); - *(unsigned int*)(((char*)ch.data.c_str())+6) = htonl(data2); + *(unsigned int*)(((char*)ch.data.c_str()) + 2) = htonl(data); + *(unsigned int*)(((char*)ch.data.c_str()) + 6) = htonl(data2); ch.data[0] = 0; ch.data[1] = type; return ch.Pack(); -}//SendUSR - +} //SendUSR /// Parses the argument string into the current chunk. /// Tries to read a whole chunk, removing data from the input string as it reads. @@ -448,21 +506,21 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne /// \warning This function will destroy the current data in this chunk! /// \returns True if a whole chunk could be read, false otherwise. bool RTMPStream::Chunk::Parse(std::string & indata){ - gettimeofday(&RTMPStream::lastrec, 0); + gettimeofday( &RTMPStream::lastrec, 0); unsigned int i = 0; - if (indata.size() < 1) return false;//need at least a byte + if (indata.size() < 1) return false; //need at least a byte - unsigned char chunktype = indata[i++]; + unsigned char chunktype = indata[i++ ]; //read the chunkstream ID properly switch (chunktype & 0x3F){ case 0: - if (indata.size() < 2) return false;//need at least 2 bytes to continue - cs_id = indata[i++] + 64; + if (indata.size() < 2) return false; //need at least 2 bytes to continue + cs_id = indata[i++ ] + 64; break; case 1: - if (indata.size() < 3) return false;//need at least 3 bytes to continue - cs_id = indata[i++] + 64; - cs_id += indata[i++] * 256; + if (indata.size() < 3) return false; //need at least 3 bytes to continue + cs_id = indata[i++ ] + 64; + cs_id += indata[i++ ] * 256; break; default: cs_id = chunktype & 0x3F; @@ -475,48 +533,58 @@ bool RTMPStream::Chunk::Parse(std::string & indata){ headertype = chunktype & 0xC0; switch (headertype){ case 0x00: - if (indata.size() < i+11) return false; //can't read whole header - timestamp = indata[i++]*256*256; - timestamp += indata[i++]*256; - timestamp += indata[i++]; - len = indata[i++]*256*256; - len += indata[i++]*256; - len += indata[i++]; + if (indata.size() < i + 11) return false; //can't read whole header + timestamp = indata[i++ ] * 256 * 256; + timestamp += indata[i++ ] * 256; + timestamp += indata[i++ ]; + len = indata[i++ ] * 256 * 256; + len += indata[i++ ] * 256; + len += indata[i++ ]; len_left = 0; - msg_type_id = indata[i++]; - msg_stream_id = indata[i++]; - msg_stream_id += indata[i++]*256; - msg_stream_id += indata[i++]*256*256; - msg_stream_id += indata[i++]*256*256*256; + msg_type_id = indata[i++ ]; + msg_stream_id = indata[i++ ]; + msg_stream_id += indata[i++ ] * 256; + msg_stream_id += indata[i++ ] * 256 * 256; + msg_stream_id += indata[i++ ] * 256 * 256 * 256; break; case 0x40: - if (indata.size() < i+7) return false; //can't read whole header - if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");} - timestamp = indata[i++]*256*256; - timestamp += indata[i++]*256; - timestamp += indata[i++]; - if (timestamp != 0x00ffffff){timestamp += prev.timestamp;} - len = indata[i++]*256*256; - len += indata[i++]*256; - len += indata[i++]; + if (indata.size() < i + 7) return false; //can't read whole header + if (prev.msg_type_id == 0){ + fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n"); + } + timestamp = indata[i++ ] * 256 * 256; + timestamp += indata[i++ ] * 256; + timestamp += indata[i++ ]; + if (timestamp != 0x00ffffff){ + timestamp += prev.timestamp; + } + len = indata[i++ ] * 256 * 256; + len += indata[i++ ] * 256; + len += indata[i++ ]; len_left = 0; - msg_type_id = indata[i++]; + msg_type_id = indata[i++ ]; msg_stream_id = prev.msg_stream_id; break; case 0x80: - if (indata.size() < i+3) return false; //can't read whole header - if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");} - timestamp = indata[i++]*256*256; - timestamp += indata[i++]*256; - timestamp += indata[i++]; - if (timestamp != 0x00ffffff){timestamp += prev.timestamp;} + if (indata.size() < i + 3) return false; //can't read whole header + if (prev.msg_type_id == 0){ + fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n"); + } + timestamp = indata[i++ ] * 256 * 256; + timestamp += indata[i++ ] * 256; + timestamp += indata[i++ ]; + if (timestamp != 0x00ffffff){ + timestamp += prev.timestamp; + } len = prev.len; len_left = prev.len_left; msg_type_id = prev.msg_type_id; msg_stream_id = prev.msg_stream_id; break; case 0xC0: - if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");} + if (prev.msg_type_id == 0){ + fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n"); + } timestamp = prev.timestamp; len = prev.len; len_left = prev.len_left; @@ -537,11 +605,11 @@ bool RTMPStream::Chunk::Parse(std::string & indata){ } //read extended timestamp, if neccesary if (timestamp == 0x00ffffff){ - if (indata.size() < i+4) return false; //can't read whole header - timestamp = indata[i++]*256*256*256; - timestamp += indata[i++]*256*256; - timestamp += indata[i++]*256; - timestamp += indata[i++]; + if (indata.size() < i + 4) return false; //can't read whole header + timestamp = indata[i++ ] * 256 * 256 * 256; + timestamp += indata[i++ ] * 256 * 256; + timestamp += indata[i++ ] * 256; + timestamp += indata[i++ ]; } //read data if length > 0, and allocate it @@ -551,11 +619,11 @@ bool RTMPStream::Chunk::Parse(std::string & indata){ }else{ data = ""; } - if (indata.size() < i+real_len) return false;//can't read all data (yet) + if (indata.size() < i + real_len) return false; //can't read all data (yet) data.append(indata, i, real_len); - indata = indata.substr(i+real_len); + indata = indata.substr(i + real_len); lastrecv[cs_id] = *this; - RTMPStream::rec_cnt += i+real_len; + RTMPStream::rec_cnt += i + real_len; if (len_left == 0){ return true; }else{ @@ -563,12 +631,12 @@ bool RTMPStream::Chunk::Parse(std::string & indata){ } }else{ data = ""; - indata = indata.substr(i+real_len); + indata = indata.substr(i + real_len); lastrecv[cs_id] = *this; - RTMPStream::rec_cnt += i+real_len; + RTMPStream::rec_cnt += i + real_len; return true; } -}//Parse +} //Parse /// Parses the argument string into the current chunk. /// Tries to read a whole chunk, removing data from the input as it reads. @@ -579,77 +647,95 @@ bool RTMPStream::Chunk::Parse(std::string & indata){ /// \warning This function will destroy the current data in this chunk! /// \returns True if a whole chunk could be read, false otherwise. bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){ - gettimeofday(&RTMPStream::lastrec, 0); + gettimeofday( &RTMPStream::lastrec, 0); unsigned int i = 0; - if (!buffer.available(3)){return false;}//we want at least 3 bytes + if ( !buffer.available(3)){ + return false; + } //we want at least 3 bytes std::string indata = buffer.copy(3); - - unsigned char chunktype = indata[i++]; + + unsigned char chunktype = indata[i++ ]; //read the chunkstream ID properly switch (chunktype & 0x3F){ case 0: - cs_id = indata[i++] + 64; + cs_id = indata[i++ ] + 64; break; case 1: - cs_id = indata[i++] + 64; - cs_id += indata[i++] * 256; + cs_id = indata[i++ ] + 64; + cs_id += indata[i++ ] * 256; break; default: cs_id = chunktype & 0x3F; break; } - + RTMPStream::Chunk prev = lastrecv[cs_id]; - + //process the rest of the header, for each chunk type headertype = chunktype & 0xC0; switch (headertype){ case 0x00: - if (!buffer.available(i+11)){return false;} //can't read whole header - indata = buffer.copy(i+11); - timestamp = indata[i++]*256*256; - timestamp += indata[i++]*256; - timestamp += indata[i++]; - len = indata[i++]*256*256; - len += indata[i++]*256; - len += indata[i++]; + if ( !buffer.available(i + 11)){ + return false; + } //can't read whole header + indata = buffer.copy(i + 11); + timestamp = indata[i++ ] * 256 * 256; + timestamp += indata[i++ ] * 256; + timestamp += indata[i++ ]; + len = indata[i++ ] * 256 * 256; + len += indata[i++ ] * 256; + len += indata[i++ ]; len_left = 0; - msg_type_id = indata[i++]; - msg_stream_id = indata[i++]; - msg_stream_id += indata[i++]*256; - msg_stream_id += indata[i++]*256*256; - msg_stream_id += indata[i++]*256*256*256; + msg_type_id = indata[i++ ]; + msg_stream_id = indata[i++ ]; + msg_stream_id += indata[i++ ] * 256; + msg_stream_id += indata[i++ ] * 256 * 256; + msg_stream_id += indata[i++ ] * 256 * 256 * 256; break; case 0x40: - if (!buffer.available(i+7)){return false;} //can't read whole header - indata = buffer.copy(i+7); - if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");} - timestamp = indata[i++]*256*256; - timestamp += indata[i++]*256; - timestamp += indata[i++]; - if (timestamp != 0x00ffffff){timestamp += prev.timestamp;} - len = indata[i++]*256*256; - len += indata[i++]*256; - len += indata[i++]; + if ( !buffer.available(i + 7)){ + return false; + } //can't read whole header + indata = buffer.copy(i + 7); + if (prev.msg_type_id == 0){ + fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n"); + } + timestamp = indata[i++ ] * 256 * 256; + timestamp += indata[i++ ] * 256; + timestamp += indata[i++ ]; + if (timestamp != 0x00ffffff){ + timestamp += prev.timestamp; + } + len = indata[i++ ] * 256 * 256; + len += indata[i++ ] * 256; + len += indata[i++ ]; len_left = 0; - msg_type_id = indata[i++]; + msg_type_id = indata[i++ ]; msg_stream_id = prev.msg_stream_id; break; case 0x80: - if (!buffer.available(i+3)){return false;} //can't read whole header - indata = buffer.copy(i+3); - if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");} - timestamp = indata[i++]*256*256; - timestamp += indata[i++]*256; - timestamp += indata[i++]; - if (timestamp != 0x00ffffff){timestamp += prev.timestamp;} + if ( !buffer.available(i + 3)){ + return false; + } //can't read whole header + indata = buffer.copy(i + 3); + if (prev.msg_type_id == 0){ + fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n"); + } + timestamp = indata[i++ ] * 256 * 256; + timestamp += indata[i++ ] * 256; + timestamp += indata[i++ ]; + if (timestamp != 0x00ffffff){ + timestamp += prev.timestamp; + } len = prev.len; len_left = prev.len_left; msg_type_id = prev.msg_type_id; msg_stream_id = prev.msg_stream_id; break; case 0xC0: - if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");} + if (prev.msg_type_id == 0){ + fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n"); + } timestamp = prev.timestamp; len = prev.len; len_left = prev.len_left; @@ -670,39 +756,43 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){ } //read extended timestamp, if neccesary if (timestamp == 0x00ffffff){ - if (!buffer.available(i+4)){return false;} //can't read timestamp - indata = buffer.copy(i+4); - timestamp = indata[i++]*256*256*256; - timestamp += indata[i++]*256*256; - timestamp += indata[i++]*256; - timestamp += indata[i++]; + if ( !buffer.available(i + 4)){ + return false; + } //can't read timestamp + indata = buffer.copy(i + 4); + timestamp = indata[i++ ] * 256 * 256 * 256; + timestamp += indata[i++ ] * 256 * 256; + timestamp += indata[i++ ] * 256; + timestamp += indata[i++ ]; } - + //read data if length > 0, and allocate it if (real_len > 0){ - if (!buffer.available(i+real_len)){return false;}//can't read all data (yet) - buffer.remove(i);//remove the header + if ( !buffer.available(i + real_len)){ + return false; + } //can't read all data (yet) + buffer.remove(i); //remove the header if (prev.len_left > 0){ - data = prev.data + buffer.remove(real_len);//append the data and remove from buffer + data = prev.data + buffer.remove(real_len); //append the data and remove from buffer }else{ - data = buffer.remove(real_len);//append the data and remove from buffer + data = buffer.remove(real_len); //append the data and remove from buffer } lastrecv[cs_id] = *this; - RTMPStream::rec_cnt += i+real_len; + RTMPStream::rec_cnt += i + real_len; if (len_left == 0){ return true; }else{ return Parse(buffer); } }else{ - buffer.remove(i);//remove the header + buffer.remove(i); //remove the header data = ""; - indata = indata.substr(i+real_len); + indata = indata.substr(i + real_len); lastrecv[cs_id] = *this; - RTMPStream::rec_cnt += i+real_len; + RTMPStream::rec_cnt += i + real_len; return true; } -}//Parse +} //Parse /// Does the handshake. Expects handshake_in to be filled, and fills handshake_out. /// After calling this function, don't forget to read and ignore 1536 extra bytes, @@ -718,21 +808,23 @@ bool RTMPStream::doHandshake(){ RTMPStream::rec_cnt += 1537; //Build S1 Packet - *((uint32_t*)Server) = 0;//time zero - *(((uint32_t*)(Server+4))) = htonl(0x01020304);//version 1 2 3 4 - for (int i = 8; i < 3072; ++i){Server[i] = versionstring[i%16];}//"random" data + *((uint32_t*)Server) = 0; //time zero + *(((uint32_t*)(Server + 4))) = htonl(0x01020304); //version 1 2 3 4 + for (int i = 8; i < 3072; ++i){ + Server[i] = versionstring[i % 16]; + } //"random" data bool encrypted = (Version == 6); - #if DEBUG >= 4 +#if DEBUG >= 4 fprintf(stderr, "Handshake version is %hhi\n", Version); - #endif +#endif uint8_t _validationScheme = 5; if (ValidateClientScheme(Client, 0)) _validationScheme = 0; if (ValidateClientScheme(Client, 1)) _validationScheme = 1; - #if DEBUG >= 4 +#if DEBUG >= 4 fprintf(stderr, "Handshake type is %hhi, encryption is %s\n", _validationScheme, encrypted?"on":"off"); - #endif +#endif //FIRST 1536 bytes from server response //compute DH key position @@ -741,19 +833,19 @@ bool RTMPStream::doHandshake(){ //generate DH key DHWrapper dhWrapper(1024); - if (!dhWrapper.Initialize()) return false; - if (!dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)) return false; - if (!dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)) return false; + if ( !dhWrapper.Initialize()) return false; + if ( !dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)) return false; + if ( !dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)) return false; - if (encrypted) { + if (encrypted){ uint8_t secretKey[128]; - if (!dhWrapper.CopySharedKey(secretKey, sizeof (secretKey))) return false; + if ( !dhWrapper.CopySharedKey(secretKey, sizeof(secretKey))) return false; RC4_KEY _pKeyIn; RC4_KEY _pKeyOut; - InitRC4Encryption(secretKey, (uint8_t*) & Client[clientDHOffset], (uint8_t*) & Server[serverDHOffset], &_pKeyIn, &_pKeyOut); + InitRC4Encryption(secretKey, (uint8_t*) &Client[clientDHOffset], (uint8_t*) &Server[serverDHOffset], &_pKeyIn, &_pKeyOut); uint8_t data[1536]; - RC4(&_pKeyIn, 1536, data, data); - RC4(&_pKeyOut, 1536, data, data); + RC4( &_pKeyIn, 1536, data, data); + RC4( &_pKeyOut, 1536, data, data); } //generate the digest uint32_t serverDigestOffset = GetDigestOffset(Server, _validationScheme); @@ -776,7 +868,7 @@ bool RTMPStream::doHandshake(){ delete[] pTempHash; delete[] pLastHash; //DONE BUILDING THE RESPONSE ***// - Server[-1] = Version; + Server[ -1] = Version; RTMPStream::snd_cnt += 3073; return true; } diff --git a/lib/rtmpchunks.h b/lib/rtmpchunks.h index 21dd160e..b4ec4d4e 100644 --- a/lib/rtmpchunks.h +++ b/lib/rtmpchunks.h @@ -11,12 +11,12 @@ #include "socket.h" //forward declaration of FLV::Tag to avoid circular dependencies. -namespace FLV{ +namespace FLV { class Tag; -}; +} /// Contains all functions and classes needed for RTMP connections. -namespace RTMPStream{ +namespace RTMPStream { extern unsigned int chunk_rec_max; ///< Maximum size for a received chunk. extern unsigned int chunk_snd_max; ///< Maximum size for a sent chunk. @@ -50,7 +50,8 @@ namespace RTMPStream{ private: static std::map lastsend; static std::map lastrecv; - };//RTMPStream::Chunk + }; + //RTMPStream::Chunk std::string & SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data); std::string & SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts); @@ -66,4 +67,4 @@ namespace RTMPStream{ extern std::string handshake_out; /// Does the handshake. Expects handshake_in to be filled, and fills handshake_out. bool doHandshake(); -};//RTMPStream namespace +} //RTMPStream namespace diff --git a/lib/socket.cpp b/lib/socket.cpp index b2d70084..bad2a703 100644 --- a/lib/socket.cpp +++ b/lib/socket.cpp @@ -16,7 +16,6 @@ #define BUFFER_BLOCKSIZE 4096 //set buffer blocksize to 4KiB #include //temporary for debugging - std::string uint2string(unsigned int i){ std::stringstream st; st << i; @@ -27,7 +26,9 @@ std::string uint2string(unsigned int i){ /// The back is popped as long as it is empty, first - this way this function is /// guaranteed to return 0 if the buffer is empty. unsigned int Socket::Buffer::size(){ - while (data.size() > 0 && data.back().empty()){data.pop_back();} + while (data.size() > 0 && data.back().empty()){ + data.pop_back(); + } return data.size(); } @@ -45,10 +46,12 @@ void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize j = i; while (j < newdatasize && j - i <= BUFFER_BLOCKSIZE){ j++; - if (newdata[j-1] == '\n'){break;} + if (newdata[j - 1] == '\n'){ + break; + } } if (i != j){ - data.push_front(std::string(newdata+i, (size_t)(j - i))); + data.push_front(std::string(newdata + i, (size_t)(j - i))); i = j; }else{ break; @@ -63,8 +66,10 @@ void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize bool Socket::Buffer::available(unsigned int count){ unsigned int i = 0; for (std::deque::iterator it = data.begin(); it != data.end(); ++it){ - i += (*it).size(); - if (i >= count){return true;} + i += ( *it).size(); + if (i >= count){ + return true; + } } return false; } @@ -72,18 +77,20 @@ bool Socket::Buffer::available(unsigned int count){ /// Removes count bytes from the buffer, returning them by value. /// Returns an empty string if not all count bytes are available. std::string Socket::Buffer::remove(unsigned int count){ - if (!available(count)){return "";} + if ( !available(count)){ + return ""; + } unsigned int i = 0; std::string ret; ret.reserve(count); for (std::deque::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){ - if (i + (*it).size() < count){ - ret.append(*it); - i += (*it).size(); - (*it).clear(); + if (i + ( *it).size() < count){ + ret.append( *it); + i += ( *it).size(); + ( *it).clear(); }else{ - ret.append(*it, 0, count - i); - (*it).erase(0, count - i); + ret.append( *it, 0, count - i); + ( *it).erase(0, count - i); break; } } @@ -93,15 +100,17 @@ std::string Socket::Buffer::remove(unsigned int count){ /// Copies count bytes from the buffer, returning them by value. /// Returns an empty string if not all count bytes are available. std::string Socket::Buffer::copy(unsigned int count){ - if (!available(count)){return "";} + if ( !available(count)){ + return ""; + } unsigned int i = 0; std::string ret; for (std::deque::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){ - if (i + (*it).size() < count){ - ret.append(*it); - i += (*it).size(); + if (i + ( *it).size() < count){ + ret.append( *it); + i += ( *it).size(); }else{ - ret.append(*it, 0, count - i); + ret.append( *it, 0, count - i); break; } } @@ -118,7 +127,6 @@ std::string & Socket::Buffer::get(){ } } - /// Create a new base socket. This is a basic constructor for converting any valid socket to a Socket::Connection. /// \param sockNo Integer representing the socket to convert. Socket::Connection::Connection(int sockNo){ @@ -130,7 +138,7 @@ Socket::Connection::Connection(int sockNo){ conntime = Util::epoch(); Error = false; Blocking = false; -}//Socket::Connection basic constructor +} //Socket::Connection basic constructor /// Simulate a socket using two file descriptors. /// \param write The filedescriptor to write to. @@ -144,7 +152,7 @@ Socket::Connection::Connection(int write, int read){ conntime = Util::epoch(); Error = false; Blocking = false; -}//Socket::Connection basic constructor +} //Socket::Connection basic constructor /// Create a new disconnected base socket. This is a basic constructor for placeholder purposes. /// A socket created like this is always disconnected and should/could be overwritten at some point. @@ -157,12 +165,12 @@ Socket::Connection::Connection(){ conntime = Util::epoch(); Error = false; Blocking = false; -}//Socket::Connection basic constructor +} //Socket::Connection basic constructor /// Internally used call to make an file descriptor blocking or not. void setFDBlocking(int FD, bool blocking){ int flags = fcntl(FD, F_GETFL, 0); - if (!blocking){ + if ( !blocking){ flags |= O_NONBLOCK; }else{ flags &= !O_NONBLOCK; @@ -172,44 +180,57 @@ void setFDBlocking(int FD, bool blocking){ /// Set this socket to be blocking (true) or nonblocking (false). void Socket::Connection::setBlocking(bool blocking){ - if (sock >=0){setFDBlocking(sock, blocking);} - if (pipes[0] >=0){setFDBlocking(pipes[0], blocking);} - if (pipes[1] >=0){setFDBlocking(pipes[1], blocking);} + if (sock >= 0){ + setFDBlocking(sock, blocking); + } + if (pipes[0] >= 0){ + setFDBlocking(pipes[0], blocking); + } + if (pipes[1] >= 0){ + setFDBlocking(pipes[1], blocking); + } } /// Close connection. The internal socket is closed and then set to -1. /// If the connection is already closed, nothing happens. void Socket::Connection::close(){ if (connected()){ - #if DEBUG >= 6 +#if DEBUG >= 6 fprintf(stderr, "Socket closed.\n"); - #endif +#endif if (sock != -1){ shutdown(sock, SHUT_RDWR); errno = EINTR; - while (::close(sock) != 0 && errno == EINTR){} + while (::close(sock) != 0 && errno == EINTR){ + } sock = -1; } if (pipes[0] != -1){ errno = EINTR; - while (::close(pipes[0]) != 0 && errno == EINTR){} + while (::close(pipes[0]) != 0 && errno == EINTR){ + } pipes[0] = -1; } if (pipes[1] != -1){ errno = EINTR; - while (::close(pipes[1]) != 0 && errno == EINTR){} + while (::close(pipes[1]) != 0 && errno == EINTR){ + } pipes[1] = -1; } } -}//Socket::Connection::close +} //Socket::Connection::close /// Returns internal socket number. -int Socket::Connection::getSocket(){return sock;} +int Socket::Connection::getSocket(){ + return sock; +} /// Returns a string describing the last error that occured. /// Simply calls strerror(errno) - not very reliable! /// \todo Improve getError at some point to be more reliable and only report socket errors. -std::string Socket::Connection::getError(){return strerror(errno);} +std::string Socket::Connection::getError(){ + return strerror(errno); +} /// Create a new Unix Socket. This socket will (try to) connect to the given address right away. /// \param address String containing the location of the Unix socket to connect to. @@ -219,9 +240,9 @@ Socket::Connection::Connection(std::string address, bool nonblock){ pipes[1] = -1; sock = socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Could not create socket! Error: %s\n", strerror(errno)); - #endif +#endif return; } Error = false; @@ -231,8 +252,8 @@ Socket::Connection::Connection(std::string address, bool nonblock){ conntime = Util::epoch(); sockaddr_un addr; addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, address.c_str(), address.size()+1); - int r = connect(sock, (sockaddr*)&addr, sizeof(addr)); + strncpy(addr.sun_path, address.c_str(), address.size() + 1); + int r = connect(sock, (sockaddr*) &addr, sizeof(addr)); if (r == 0){ if (nonblock){ int flags = fcntl(sock, F_GETFL, 0); @@ -240,12 +261,12 @@ Socket::Connection::Connection(std::string address, bool nonblock){ fcntl(sock, F_SETFL, flags); } }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Could not connect to %s! Error: %s\n", address.c_str(), strerror(errno)); - #endif +#endif close(); } -}//Socket::Connection Unix Contructor +} //Socket::Connection Unix Contructor /// Create a new TCP Socket. This socket will (try to) connect to the given host/port right away. /// \param host String containing the hostname to connect to. @@ -263,7 +284,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){ std::stringstream ss; ss << port; - memset(&hints, 0, sizeof(struct addrinfo)); + memset( &hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; @@ -273,25 +294,29 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){ hints.ai_next = NULL; int s = getaddrinfo(host.c_str(), ss.str().c_str(), &hints, &result); if (s != 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Could not connect to %s:%i! Error: %s\n", host.c_str(), port, gai_strerror(s)); - #endif +#endif close(); return; } - for (rp = result; rp != NULL; rp = rp->ai_next) { + for (rp = result; rp != NULL; rp = rp->ai_next){ sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (sock < 0){continue;} - if (connect(sock, rp->ai_addr, rp->ai_addrlen) == 0){break;} + if (sock < 0){ + continue; + } + if (connect(sock, rp->ai_addr, rp->ai_addrlen) == 0){ + break; + } ::close(sock); } freeaddrinfo(result); if (rp == 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Could not connect to %s! Error: %s\n", host.c_str(), strerror(errno)); - #endif +#endif close(); }else{ if (nonblock){ @@ -300,7 +325,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){ fcntl(sock, F_SETFL, flags); } } -}//Socket::Connection TCP Contructor +} //Socket::Connection TCP Contructor /// Returns the connected-state for this socket. /// Note that this function might be slightly behind the real situation. @@ -345,8 +370,8 @@ bool Socket::Connection::spool(){ /// Returns true if new data was received, false otherwise. bool Socket::Connection::flush(){ while (upbuffer.size() > 0 && connected()){ - if (!iwrite(upbuffer.get())){ - Util::sleep(10);//sleep 10ms + if ( !iwrite(upbuffer.get())){ + Util::sleep(10); //sleep 10ms } } /// \todo Provide better mechanism to prevent overbuffering. @@ -357,7 +382,6 @@ bool Socket::Connection::flush(){ } } - /// Returns a reference to the download buffer. Socket::Buffer & Socket::Connection::Received(){ return downbuffer; @@ -368,17 +392,17 @@ Socket::Buffer & Socket::Connection::Received(){ /// Any data that could not be send will block until it can be send or the connection is severed. void Socket::Connection::SendNow(const char * data, size_t len){ while (upbuffer.size() > 0 && connected()){ - if (!iwrite(upbuffer.get())){ - Util::sleep(1);//sleep 1ms if buffer full + if ( !iwrite(upbuffer.get())){ + Util::sleep(1); //sleep 1ms if buffer full } } int i = iwrite(data, len); while (i < len && connected()){ - int j = iwrite(data+i, len-i); + int j = iwrite(data + i, len - i); if (j > 0){ i += j; }else{ - Util::sleep(1);//sleep 1ms and retry + Util::sleep(1); //sleep 1ms and retry } } } @@ -390,7 +414,9 @@ void Socket::Connection::SendNow(const char * data, size_t len){ /// This means this function is blocking if the socket is, but nonblocking otherwise. void Socket::Connection::Send(const char * data, size_t len){ while (upbuffer.size() > 0){ - if (!iwrite(upbuffer.get())){break;} + if ( !iwrite(upbuffer.get())){ + break; + } } if (upbuffer.size() > 0){ upbuffer.append(data, len); @@ -442,7 +468,9 @@ void Socket::Connection::Send(std::string & data){ /// \param len Amount of bytes to write. /// \returns The amount of bytes actually written. int Socket::Connection::iwrite(const void * buffer, int len){ - if (!connected() || len < 1){return 0;} + if ( !connected() || len < 1){ + return 0; + } int r; if (sock >= 0){ r = send(sock, buffer, len, 0); @@ -457,9 +485,9 @@ int Socket::Connection::iwrite(const void * buffer, int len){ default: if (errno != EPIPE){ Error = true; - #if DEBUG >= 2 +#if DEBUG >= 2 fprintf(stderr, "Could not iwrite data! Error: %s\n", strerror(errno)); - #endif +#endif } close(); return 0; @@ -471,7 +499,7 @@ int Socket::Connection::iwrite(const void * buffer, int len){ } up += r; return r; -}//Socket::Connection::iwrite +} //Socket::Connection::iwrite /// Incremental read call. This function tries to read len bytes to the buffer from the socket, /// returning the amount of bytes it actually read. @@ -479,7 +507,9 @@ int Socket::Connection::iwrite(const void * buffer, int len){ /// \param len Amount of bytes to read. /// \returns The amount of bytes actually read. int Socket::Connection::iread(void * buffer, int len){ - if (!connected() || len < 1){return 0;} + if ( !connected() || len < 1){ + return 0; + } int r; if (sock >= 0){ r = recv(sock, buffer, len, 0); @@ -494,9 +524,9 @@ int Socket::Connection::iread(void * buffer, int len){ default: if (errno != EPIPE){ Error = true; - #if DEBUG >= 2 +#if DEBUG >= 2 fprintf(stderr, "Could not iread data! Error: %s\n", strerror(errno)); - #endif +#endif } close(); return 0; @@ -508,7 +538,7 @@ int Socket::Connection::iread(void * buffer, int len){ } down += r; return r; -}//Socket::Connection::iread +} //Socket::Connection::iread /// Read call that is compatible with Socket::Buffer. /// Data is read using iread (which is nonblocking if the Socket::Connection itself is), @@ -518,10 +548,12 @@ int Socket::Connection::iread(void * buffer, int len){ bool Socket::Connection::iread(Buffer & buffer){ char cbuffer[BUFFER_BLOCKSIZE]; int num = iread(cbuffer, BUFFER_BLOCKSIZE); - if (num < 1){return false;} + if (num < 1){ + return false; + } buffer.append(cbuffer, num); return true; -}//iread +} //iread /// Incremental write call that is compatible with std::string. /// Data is written using iwrite (which is nonblocking if the Socket::Connection itself is), @@ -529,12 +561,16 @@ bool Socket::Connection::iread(Buffer & buffer){ /// \param buffer std::string to remove data from. /// \return True if more data was sent, false otherwise. bool Socket::Connection::iwrite(std::string & buffer){ - if (buffer.size() < 1){return false;} + if (buffer.size() < 1){ + return false; + } int tmp = iwrite((void*)buffer.c_str(), buffer.size()); - if (tmp < 1){return false;} + if (tmp < 1){ + return false; + } buffer = buffer.substr(tmp); return true; -}//iwrite +} //iwrite /// Gets hostname for connection, if available. std::string Socket::Connection::getHost(){ @@ -549,13 +585,13 @@ void Socket::Connection::setHost(std::string host){ /// Returns true if these sockets are the same socket. /// Does not check the internal stats - only the socket itself. -bool Socket::Connection::operator== (const Connection &B) const{ +bool Socket::Connection::operator==(const Connection &B) const{ return sock == B.sock && pipes[0] == B.pipes[0] && pipes[1] == B.pipes[1]; } /// Returns true if these sockets are not the same socket. /// Does not check the internal stats - only the socket itself. -bool Socket::Connection::operator!= (const Connection &B) const{ +bool Socket::Connection::operator!=(const Connection &B) const{ return sock != B.sock || pipes[0] != B.pipes[0] || pipes[1] != B.pipes[1]; } @@ -568,7 +604,7 @@ Socket::Connection::operator bool() const{ /// Create a new base Server. The socket is never connected, and a placeholder for later connections. Socket::Server::Server(){ sock = -1; -}//Socket::Server base Constructor +} //Socket::Server base Constructor /// Create a new TCP Server. The socket is immediately bound and set to listen. /// A maximum of 100 connections will be accepted between accept() calls. @@ -577,11 +613,11 @@ Socket::Server::Server(){ /// \param hostname (optional) The interface to bind to. The default is 0.0.0.0 (all interfaces). /// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false (blocking). Socket::Server::Server(int port, std::string hostname, bool nonblock){ - if (!IPv6bind(port, hostname, nonblock) && !IPv4bind(port, hostname, nonblock)){ + if ( !IPv6bind(port, hostname, nonblock) && !IPv4bind(port, hostname, nonblock)){ fprintf(stderr, "Could not create socket %s:%i! Error: %s\n", hostname.c_str(), port, strerror(errno)); sock = -1; } -}//Socket::Server TCP Constructor +} //Socket::Server TCP Constructor /// Attempt to bind an IPv6 socket. /// \param port The TCP port to listen on @@ -591,9 +627,9 @@ Socket::Server::Server(int port, std::string hostname, bool nonblock){ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){ sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock < 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Could not create IPv6 socket %s:%i! Error: %s\n", hostname.c_str(), port, strerror(errno)); - #endif +#endif return false; } int on = 1; @@ -605,31 +641,31 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){ } struct sockaddr_in6 addr; addr.sin6_family = AF_INET6; - addr.sin6_port = htons(port);//set port + addr.sin6_port = htons(port); //set port if (hostname == "0.0.0.0" || hostname.length() == 0){ addr.sin6_addr = in6addr_any; }else{ - inet_pton(AF_INET6, hostname.c_str(), &addr.sin6_addr);//set interface, 0.0.0.0 (default) is all + inet_pton(AF_INET6, hostname.c_str(), &addr.sin6_addr); //set interface, 0.0.0.0 (default) is all } - int ret = bind(sock, (sockaddr*)&addr, sizeof(addr));//do the actual bind + int ret = bind(sock, (sockaddr*) &addr, sizeof(addr)); //do the actual bind if (ret == 0){ - ret = listen(sock, 100);//start listening, backlog of 100 allowed + ret = listen(sock, 100); //start listening, backlog of 100 allowed if (ret == 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "IPv6 socket success @ %s:%i\n", hostname.c_str(), port); - #endif +#endif return true; }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "IPv6 Listen failed! Error: %s\n", strerror(errno)); - #endif +#endif close(); return false; } }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "IPv6 Binding %s:%i failed (%s)\n", hostname.c_str(), port, strerror(errno)); - #endif +#endif close(); return false; } @@ -643,9 +679,9 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Could not create IPv4 socket %s:%i! Error: %s\n", hostname.c_str(), port, strerror(errno)); - #endif +#endif return false; } int on = 1; @@ -657,31 +693,31 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){ } struct sockaddr_in addr4; addr4.sin_family = AF_INET; - addr4.sin_port = htons(port);//set port + addr4.sin_port = htons(port); //set port if (hostname == "0.0.0.0" || hostname.length() == 0){ addr4.sin_addr.s_addr = INADDR_ANY; }else{ - inet_pton(AF_INET, hostname.c_str(), &addr4.sin_addr);//set interface, 0.0.0.0 (default) is all + inet_pton(AF_INET, hostname.c_str(), &addr4.sin_addr); //set interface, 0.0.0.0 (default) is all } - int ret = bind(sock, (sockaddr*)&addr4, sizeof(addr4));//do the actual bind + int ret = bind(sock, (sockaddr*) &addr4, sizeof(addr4)); //do the actual bind if (ret == 0){ - ret = listen(sock, 100);//start listening, backlog of 100 allowed + ret = listen(sock, 100); //start listening, backlog of 100 allowed if (ret == 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "IPv4 socket success @ %s:%i\n", hostname.c_str(), port); - #endif +#endif return true; }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "IPv4 Listen failed! Error: %s\n", strerror(errno)); - #endif +#endif close(); return false; } }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "IPv4 binding %s:%i failed (%s)\n", hostname.c_str(), port, strerror(errno)); - #endif +#endif close(); return false; } @@ -697,9 +733,9 @@ Socket::Server::Server(std::string address, bool nonblock){ unlink(address.c_str()); sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Could not create socket! Error: %s\n", strerror(errno)); - #endif +#endif return; } if (nonblock){ @@ -709,38 +745,40 @@ Socket::Server::Server(std::string address, bool nonblock){ } sockaddr_un addr; addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, address.c_str(), address.size()+1); - int ret = bind(sock, (sockaddr*)&addr, sizeof(addr)); + strncpy(addr.sun_path, address.c_str(), address.size() + 1); + int ret = bind(sock, (sockaddr*) &addr, sizeof(addr)); if (ret == 0){ - ret = listen(sock, 100);//start listening, backlog of 100 allowed + ret = listen(sock, 100); //start listening, backlog of 100 allowed if (ret == 0){ return; }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Listen failed! Error: %s\n", strerror(errno)); - #endif +#endif close(); return; } }else{ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Binding failed! Error: %s\n", strerror(errno)); - #endif +#endif close(); return; } -}//Socket::Server Unix Constructor +} //Socket::Server Unix Constructor /// Accept any waiting connections. If the Socket::Server is blocking, this function will block until there is an incoming connection. /// If the Socket::Server is nonblocking, it might return a Socket::Connection that is not connected, so check for this. /// \param nonblock (optional) Whether the newly connected socket should be nonblocking. Default is false (blocking). /// \returns A Socket::Connection, which may or may not be connected, depending on settings and circumstances. Socket::Connection Socket::Server::accept(bool nonblock){ - if (sock < 0){return Socket::Connection(-1);} + if (sock < 0){ + return Socket::Connection( -1); + } struct sockaddr_in6 addrinfo; socklen_t len = sizeof(addrinfo); static char addrconv[INET6_ADDRSTRLEN]; - int r = ::accept(sock, (sockaddr*)&addrinfo, &len); + int r = ::accept(sock, (sockaddr*) &addrinfo, &len); //set the socket to be nonblocking, if requested. //we could do this through accept4 with a flag, but that call is non-standard... if ((r >= 0) && nonblock){ @@ -751,29 +789,29 @@ Socket::Connection Socket::Server::accept(bool nonblock){ Socket::Connection tmp(r); if (r < 0){ if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)){ - #if DEBUG >= 1 +#if DEBUG >= 1 fprintf(stderr, "Error during accept - closing server socket.\n"); - #endif +#endif close(); } }else{ if (addrinfo.sin6_family == AF_INET6){ tmp.remotehost = inet_ntop(AF_INET6, &(addrinfo.sin6_addr), addrconv, INET6_ADDRSTRLEN); - #if DEBUG >= 6 +#if DEBUG >= 6 fprintf(stderr,"IPv6 addr: %s\n", tmp.remotehost.c_str()); - #endif +#endif } if (addrinfo.sin6_family == AF_INET){ - tmp.remotehost = inet_ntop(AF_INET, &(((sockaddr_in*)&addrinfo)->sin_addr), addrconv, INET6_ADDRSTRLEN); - #if DEBUG >= 6 + tmp.remotehost = inet_ntop(AF_INET, &(((sockaddr_in*) &addrinfo)->sin_addr), addrconv, INET6_ADDRSTRLEN); +#if DEBUG >= 6 fprintf(stderr,"IPv4 addr: %s\n", tmp.remotehost.c_str()); - #endif +#endif } if (addrinfo.sin6_family == AF_UNIX){ - #if DEBUG >= 6 +#if DEBUG >= 6 tmp.remotehost = ((sockaddr_un*)&addrinfo)->sun_path; fprintf(stderr,"Unix socket, no address\n"); - #endif +#endif tmp.remotehost = "UNIX_SOCKET"; } } @@ -784,15 +822,16 @@ Socket::Connection Socket::Server::accept(bool nonblock){ /// If the connection is already closed, nothing happens. void Socket::Server::close(){ if (connected()){ - #if DEBUG >= 6 +#if DEBUG >= 6 fprintf(stderr, "ServerSocket closed.\n"); - #endif +#endif shutdown(sock, SHUT_RDWR); errno = EINTR; - while (::close(sock) != 0 && errno == EINTR){} + while (::close(sock) != 0 && errno == EINTR){ + } sock = -1; } -}//Socket::Server::close +} //Socket::Server::close /// Returns the connected-state for this socket. /// Note that this function might be slightly behind the real situation. @@ -801,7 +840,9 @@ void Socket::Server::close(){ /// \returns True if socket is connected, false otherwise. bool Socket::Server::connected() const{ return (sock >= 0); -}//Socket::Server::connected +} //Socket::Server::connected /// Returns internal socket number. -int Socket::Server::getSocket(){return sock;} +int Socket::Server::getSocket(){ + return sock; +} diff --git a/lib/socket.h b/lib/socket.h index c5f907f7..d7f347ad 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -17,10 +17,12 @@ #include //for being friendly with Socket::Connection down below -namespace Buffer{class user;}; +namespace Buffer { + class user; +} ///Holds Socket tools. -namespace Socket{ +namespace Socket { /// A buffer made out of std::string objects that can be efficiently read from and written to. class Buffer{ @@ -34,7 +36,8 @@ namespace Socket{ bool available(unsigned int count); std::string remove(unsigned int count); std::string copy(unsigned int count); - };//Buffer + }; + //Buffer /// This class is for easy communicating through sockets, either TCP or Unix. class Connection{ @@ -51,7 +54,7 @@ namespace Socket{ int iwrite(const void * buffer, int len); ///< Incremental write call. bool iread(Buffer & buffer); ///< Incremental write call that is compatible with Socket::Buffer. bool iwrite(std::string & buffer); ///< Write call that is compatible with std::string. - public: + public: //friends friend class ::Buffer::user; //constructors @@ -86,8 +89,8 @@ namespace Socket{ bool Error; ///< Set to true if a socket error happened. bool Blocking; ///< Set to true if a socket is currently or wants to be blocking. //overloaded operators - bool operator== (const Connection &B) const; - bool operator!= (const Connection &B) const; + bool operator==(const Connection &B) const; + bool operator!=(const Connection &B) const; operator bool() const; }; @@ -97,7 +100,7 @@ namespace Socket{ int sock; ///< Internally saved socket number. bool IPv6bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv6 socket bool IPv4bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv4 socket - public: + public: Server(); ///< Create a new base Server. Server(int port, std::string hostname = "0.0.0.0", bool nonblock = false); ///< Create a new TCP Server. Server(std::string adres, bool nonblock = false); ///< Create a new Unix Server. @@ -106,5 +109,5 @@ namespace Socket{ void close(); ///< Close connection. int getSocket(); ///< Returns internal socket number. }; - -}; + +} diff --git a/lib/stream.cpp b/lib/stream.cpp index 3b681c09..476c4402 100644 --- a/lib/stream.cpp +++ b/lib/stream.cpp @@ -18,18 +18,21 @@ /// that character is deleted. The original string is modified. void Util::Stream::sanitizeName(std::string & streamname){ //strip anything that isn't numbers, digits or underscores - for (std::string::iterator i=streamname.end()-1; i>=streamname.begin(); --i){ - if (*i == '?'){streamname.erase(i, streamname.end()); break;} - if (!isalpha(*i) && !isdigit(*i) && *i != '_'){ + for (std::string::iterator i = streamname.end() - 1; i >= streamname.begin(); --i){ + if ( *i == '?'){ + streamname.erase(i, streamname.end()); + break; + } + if ( !isalpha( *i) && !isdigit( *i) && *i != '_'){ streamname.erase(i); }else{ - *i=tolower(*i); + *i = tolower( *i); } } } Socket::Connection Util::Stream::getLive(std::string streamname){ - return Socket::Connection("/tmp/mist/stream_"+streamname); + return Socket::Connection("/tmp/mist/stream_" + streamname); } /// Starts a process for a VoD stream. @@ -49,20 +52,20 @@ Socket::Connection Util::Stream::getStream(std::string streamname){ JSON::Value ServConf = JSON::fromFile("/tmp/mist/streamlist"); if (ServConf["streams"].isMember(streamname)){ if (ServConf["streams"][streamname]["channel"]["URL"].asString()[0] == '/'){ - #if DEBUG >= 4 +#if DEBUG >= 4 std::cerr << "Opening VoD stream from file " << ServConf["streams"][streamname]["channel"]["URL"].asString() << std::endl; - #endif +#endif return getVod(ServConf["streams"][streamname]["channel"]["URL"].asString()); }else{ - #if DEBUG >= 4 +#if DEBUG >= 4 std::cerr << "Opening live stream " << streamname << std::endl; - #endif - return Socket::Connection("/tmp/mist/stream_"+streamname); +#endif + return Socket::Connection("/tmp/mist/stream_" + streamname); } } - #if DEBUG >= 4 +#if DEBUG >= 4 std::cerr << "Could not open stream " << streamname << " - stream not found" << std::endl; - #endif +#endif return Socket::Connection(); } @@ -73,7 +76,7 @@ Socket::Connection Util::Stream::getStream(std::string streamname){ /// If the /tmp/mist directory doesn't exist yet, this will create it. Socket::Server Util::Stream::makeLive(std::string streamname){ sanitizeName(streamname); - std::string loc = "/tmp/mist/stream_"+streamname; + std::string loc = "/tmp/mist/stream_" + streamname; //attempt to create the /tmp/mist directory if it doesn't exist already. //ignore errors - we catch all problems in the Socket::Server creation already mkdir("/tmp/mist", S_IRWXU | S_IRWXG | S_IRWXO); diff --git a/lib/stream.h b/lib/stream.h index f08433d9..2c285997 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -5,7 +5,7 @@ #include #include "socket.h" -namespace Util{ +namespace Util { class Stream{ public: static void sanitizeName(std::string & streamname); diff --git a/lib/timing.cpp b/lib/timing.cpp index 8d7a5f97..f89523fa 100644 --- a/lib/timing.cpp +++ b/lib/timing.cpp @@ -4,22 +4,25 @@ #include "timing.h" #include //for gettimeofday #include //for time and nanosleep - /// Sleeps for the indicated amount of milliseconds or longer. void Util::sleep(int ms){ - if (ms < 0){return;} - if (ms > 10000){return;} + if (ms < 0){ + return; + } + if (ms > 10000){ + return; + } struct timespec T; - T.tv_sec = ms/1000; - T.tv_nsec = 1000000*(ms%1000); - nanosleep(&T, 0); + T.tv_sec = ms / 1000; + T.tv_nsec = 1000000 * (ms % 1000); + nanosleep( &T, 0); } /// Gets the current time in milliseconds. long long int Util::getMS(){ struct timespec t; clock_gettime(CLOCK_REALTIME, &t); - return ((long long int)t.tv_sec) * 1000 + t.tv_nsec/1000000; + return ((long long int)t.tv_sec) * 1000 + t.tv_nsec / 1000000; } /// Gets the amount of seconds since 01/01/1970. diff --git a/lib/timing.h b/lib/timing.h index b9c43a79..3cbe1e6b 100644 --- a/lib/timing.h +++ b/lib/timing.h @@ -3,8 +3,8 @@ #pragma once -namespace Util{ +namespace Util { void sleep(int ms); ///< Sleeps for the indicated amount of milliseconds or longer. long long int getMS(); ///< Gets the current time in milliseconds. long long int epoch(); ///< Gets the amount of seconds since 01/01/1970. -}; +}