Global cleanups and standardization of code style.
This commit is contained in:
parent
51a9b4162c
commit
38ef8704f8
33 changed files with 4322 additions and 2824 deletions
399
lib/amf.cpp
399
lib/amf.cpp
|
@ -4,68 +4,89 @@
|
|||
#include "amf.h"
|
||||
#include <sstream>
|
||||
#include <cstdio> //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<AMF::Object>::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<AMF::Object>::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.
|
||||
|
@ -77,7 +98,7 @@ AMF::Object::Object(std::string indice, double val, AMF::obj0type setType){//num
|
|||
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.
|
||||
|
@ -90,7 +111,7 @@ AMF::Object::Object(std::string indice, std::string val, AMF::obj0type setType){
|
|||
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.
|
||||
|
@ -101,7 +122,7 @@ AMF::Object::Object(std::string indice, AMF::obj0type setType){//object type ini
|
|||
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_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_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<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){st << it->Print(indent+" ");}
|
||||
for (std::vector<AMF::Object>::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,22 +223,34 @@ 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*) &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;
|
||||
|
@ -188,11 +270,11 @@ std::string AMF::Object::Pack(){
|
|||
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<AMF::Object>::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:
|
||||
|
@ -221,7 +305,10 @@ std::string AMF::Object::Pack(){
|
|||
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<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
|
||||
r += it->Indice().size() / 256;
|
||||
r += it->Indice().size() % 256;
|
||||
|
@ -229,22 +316,35 @@ 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;
|
||||
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<AMF::Object>::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;
|
||||
}
|
||||
break;
|
||||
case AMF::AMF0_DDV_CONTAINER: //only send contents
|
||||
if (contents.size() > 0){
|
||||
for (std::vector<AMF::Object>::iterator it = contents.begin(); it != contents.end(); it++){
|
||||
|
@ -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.
|
||||
|
@ -350,7 +450,8 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
|
|||
}
|
||||
i += 3; //skip 0x000009
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case AMF::AMF0_TYPED_OBJ: {
|
||||
++i;
|
||||
tmpi = data[i] * 256 + data[i + 1]; //set tmpi to the UTF-8 length
|
||||
|
@ -366,7 +467,8 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
|
|||
}
|
||||
i += 3; //skip 0x000009
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case AMF::AMF0_ECMA_ARRAY: {
|
||||
++i;
|
||||
AMF::Object ret(name, AMF::AMF0_ECMA_ARRAY);
|
||||
|
@ -380,7 +482,8 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
|
|||
}
|
||||
i += 3; //skip 0x000009
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
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
|
||||
|
@ -390,7 +493,8 @@ AMF::Object AMF::parseOne(const unsigned char *& data, unsigned int &len, unsign
|
|||
--tmpi;
|
||||
}
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if DEBUG >= 2
|
||||
fprintf(stderr, "Error: Unimplemented AMF type %hhx - returning.\n", data[i]);
|
||||
|
@ -406,7 +510,11 @@ AMF::Object AMF::parse(const unsigned char * data, unsigned int len){
|
|||
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
|
||||
|
@ -420,69 +528,93 @@ AMF::Object AMF::parse(std::string data){
|
|||
|
||||
/// 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<AMF::Object3>::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<AMF::Object3>::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.
|
||||
|
@ -495,7 +627,7 @@ AMF::Object3::Object3(std::string indice, double val, AMF::obj3type setType){//n
|
|||
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.
|
||||
|
@ -508,7 +640,7 @@ 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.
|
||||
|
@ -522,7 +654,7 @@ AMF::Object3::Object3(std::string indice, std::string val, AMF::obj3type 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.
|
||||
|
@ -534,7 +666,7 @@ AMF::Object3::Object3(std::string indice, AMF::obj3type setType){//object type i
|
|||
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<AMF::Object3>::iterator it = contents.begin(); it != contents.end(); it++){it->Print(indent+" ");}
|
||||
for (std::vector<AMF::Object3>::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.
|
||||
|
@ -879,7 +1050,8 @@ AMF::Object3 AMF::parseOne3(const unsigned char *& data, unsigned int &len, unsi
|
|||
--arrsize;
|
||||
}
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case AMF::AMF3_OBJECT: {
|
||||
if (data[i + 1] < 0x80){
|
||||
tmpi = data[i + 1];
|
||||
|
@ -946,7 +1118,8 @@ AMF::Object3 AMF::parseOne3(const unsigned char *& data, unsigned int &len, unsi
|
|||
}while (tmpi > 0); //keep reading dynamic values until empty string
|
||||
} //dynamic types
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if DEBUG >= 2
|
||||
fprintf(stderr, "Error: Unimplemented AMF3 type %hhx - returning.\n", data[i]);
|
||||
|
@ -962,7 +1135,11 @@ AMF::Object3 AMF::parse3(const unsigned char * data, unsigned int len){
|
|||
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
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
//#include <string.h>
|
||||
#include <string>
|
||||
|
||||
/// Holds all AMF parsing and creation related functions and classes.
|
||||
|
@ -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<Object> 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);
|
||||
|
@ -117,7 +117,8 @@ namespace AMF{
|
|||
double dblval; ///< Holds this objects double value, if any.
|
||||
int intval; ///< Holds this objects int value, if any.
|
||||
std::vector<Object3> 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);
|
||||
|
@ -126,4 +127,4 @@ namespace AMF{
|
|||
/// 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
|
||||
|
|
40
lib/auth.cpp
40
lib/auth.cpp
|
@ -8,33 +8,19 @@
|
|||
|
||||
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.
|
||||
|
|
|
@ -17,16 +17,28 @@ std::string Base64::encode(std::string const input) {
|
|||
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
|
||||
|
@ -42,23 +54,33 @@ std::string Base64::decode(std::string const& encoded_string) {
|
|||
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_++;
|
||||
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]);}
|
||||
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]);}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -62,8 +62,12 @@ void Util::Config::addOption(std::string optname, JSON::Value option){
|
|||
}
|
||||
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<long long int, std::string> 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,13 +157,14 @@ 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){
|
||||
|
@ -153,22 +176,30 @@ void Util::Config::parseArgs(int argc, char ** argv){
|
|||
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())){
|
||||
|
@ -306,21 +337,33 @@ 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.\"}"));
|
||||
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);
|
||||
return tPath;
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
/// Contains generic function headers for managing configuration.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef PACKAGE_VERSION
|
||||
#define PACKAGE_VERSION "unknown"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include "json.h"
|
||||
|
||||
|
@ -40,4 +45,5 @@ namespace Util{
|
|||
/// Will turn the current process into a daemon.
|
||||
void Daemonize();
|
||||
|
||||
};
|
||||
}
|
||||
;
|
||||
|
|
25
lib/crypto.h
25
lib/crypto.h
|
@ -1,25 +0,0 @@
|
|||
/// \file crypto.h
|
||||
/// Holds all headers needed for RTMP cryptography functions.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/rc4.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
|
||||
|
||||
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);
|
132
lib/dtsc.cpp
132
lib/dtsc.cpp
|
@ -5,12 +5,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h> //for memcmp
|
||||
#include <arpa/inet.h> //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,7 +42,9 @@ 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);
|
||||
|
@ -47,7 +52,9 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
|
|||
}
|
||||
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,13 +66,23 @@ 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();}
|
||||
while (buffers.size() > buffercount){
|
||||
buffers.pop_back();
|
||||
}
|
||||
advanceRings();
|
||||
syncing = false;
|
||||
return true;
|
||||
|
@ -97,7 +114,9 @@ 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);
|
||||
metadata = JSON::fromDTMI((unsigned char*)wholepacket.c_str() + 8, len, i);
|
||||
|
@ -105,7 +124,9 @@ bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){
|
|||
}
|
||||
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);
|
||||
|
@ -118,12 +139,22 @@ 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;
|
||||
|
@ -186,18 +217,29 @@ void DTSC::Stream::advanceRings(){
|
|||
std::set<DTSC::Ring *>::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;}
|
||||
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<DTSC::Ring *>::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.
|
||||
|
@ -300,11 +344,17 @@ long long int DTSC::File::addHeader(std::string & header){
|
|||
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;}
|
||||
if (ret != 1){
|
||||
return 0;
|
||||
}
|
||||
ret = fwrite((void*)( &hSize), 4, 1, F); //write size
|
||||
if (ret != 1){return 0;}
|
||||
if (ret != 1){
|
||||
return 0;
|
||||
}
|
||||
ret = fwrite(header.c_str(), header.size(), 1, F); //write contents
|
||||
if (ret != 1){return 0;}
|
||||
if (ret != 1){
|
||||
return 0;
|
||||
}
|
||||
return writePos; //return position written at
|
||||
}
|
||||
|
||||
|
@ -423,13 +473,19 @@ 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.
|
||||
|
@ -444,7 +500,10 @@ bool DTSC::File::seek_frame(int frameno){
|
|||
}
|
||||
}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
|
||||
|
@ -452,7 +511,9 @@ bool DTSC::File::seek_frame(int frameno){
|
|||
#endif
|
||||
while (currframe < frameno){
|
||||
seekNext();
|
||||
if (jsonbuffer.isNull()){return false;}
|
||||
if (jsonbuffer.isNull()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
seek_frame(frameno);
|
||||
return true;
|
||||
|
@ -468,8 +529,13 @@ 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
|
||||
|
@ -477,7 +543,9 @@ bool DTSC::File::seek_time(int ms){
|
|||
#endif
|
||||
while (currtime < ms){
|
||||
seekNext();
|
||||
if (jsonbuffer.isNull()){return false;}
|
||||
if (jsonbuffer.isNull()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (currtime > ms){
|
||||
return seek_frame(currframe - 1);
|
||||
|
|
|
@ -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:
|
||||
|
@ -91,8 +89,8 @@ 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
|
||||
|
@ -134,4 +132,4 @@ namespace DTSC{
|
|||
datatype datapointertype;
|
||||
unsigned int buffercount;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
#include "filesystem.h"
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
Filesystem::Directory::~Directory( ) { }
|
||||
Filesystem::Directory::~Directory(){
|
||||
}
|
||||
|
||||
void Filesystem::Directory::FillEntries(){
|
||||
fprintf(stderr, "Filling Entries of %s:\n", (MyBase + MyPath).c_str());
|
||||
|
@ -21,7 +25,7 @@ void Filesystem::Directory::FillEntries( ) {
|
|||
ValidDir = false;
|
||||
}else{
|
||||
dirent * entry;
|
||||
while( entry = readdir( Dirp ) ) {
|
||||
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;
|
||||
|
@ -64,7 +68,9 @@ std::string Filesystem::Directory::LIST( std::vector<std::string> ActiveStreams
|
|||
char datestring[256]; //For time localisation
|
||||
|
||||
std::string MyLoc = MyBase + MyPath;
|
||||
if( MyLoc[MyLoc.size()-1] != '/' ) { MyLoc += "/"; }
|
||||
if (MyLoc[MyLoc.size() - 1] != '/'){
|
||||
MyLoc += "/";
|
||||
}
|
||||
|
||||
for (std::map<std::string, struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++){
|
||||
|
||||
|
@ -73,19 +79,59 @@ std::string Filesystem::Directory::LIST( std::vector<std::string> ActiveStreams
|
|||
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 << '-'; }
|
||||
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 << '-'; }
|
||||
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 << '-'; }
|
||||
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 (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 << ' ';
|
||||
|
@ -147,7 +193,9 @@ std::string Filesystem::Directory::RETR( std::string Path ) {
|
|||
}
|
||||
std::ifstream File;
|
||||
File.open(FileName.c_str());
|
||||
while( File.good() ) { Result += File.get(); }
|
||||
while (File.good()){
|
||||
Result += File.get();
|
||||
}
|
||||
File.close();
|
||||
return Result;
|
||||
}
|
||||
|
@ -191,7 +239,9 @@ bool Filesystem::Directory::SimplifyPath( ) {
|
|||
MyPath = "";
|
||||
for (std::vector<std::string>::iterator it = TempPath.begin(); it != TempPath.end(); it++){
|
||||
MyPath += ( *it);
|
||||
if( it != ( TempPath.end() - 1 ) ) { MyPath += "/"; }
|
||||
if (it != (TempPath.end() - 1)){
|
||||
MyPath += "/";
|
||||
}
|
||||
}
|
||||
if (MyVisible.find(MyPath) == MyVisible.end()){
|
||||
MyVisible[MyPath] = S_ALL;
|
||||
|
|
|
@ -32,10 +32,7 @@ namespace Filesystem {
|
|||
};
|
||||
|
||||
enum DIR_Show{
|
||||
S_NONE = 0x00,
|
||||
S_ACTIVE = 0x01,
|
||||
S_INACTIVE = 0x02,
|
||||
S_ALL = 0x03,
|
||||
S_NONE = 0x00, S_ACTIVE = 0x01, S_INACTIVE = 0x02, S_ALL = 0x03,
|
||||
};
|
||||
|
||||
class Directory{
|
||||
|
@ -65,5 +62,6 @@ namespace Filesystem {
|
|||
std::map<std::string, struct stat> Entries;
|
||||
std::map<std::string, char> MyPermissions;
|
||||
std::map<std::string, char> MyVisible;
|
||||
};//Directory Class
|
||||
};//Filesystem namespace
|
||||
};
|
||||
//Directory Class
|
||||
}//Filesystem namespace
|
||||
|
|
534
lib/flv_tag.cpp
534
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 <stdio.h> //for Tag::FileLoader
|
||||
#include <unistd.h> //for Tag::FileLoader
|
||||
#include <fcntl.h> //for Tag::FileLoader
|
||||
|
@ -57,17 +57,31 @@ 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;
|
||||
}
|
||||
|
@ -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,62 +124,140 @@ 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;
|
||||
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)){
|
||||
|
@ -198,7 +294,12 @@ void FLV::Tag::tagTime(unsigned int T){
|
|||
/// 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;
|
||||
len = 0;
|
||||
buf = 0;
|
||||
data = 0;
|
||||
isKeyframe = false;
|
||||
done = true;
|
||||
sofar = 0;
|
||||
} //empty constructor
|
||||
|
||||
/// Copy constructor, copies the contents of an existing tag.
|
||||
|
@ -219,13 +320,17 @@ FLV::Tag::Tag(const Tag& O){
|
|||
isKeyframe = O.isKeyframe;
|
||||
} //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);
|
||||
}
|
||||
|
||||
|
@ -258,13 +363,17 @@ 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:
|
||||
|
@ -289,18 +398,32 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){
|
|||
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;}
|
||||
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: {
|
||||
if ((unsigned int)len == S.lastData().length() + 16){
|
||||
|
@ -310,8 +433,12 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){
|
|||
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;
|
||||
|
@ -320,22 +447,34 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){
|
|||
}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());
|
||||
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;
|
||||
|
@ -425,8 +564,12 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){
|
|||
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;
|
||||
|
@ -435,8 +578,12 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){
|
|||
}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;
|
||||
|
@ -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"){
|
||||
|
@ -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,17 +777,24 @@ 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;}
|
||||
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
|
||||
|
||||
|
||||
/// 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!
|
||||
/// While this function returns false, the Tag might not contain valid data.
|
||||
|
@ -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,7 +846,11 @@ 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;
|
||||
|
@ -690,7 +859,6 @@ bool FLV::Tag::MemLoader(char * D, unsigned int S, unsigned int & P){
|
|||
return false;
|
||||
} //Tag::MemLoader
|
||||
|
||||
|
||||
/// Helper function for FLV::FileLoader.
|
||||
/// This function will try to read count bytes from file f into buffer.
|
||||
/// This function should be called repeatedly until true.
|
||||
|
@ -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;}
|
||||
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);
|
||||
|
@ -772,17 +962,31 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){
|
|||
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")){
|
||||
|
@ -814,14 +1018,28 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!metadata.isMember("length")){metadata["length"] = 0;}
|
||||
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["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
|
||||
}
|
||||
|
@ -839,35 +1057,59 @@ JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){
|
|||
pack_out["time"] = tagTime();
|
||||
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){
|
||||
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){
|
||||
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){
|
||||
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();}
|
||||
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();}
|
||||
if (len < 17){
|
||||
return JSON::Value();
|
||||
}
|
||||
pack_out["data"] = std::string((char*)data + 12, (size_t)len - 16);
|
||||
}
|
||||
return pack_out;
|
||||
|
@ -876,42 +1118,70 @@ 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();}
|
||||
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();}
|
||||
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.
|
||||
}
|
||||
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();}
|
||||
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();}
|
||||
if (len < 17){
|
||||
return JSON::Value();
|
||||
}
|
||||
pack_out["data"] = std::string((char*)data + 12, (size_t)len - 16);
|
||||
}
|
||||
return pack_out;
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
#include "json.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
//forward declaration of RTMPStream::Chunk to avoid circular dependencies.
|
||||
namespace RTMPStream {
|
||||
class Chunk;
|
||||
};
|
||||
}
|
||||
|
||||
/// This namespace holds all FLV-parsing related functionality.
|
||||
namespace FLV {
|
||||
|
@ -59,6 +60,7 @@ namespace FLV {
|
|||
void Meta_Put(JSON::Value & meta, std::string cat, std::string elem, std::string val);
|
||||
void Meta_Put(JSON::Value & meta, std::string cat, std::string elem, uint64_t val);
|
||||
bool Meta_Has(JSON::Value & meta, std::string cat, std::string elem);
|
||||
};//Tag
|
||||
};
|
||||
//Tag
|
||||
|
||||
};//FLV namespace
|
||||
}//FLV namespace
|
||||
|
|
316
lib/ftp.cpp
316
lib/ftp.cpp
|
@ -2,6 +2,7 @@
|
|||
|
||||
FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::string> Credentials){
|
||||
Conn = NewConnection;
|
||||
MyPassivePort = 0;
|
||||
USER = "";
|
||||
PASS = "";
|
||||
MODE = MODE_STREAM;
|
||||
|
@ -35,32 +36,98 @@ FTP::User::User( Socket::Connection NewConnection, std::map<std::string,std::str
|
|||
}
|
||||
}
|
||||
|
||||
FTP::User::~User( ) { }
|
||||
FTP::User::~User(){
|
||||
}
|
||||
|
||||
int FTP::User::ParseCommand(std::string Command){
|
||||
Commands ThisCmd = CMD_NOCMD;
|
||||
if( Command.substr(0,4) == "NOOP" ) { ThisCmd = CMD_NOOP; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "USER" ) { ThisCmd = CMD_USER; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "PASS" ) { ThisCmd = CMD_PASS; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "QUIT" ) { ThisCmd = CMD_QUIT; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "PORT" ) { ThisCmd = CMD_PORT; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "RETR" ) { ThisCmd = CMD_RETR; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "STOR" ) { ThisCmd = CMD_STOR; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "TYPE" ) { ThisCmd = CMD_TYPE; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "MODE" ) { ThisCmd = CMD_MODE; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "STRU" ) { ThisCmd = CMD_STRU; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "EPSV" ) { ThisCmd = CMD_EPSV; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "PASV" ) { ThisCmd = CMD_PASV; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "LIST" ) { ThisCmd = CMD_LIST; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "CDUP" ) { ThisCmd = CMD_CDUP; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "DELE" ) { ThisCmd = CMD_DELE; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "RNFR" ) { ThisCmd = CMD_RNFR; Command.erase(0,5); }
|
||||
if( Command.substr(0,4) == "RNTO" ) { ThisCmd = CMD_RNTO; Command.erase(0,5); }
|
||||
if( Command.substr(0,3) == "PWD" ) { ThisCmd = CMD_PWD; Command.erase(0,4); }
|
||||
if( Command.substr(0,3) == "CWD" ) { ThisCmd = CMD_CWD; Command.erase(0,4); }
|
||||
if( Command.substr(0,3) == "RMD" ) { ThisCmd = CMD_RMD; Command.erase(0,4); }
|
||||
if( Command.substr(0,3) == "MKD" ) { ThisCmd = CMD_MKD; Command.erase(0,4); }
|
||||
if( ThisCmd != CMD_RNTO ) { RNFR = ""; }
|
||||
if (Command.substr(0, 4) == "NOOP"){
|
||||
ThisCmd = CMD_NOOP;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "USER"){
|
||||
ThisCmd = CMD_USER;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "PASS"){
|
||||
ThisCmd = CMD_PASS;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "QUIT"){
|
||||
ThisCmd = CMD_QUIT;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "PORT"){
|
||||
ThisCmd = CMD_PORT;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "RETR"){
|
||||
ThisCmd = CMD_RETR;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "STOR"){
|
||||
ThisCmd = CMD_STOR;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "TYPE"){
|
||||
ThisCmd = CMD_TYPE;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "MODE"){
|
||||
ThisCmd = CMD_MODE;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "STRU"){
|
||||
ThisCmd = CMD_STRU;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "EPSV"){
|
||||
ThisCmd = CMD_EPSV;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "PASV"){
|
||||
ThisCmd = CMD_PASV;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "LIST"){
|
||||
ThisCmd = CMD_LIST;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "CDUP"){
|
||||
ThisCmd = CMD_CDUP;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "DELE"){
|
||||
ThisCmd = CMD_DELE;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "RNFR"){
|
||||
ThisCmd = CMD_RNFR;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "RNTO"){
|
||||
ThisCmd = CMD_RNTO;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 3) == "PWD"){
|
||||
ThisCmd = CMD_PWD;
|
||||
Command.erase(0, 4);
|
||||
}
|
||||
if (Command.substr(0, 3) == "CWD"){
|
||||
ThisCmd = CMD_CWD;
|
||||
Command.erase(0, 4);
|
||||
}
|
||||
if (Command.substr(0, 3) == "RMD"){
|
||||
ThisCmd = CMD_RMD;
|
||||
Command.erase(0, 4);
|
||||
}
|
||||
if (Command.substr(0, 3) == "MKD"){
|
||||
ThisCmd = CMD_MKD;
|
||||
Command.erase(0, 4);
|
||||
}
|
||||
if (ThisCmd != CMD_RNTO){
|
||||
RNFR = "";
|
||||
}
|
||||
switch (ThisCmd){
|
||||
case CMD_NOOP: {
|
||||
return 200; //Command okay.
|
||||
|
@ -69,14 +136,20 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
case CMD_USER: {
|
||||
USER = "";
|
||||
PASS = "";
|
||||
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
|
||||
if (Command == ""){
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
USER = Command;
|
||||
return 331; //User name okay, need password.
|
||||
break;
|
||||
}
|
||||
case CMD_PASS: {
|
||||
if( USER == "" ) { return 503; }//Bad sequence of commands
|
||||
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
|
||||
if (USER == ""){
|
||||
return 503;
|
||||
} //Bad sequence of commands
|
||||
if (Command == ""){
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
PASS = Command;
|
||||
if ( !LoggedIn()){
|
||||
USER = "";
|
||||
|
@ -109,14 +182,20 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
break;
|
||||
}
|
||||
case CMD_PORT: {
|
||||
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.
|
||||
PORT = atoi(Command.c_str());
|
||||
return 200; //Command okay.
|
||||
break;
|
||||
}
|
||||
case CMD_EPSV: {
|
||||
if( !LoggedIn( ) ) { return 530; }//Not logged in.
|
||||
if ( !LoggedIn()){
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
MyPassivePort = (rand() % 9999);
|
||||
std::cout << ":" << MyPassivePort << "\n";
|
||||
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
||||
|
@ -124,7 +203,9 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
break;
|
||||
}
|
||||
case CMD_PASV: {
|
||||
if( !LoggedIn( ) ) { return 530; }//Not logged in.
|
||||
if ( !LoggedIn()){
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
MyPassivePort = (rand() % 9999) + 49152;
|
||||
std::cout << ":" << MyPassivePort << "\n";
|
||||
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
||||
|
@ -132,9 +213,15 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
break;
|
||||
}
|
||||
case CMD_RETR: {
|
||||
if( !LoggedIn( ) ) { return 530; }//Not logged in.
|
||||
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
|
||||
if( !MyDir.HasPermission( Filesystem::P_RETR ) ) { return 550; }//Access denied.
|
||||
if ( !LoggedIn()){
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
if (Command == ""){
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
if ( !MyDir.HasPermission(Filesystem::P_RETR)){
|
||||
return 550;
|
||||
} //Access denied.
|
||||
std::cout << "Listening on :" << MyPassivePort << "\n";
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()){
|
||||
|
@ -153,9 +240,15 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
break;
|
||||
}
|
||||
case CMD_STOR: {
|
||||
if( !LoggedIn( ) ) { return 530; }//Not logged in.
|
||||
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
|
||||
if( !MyDir.HasPermission( Filesystem::P_STOR ) ) { return 550; }//Access denied.
|
||||
if ( !LoggedIn()){
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
if (Command == ""){
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
if ( !MyDir.HasPermission(Filesystem::P_STOR)){
|
||||
return 550;
|
||||
} //Access denied.
|
||||
std::cout << "Listening on :" << MyPassivePort << "\n";
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()){
|
||||
|
@ -168,7 +261,8 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
}
|
||||
fprintf(stderr, "Reading STOR information\n");
|
||||
std::string Buffer;
|
||||
while( Connected.spool() ) { }
|
||||
while (Connected.spool()){
|
||||
}
|
||||
/// \todo Comment me back in. ^_^
|
||||
//Buffer = Connected.Received();
|
||||
MyDir.STOR(Command, Buffer);
|
||||
|
@ -176,22 +270,36 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
break;
|
||||
}
|
||||
case CMD_TYPE: {
|
||||
if( !LoggedIn( ) ) { return 530; }//Not logged in.
|
||||
if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
|
||||
if( Command.size() != 1 && Command.size() != 3 ) { 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.
|
||||
if (Command.size() != 1 && Command.size() != 3){
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
switch (Command[0]){
|
||||
case 'A': {
|
||||
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[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[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;
|
||||
|
@ -205,18 +313,32 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
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.
|
||||
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.
|
||||
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;
|
||||
|
@ -235,13 +357,19 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
break;
|
||||
}
|
||||
case CMD_PWD: {
|
||||
if( !LoggedIn( ) ) { return 550; }//Not logged in.
|
||||
if( Command != "" ) { return 501; }//Syntax error in parameters or arguments.
|
||||
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()){
|
||||
|
@ -253,8 +381,12 @@ 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()){
|
||||
|
@ -266,39 +398,73 @@ 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
|
||||
}
|
||||
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: {
|
||||
|
@ -309,7 +475,9 @@ int FTP::User::ParseCommand( std::string Command ) {
|
|||
}
|
||||
|
||||
bool FTP::User::LoggedIn(){
|
||||
if( USER == "" || PASS == "" ) { return false; }
|
||||
if (USER == "" || PASS == ""){
|
||||
return false;
|
||||
}
|
||||
if ( !AllCredentials.size()){
|
||||
return true;
|
||||
}
|
||||
|
|
23
lib/ftp.h
23
lib/ftp.h
|
@ -16,17 +16,18 @@ namespace FTP {
|
|||
|
||||
enum Mode{
|
||||
MODE_STREAM,
|
||||
};//FTP::Mode enumeration
|
||||
};
|
||||
//FTP::Mode enumeration
|
||||
|
||||
enum Structure{
|
||||
STRU_FILE,
|
||||
STRU_RECORD,
|
||||
};//FTP::Structure enumeration
|
||||
STRU_FILE, STRU_RECORD,
|
||||
};
|
||||
//FTP::Structure enumeration
|
||||
|
||||
enum Type{
|
||||
TYPE_ASCII_NONPRINT,
|
||||
TYPE_IMAGE_NONPRINT,
|
||||
};//FTP::Type enumeration
|
||||
TYPE_ASCII_NONPRINT, TYPE_IMAGE_NONPRINT,
|
||||
};
|
||||
//FTP::Type enumeration
|
||||
|
||||
enum Commands{
|
||||
CMD_NOCMD,
|
||||
|
@ -51,7 +52,8 @@ namespace FTP {
|
|||
CMD_MKD,
|
||||
CMD_RNFR,
|
||||
CMD_RNTO,
|
||||
};//FTP::Commands enumeration
|
||||
};
|
||||
//FTP::Commands enumeration
|
||||
|
||||
class User{
|
||||
public:
|
||||
|
@ -74,6 +76,7 @@ namespace FTP {
|
|||
Filesystem::Directory MyDir;
|
||||
std::string RNFR;
|
||||
std::vector<std::string> ActiveStreams;
|
||||
};//FTP::User class
|
||||
};
|
||||
//FTP::User class
|
||||
|
||||
};//FTP Namespace
|
||||
}//FTP Namespace
|
||||
|
|
|
@ -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,7 +29,9 @@ void HTTP::Parser::Clean(){
|
|||
std::string & HTTP::Parser::BuildRequest(){
|
||||
/// \todo Include GET/POST variable parsing?
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){protocol = "HTTP/1.0";}
|
||||
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 != ""){
|
||||
|
@ -47,7 +51,9 @@ std::string & HTTP::Parser::BuildRequest(){
|
|||
std::string & HTTP::Parser::BuildResponse(std::string code, std::string message){
|
||||
/// \todo Include GET/POST variable parsing?
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
if (protocol.size() < 5 || protocol.substr(0, 4) != "HTTP"){protocol = "HTTP/1.0";}
|
||||
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 != ""){
|
||||
|
@ -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){
|
||||
|
@ -153,28 +167,38 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
|||
}else{
|
||||
HTTPbuffer.erase(0, f + 1);
|
||||
}
|
||||
while (tmpA.find('\r') != std::string::npos){tmpA.erase(tmpA.find('\r'));}
|
||||
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
|
||||
}
|
||||
}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(':');
|
||||
|
@ -267,7 +291,11 @@ std::string HTTP::Parser::urlunescape(const std::string & in){
|
|||
}
|
||||
out += tmp;
|
||||
}else{
|
||||
if (in[i] == '+'){out += ' ';}else{out += in[i];}
|
||||
if (in[i] == '+'){
|
||||
out += ' ';
|
||||
}else{
|
||||
out += in[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
@ -284,7 +312,8 @@ std::string HTTP::Parser::urlencode(const std::string &c){
|
|||
std::string escaped = "";
|
||||
int max = c.length();
|
||||
for (int i = 0; i < max; i++){
|
||||
if (('0'<=c[i] && c[i]<='9') || ('a'<=c[i] && c[i]<='z') || ('A'<=c[i] && c[i]<='Z') || (c[i]=='~' || c[i]=='!' || c[i]=='*' || c[i]=='(' || c[i]==')' || c[i]=='\'')){
|
||||
if (('0' <= c[i] && c[i] <= '9') || ('a' <= c[i] && c[i] <= 'z') || ('A' <= c[i] && c[i] <= 'Z')
|
||||
|| (c[i] == '~' || c[i] == '!' || c[i] == '*' || c[i] == '(' || c[i] == ')' || c[i] == '\'')){
|
||||
escaped.append( &c[i], 1);
|
||||
}else{
|
||||
escaped.append("%");
|
||||
|
|
|
@ -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
|
||||
|
|
189
lib/json.cpp
189
lib/json.cpp
|
@ -7,7 +7,6 @@
|
|||
#include <stdint.h> //for uint64_t
|
||||
#include <string.h> //for memcpy
|
||||
#include <arpa/inet.h> //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 '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();
|
||||
}
|
||||
}
|
||||
|
@ -146,11 +177,15 @@ JSON::Value::Value(std::istream & 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':
|
||||
|
@ -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<std::string, Value>::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<Value>::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;
|
||||
|
@ -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,12 +346,24 @@ 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;}
|
||||
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...
|
||||
}
|
||||
|
||||
|
@ -320,7 +380,6 @@ const bool JSON::Value::asBool(){
|
|||
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,10 +421,14 @@ 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;
|
||||
|
@ -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.
|
||||
|
@ -429,7 +497,6 @@ std::string & JSON::Value::toNetPacked(){
|
|||
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 += "}";
|
||||
|
@ -502,7 +573,9 @@ std::string JSON::Value::toPrettyString(int indentation){
|
|||
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";}
|
||||
if (it + 1 != ArrEnd()){
|
||||
tmp += ",\n";
|
||||
}
|
||||
}
|
||||
tmp += "\n" + std::string(indentation, ' ') + "]";
|
||||
return tmp;
|
||||
|
@ -519,7 +592,9 @@ std::string JSON::Value::toPrettyString(int indentation){
|
|||
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";}
|
||||
if (it2 != it3){
|
||||
tmp2 += ",\n";
|
||||
}
|
||||
}
|
||||
tmp2 += "\n" + std::string(indentation, ' ') + "}";
|
||||
return tmp2;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -688,13 +767,15 @@ JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigne
|
|||
i += 9; //skip 8(an uint64_t)+1 forwards
|
||||
uint64_t * d = (uint64_t*)tmpdbl;
|
||||
return JSON::Value((long long int) *d);
|
||||
} break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case 0xFF: //also object
|
||||
case 0xE0: { //object
|
||||
++i;
|
||||
|
@ -707,7 +788,8 @@ JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigne
|
|||
}
|
||||
i += 3; //skip 0x0000EE
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case 0x0A: { //array
|
||||
JSON::Value ret;
|
||||
++i;
|
||||
|
@ -716,7 +798,8 @@ JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigne
|
|||
}
|
||||
i += 3; //skip 0x0000EE
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if DEBUG >= 2
|
||||
fprintf(stderr, "Error: Unimplemented DTMI type %hhx - returning.\n", data[i]);
|
||||
|
|
13
lib/json.h
13
lib/json.h
|
@ -7,15 +7,20 @@
|
|||
#include <istream>
|
||||
|
||||
//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 {
|
||||
|
||||
/// 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<std::string, Value>::iterator ObjIter;
|
||||
typedef std::deque<Value>::iterator ArrIter;
|
||||
|
@ -92,4 +97,4 @@ namespace JSON{
|
|||
Value fromString(std::string json);
|
||||
Value fromFile(std::string filename);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
826
lib/mp4.cpp
826
lib/mp4.cpp
File diff suppressed because it is too large
Load diff
29
lib/mp4.h
29
lib/mp4.h
|
@ -16,7 +16,7 @@ namespace MP4{
|
|||
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();
|
||||
|
@ -52,14 +52,16 @@ namespace MP4{
|
|||
int data_size; ///< Currently reserved size
|
||||
bool managed; ///< If false, will not attempt to resize/free the data pointer.
|
||||
int payloadOffset; ///<The offset of the payload with regards to the data
|
||||
};//Box Class
|
||||
};
|
||||
//Box Class
|
||||
|
||||
struct afrt_runtable{
|
||||
long firstFragment;
|
||||
long long int firstTimestamp;
|
||||
long duration;
|
||||
long discontinuity;
|
||||
};//fragmentRun
|
||||
};
|
||||
//fragmentRun
|
||||
|
||||
/// AFRT Box class
|
||||
class AFRT: public Box{
|
||||
|
@ -78,7 +80,8 @@ namespace MP4{
|
|||
void setFragmentRun(afrt_runtable newRun, long no);
|
||||
afrt_runtable getFragmentRun(long no);
|
||||
std::string toPrettyString(int indent = 0);
|
||||
};//AFRT Box
|
||||
};
|
||||
//AFRT Box
|
||||
|
||||
struct asrt_runtable{
|
||||
long firstSegment;
|
||||
|
@ -100,7 +103,8 @@ namespace MP4{
|
|||
void setSegmentRun(long firstSegment, long fragmentsPerSegment, long no);
|
||||
asrt_runtable getSegmentRun(long no);
|
||||
std::string toPrettyString(int indent = 0);
|
||||
};//ASRT Box
|
||||
};
|
||||
//ASRT Box
|
||||
|
||||
/// ABST Box class
|
||||
class ABST: public Box{
|
||||
|
@ -143,7 +147,8 @@ namespace MP4{
|
|||
void setFragmentRunTable(AFRT & table, long no);
|
||||
AFRT & getFragmentRunTable(long no);
|
||||
std::string toPrettyString(long indent = 0);
|
||||
};//ABST Box
|
||||
};
|
||||
//ABST Box
|
||||
|
||||
class MFHD: public Box{
|
||||
public:
|
||||
|
@ -151,7 +156,8 @@ namespace MP4{
|
|||
void setSequenceNumber(long newSequenceNumber);
|
||||
long getSequenceNumber();
|
||||
std::string toPrettyString(int indent = 0);
|
||||
};//MFHD Box
|
||||
};
|
||||
//MFHD Box
|
||||
|
||||
class MOOF: public Box{
|
||||
public:
|
||||
|
@ -160,7 +166,8 @@ namespace MP4{
|
|||
void setContent(Box & newContent, long no);
|
||||
Box & getContent(long no);
|
||||
std::string toPrettyString(int indent = 0);
|
||||
};//MOOF Box
|
||||
};
|
||||
//MOOF Box
|
||||
|
||||
class TRAF: public Box{
|
||||
public:
|
||||
|
@ -169,7 +176,8 @@ namespace MP4{
|
|||
void setContent(Box & newContent, long no);
|
||||
Box & getContent(long no);
|
||||
std::string toPrettyString(int indent = 0);
|
||||
};//TRAF Box
|
||||
};
|
||||
//TRAF Box
|
||||
|
||||
struct trunSampleInformation{
|
||||
long sampleDuration;
|
||||
|
@ -309,4 +317,5 @@ namespace MP4{
|
|||
void setValue(long newValue, size_t index);
|
||||
long getValue(size_t index);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ bool Util::Procs::handler_set = false;
|
|||
|
||||
/// Used internally to capture child signals and update plist.
|
||||
void Util::Procs::childsig_handler(int signum){
|
||||
if (signum != SIGCHLD){return;}
|
||||
if (signum != SIGCHLD){
|
||||
return;
|
||||
}
|
||||
int status;
|
||||
pid_t ret = waitpid( -1, &status, WNOHANG);
|
||||
if (ret == 0){ //ignore, would block otherwise
|
||||
|
@ -41,7 +43,9 @@ 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
|
||||
std::string pname = plist[ret];
|
||||
|
@ -84,7 +88,9 @@ 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
|
||||
|
@ -98,7 +104,9 @@ 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 (isActive(name)){
|
||||
return getPid(name);
|
||||
}
|
||||
if ( !handler_set){
|
||||
struct sigaction new_action;
|
||||
new_action.sa_handler = Util::Procs::childsig_handler;
|
||||
|
@ -132,7 +140,9 @@ 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 (isActive(name)){
|
||||
return getPid(name);
|
||||
}
|
||||
if ( !handler_set){
|
||||
struct sigaction new_action;
|
||||
new_action.sa_handler = Util::Procs::childsig_handler;
|
||||
|
@ -207,7 +217,9 @@ 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 (isActive(name)){
|
||||
return getPid(name);
|
||||
}
|
||||
if ( !handler_set){
|
||||
struct sigaction new_action;
|
||||
new_action.sa_handler = Util::Procs::childsig_handler;
|
||||
|
@ -329,7 +341,9 @@ 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){
|
||||
|
@ -350,15 +364,24 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
|
|||
#if DEBUG >= 1
|
||||
std::cerr << "Pipe (out) creation failed for " << name << std::endl;
|
||||
#endif
|
||||
if (*fdin == -1){close(pipein[0]);close(pipein[1]);}
|
||||
if ( *fdin == -1){
|
||||
close(pipein[0]);
|
||||
close(pipein[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
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]);}
|
||||
if ( *fdin == -1){
|
||||
close(pipein[0]);
|
||||
close(pipein[1]);
|
||||
}
|
||||
if ( *fdout == -1){
|
||||
close(pipeout[0]);
|
||||
close(pipeout[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int devnull = -1;
|
||||
|
@ -368,9 +391,18 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
|
|||
#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]);}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -406,7 +438,9 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
|
|||
dup2( *fderr, STDERR_FILENO);
|
||||
close( *fderr);
|
||||
}
|
||||
if (devnull != -1){close(devnull);}
|
||||
if (devnull != -1){
|
||||
close(devnull);
|
||||
}
|
||||
execvp(argv[0], argv);
|
||||
#if DEBUG >= 1
|
||||
perror("execvp failed");
|
||||
|
@ -416,10 +450,21 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
|
|||
#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);}
|
||||
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
|
||||
|
@ -430,7 +475,9 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int *
|
|||
if (devnull != -1) std::cerr << " null=" << devnull;
|
||||
std::cerr << ", PID " << pid << ": " << argv[0] << std::endl;
|
||||
#endif
|
||||
if (devnull != -1){close(devnull);}
|
||||
if (devnull != -1){
|
||||
close(devnull);
|
||||
}
|
||||
if (fdin && *fdin == -1){
|
||||
close(pipein[0]); // close unused end end
|
||||
*fdin = pipein[1];
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,7 +533,9 @@ int Util::Procs::Count(){
|
|||
bool Util::Procs::isActive(std::string name){
|
||||
std::map<pid_t, std::string>::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<pid_t, std::string>::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;
|
||||
}
|
||||
|
|
|
@ -35,4 +35,4 @@ namespace Util{
|
|||
static bool SetTerminationNotifier(pid_t pid, TerminationNotifier notifier);
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -39,19 +39,17 @@ std::map<unsigned int, RTMPStream::Chunk> 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){
|
||||
|
@ -104,66 +102,119 @@ DHWrapper::~DHWrapper() {
|
|||
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;}
|
||||
if ( !_pDH){
|
||||
return false;
|
||||
}
|
||||
return CopyKey(_pDH->pub_key, pDst, dstLength);
|
||||
}
|
||||
|
||||
bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength){
|
||||
if (!_pDH){return false;}
|
||||
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;}
|
||||
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 ( !_peerPublickey){
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength){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;}
|
||||
if ( !_pDH){
|
||||
return false;
|
||||
}
|
||||
if (dstLength != _sharedKeyLength){
|
||||
return false;
|
||||
}
|
||||
memcpy(pDst, _pSharedKey, _sharedKeyLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
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){
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -237,7 +288,9 @@ std::string & RTMPStream::Chunk::Pack(){
|
|||
}
|
||||
}
|
||||
//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);
|
||||
|
@ -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);
|
||||
|
@ -290,7 +346,9 @@ 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){
|
||||
|
@ -313,8 +371,9 @@ std::string & RTMPStream::Chunk::Pack(){
|
|||
return output;
|
||||
} //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;
|
||||
|
@ -438,7 +497,6 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
|
|||
return ch.Pack();
|
||||
} //SendUSR
|
||||
|
||||
|
||||
/// Parses the argument string into the current chunk.
|
||||
/// Tries to read a whole chunk, removing data from the input string as it reads.
|
||||
/// If only part of a chunk is read, it will remove the part and call itself again.
|
||||
|
@ -491,11 +549,15 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
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");}
|
||||
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;}
|
||||
if (timestamp != 0x00ffffff){
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = indata[i++ ] * 256 * 256;
|
||||
len += indata[i++ ] * 256;
|
||||
len += indata[i++ ];
|
||||
|
@ -505,18 +567,24 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
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");}
|
||||
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 (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;
|
||||
|
@ -581,7 +649,9 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
||||
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++ ];
|
||||
|
@ -605,7 +675,9 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
headertype = chunktype & 0xC0;
|
||||
switch (headertype){
|
||||
case 0x00:
|
||||
if (!buffer.available(i+11)){return false;} //can't read whole header
|
||||
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;
|
||||
|
@ -621,13 +693,19 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
msg_stream_id += indata[i++ ] * 256 * 256 * 256;
|
||||
break;
|
||||
case 0x40:
|
||||
if (!buffer.available(i+7)){return false;} //can't read whole header
|
||||
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");}
|
||||
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;}
|
||||
if (timestamp != 0x00ffffff){
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = indata[i++ ] * 256 * 256;
|
||||
len += indata[i++ ] * 256;
|
||||
len += indata[i++ ];
|
||||
|
@ -636,20 +714,28 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
msg_stream_id = prev.msg_stream_id;
|
||||
break;
|
||||
case 0x80:
|
||||
if (!buffer.available(i+3)){return false;} //can't read whole header
|
||||
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");}
|
||||
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 (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,7 +756,9 @@ 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
|
||||
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;
|
||||
|
@ -680,7 +768,9 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
|
||||
//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)
|
||||
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
|
||||
|
@ -720,7 +810,9 @@ bool RTMPStream::doHandshake(){
|
|||
//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
|
||||
for (int i = 8; i < 3072; ++i){
|
||||
Server[i] = versionstring[i % 16];
|
||||
} //"random" data
|
||||
|
||||
bool encrypted = (Version == 6);
|
||||
#if DEBUG >= 4
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//forward declaration of FLV::Tag to avoid circular dependencies.
|
||||
namespace FLV {
|
||||
class Tag;
|
||||
};
|
||||
}
|
||||
|
||||
/// Contains all functions and classes needed for RTMP connections.
|
||||
namespace RTMPStream {
|
||||
|
@ -50,7 +50,8 @@ namespace RTMPStream{
|
|||
private:
|
||||
static std::map<unsigned int, Chunk> lastsend;
|
||||
static std::map<unsigned int, Chunk> 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
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#define BUFFER_BLOCKSIZE 4096 //set buffer blocksize to 4KiB
|
||||
#include <iostream>//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,7 +46,9 @@ 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)));
|
||||
|
@ -64,7 +67,9 @@ bool Socket::Buffer::available(unsigned int count){
|
|||
unsigned int i = 0;
|
||||
for (std::deque<std::string>::iterator it = data.begin(); it != data.end(); ++it){
|
||||
i += ( *it).size();
|
||||
if (i >= count){return true;}
|
||||
if (i >= count){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -72,7 +77,9 @@ 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);
|
||||
|
@ -93,7 +100,9 @@ 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<std::string>::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){
|
||||
|
@ -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){
|
||||
|
@ -172,9 +180,15 @@ 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.
|
||||
|
@ -187,29 +201,36 @@ void Socket::Connection::close(){
|
|||
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
|
||||
|
||||
/// 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.
|
||||
|
@ -282,8 +303,12 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
|
|||
|
||||
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);
|
||||
|
@ -357,7 +382,6 @@ bool Socket::Connection::flush(){
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Returns a reference to the download buffer.
|
||||
Socket::Buffer & Socket::Connection::Received(){
|
||||
return downbuffer;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -518,7 +548,9 @@ 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
|
||||
|
@ -529,9 +561,13 @@ 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
|
||||
|
@ -736,7 +772,9 @@ Socket::Server::Server(std::string address, bool nonblock){
|
|||
/// \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];
|
||||
|
@ -789,7 +827,8 @@ void Socket::Server::close(){
|
|||
#endif
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
errno = EINTR;
|
||||
while (::close(sock) != 0 && errno == EINTR){}
|
||||
while (::close(sock) != 0 && errno == EINTR){
|
||||
}
|
||||
sock = -1;
|
||||
}
|
||||
} //Socket::Server::close
|
||||
|
@ -804,4 +843,6 @@ bool Socket::Server::connected() const{
|
|||
} //Socket::Server::connected
|
||||
|
||||
/// Returns internal socket number.
|
||||
int Socket::Server::getSocket(){return sock;}
|
||||
int Socket::Server::getSocket(){
|
||||
return sock;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#include <deque>
|
||||
|
||||
//for being friendly with Socket::Connection down below
|
||||
namespace Buffer{class user;};
|
||||
namespace Buffer {
|
||||
class user;
|
||||
}
|
||||
|
||||
///Holds Socket tools.
|
||||
namespace Socket {
|
||||
|
@ -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{
|
||||
|
@ -107,4 +110,4 @@ namespace Socket{
|
|||
int getSocket(); ///< Returns internal socket number.
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
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 ( *i == '?'){
|
||||
streamname.erase(i, streamname.end());
|
||||
break;
|
||||
}
|
||||
if ( !isalpha( *i) && !isdigit( *i) && *i != '_'){
|
||||
streamname.erase(i);
|
||||
}else{
|
||||
|
|
|
@ -4,11 +4,14 @@
|
|||
#include "timing.h"
|
||||
#include <sys/time.h>//for gettimeofday
|
||||
#include <time.h>//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);
|
||||
|
|
|
@ -7,4 +7,4 @@ 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.
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue