Such style. (Code style unification)
This commit is contained in:
parent
57bcd8f25c
commit
8c01ec8897
57 changed files with 6548 additions and 6437 deletions
642
lib/amf.cpp
642
lib/amf.cpp
File diff suppressed because it is too large
Load diff
20
lib/amf.h
20
lib/amf.h
|
@ -10,7 +10,7 @@
|
|||
namespace AMF {
|
||||
|
||||
/// Enumerates all possible AMF0 types, adding a special DDVTECH container type for ease of use.
|
||||
enum obj0type{
|
||||
enum obj0type {
|
||||
AMF0_NUMBER = 0x00,
|
||||
AMF0_BOOL = 0x01,
|
||||
AMF0_STRING = 0x02,
|
||||
|
@ -33,7 +33,7 @@ namespace AMF {
|
|||
};
|
||||
|
||||
/// Enumerates all possible AMF3 types, adding a special DDVTECH container type for ease of use.
|
||||
enum obj3type{
|
||||
enum obj3type {
|
||||
AMF3_UNDEFINED = 0x00,
|
||||
AMF3_NULL = 0x01,
|
||||
AMF3_FALSE = 0x02,
|
||||
|
@ -52,7 +52,7 @@ namespace AMF {
|
|||
|
||||
/// Recursive class that holds AMF0 objects.
|
||||
/// It supports all AMF0 types (defined in AMF::obj0type), adding support for a special DDVTECH container type.
|
||||
class Object{
|
||||
class Object {
|
||||
public:
|
||||
std::string Indice();
|
||||
obj0type GetType();
|
||||
|
@ -61,9 +61,9 @@ namespace AMF {
|
|||
const char * Str();
|
||||
int hasContent();
|
||||
void addContent(AMF::Object c);
|
||||
Object* getContentP(unsigned int i);
|
||||
Object * getContentP(unsigned int i);
|
||||
Object getContent(unsigned int i);
|
||||
Object* getContentP(std::string s);
|
||||
Object * getContentP(std::string s);
|
||||
Object getContent(std::string s);
|
||||
Object();
|
||||
Object(std::string indice, double val, obj0type setType = AMF0_NUMBER);
|
||||
|
@ -85,11 +85,11 @@ namespace AMF {
|
|||
/// Parses a std::string to a valid AMF::Object.
|
||||
Object parse(std::string data);
|
||||
/// Parses a single AMF0 type - used recursively by the AMF::parse() functions.
|
||||
Object parseOne(const unsigned char *& data, unsigned int &len, unsigned int &i, std::string name);
|
||||
Object parseOne(const unsigned char *& data, unsigned int & len, unsigned int & i, std::string name);
|
||||
|
||||
/// Recursive class that holds AMF3 objects.
|
||||
/// It supports all AMF3 types (defined in AMF::obj3type), adding support for a special DDVTECH container type.
|
||||
class Object3{
|
||||
class Object3 {
|
||||
public:
|
||||
std::string Indice();
|
||||
obj3type GetType();
|
||||
|
@ -99,9 +99,9 @@ namespace AMF {
|
|||
const char * Str();
|
||||
int hasContent();
|
||||
void addContent(AMF::Object3 c);
|
||||
Object3* getContentP(int i);
|
||||
Object3 * getContentP(int i);
|
||||
Object3 getContent(int i);
|
||||
Object3* getContentP(std::string s);
|
||||
Object3 * getContentP(std::string s);
|
||||
Object3 getContent(std::string s);
|
||||
Object3();
|
||||
Object3(std::string indice, int val, obj3type setType = AMF3_INTEGER);
|
||||
|
@ -125,6 +125,6 @@ namespace AMF {
|
|||
/// Parses a std::string to a valid AMF::Object3.
|
||||
Object3 parse3(std::string data);
|
||||
/// Parses a single AMF3 type - used recursively by the AMF::parse3() functions.
|
||||
Object3 parseOne3(const unsigned char *& data, unsigned int &len, unsigned int &i, std::string name);
|
||||
Object3 parseOne3(const unsigned char *& data, unsigned int & len, unsigned int & i, std::string name);
|
||||
|
||||
} //AMF namespace
|
||||
|
|
39
lib/auth.cpp
39
lib/auth.cpp
|
@ -9,40 +9,41 @@
|
|||
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.
|
||||
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.
|
||||
Auth::Auth(){
|
||||
Auth::Auth() {
|
||||
const unsigned char * key = __gbv2keypub_der;
|
||||
pubkey = (void*)d2i_RSAPublicKey(0, &key, __gbv2keypub_der_len);
|
||||
pubkey = (void *)d2i_RSAPublicKey(0, &key, __gbv2keypub_der_len);
|
||||
}
|
||||
|
||||
/// Attempts to verify RSA signature using the public key.
|
||||
/// Assumes basesign argument is base64 encoded RSA signature for data.
|
||||
/// Returns true if the data could be verified, false otherwise.
|
||||
bool Auth::PubKey_Check(std::string & data, std::string basesign){
|
||||
bool Auth::PubKey_Check(std::string & data, std::string basesign) {
|
||||
std::string sign = Base64::decode(basesign);
|
||||
return (RSA_verify(NID_md5, (unsigned char*)data.c_str(), data.size(), (unsigned char*)sign.c_str(), sign.size(), (RSA*)pubkey) == 1);
|
||||
return (RSA_verify(NID_md5, (unsigned char *)data.c_str(), data.size(), (unsigned char *)sign.c_str(), sign.size(), (RSA *)pubkey) == 1);
|
||||
}
|
||||
|
||||
/// Wrapper function for openssl MD5 implementation
|
||||
std::string md5(std::string input){
|
||||
std::string md5(std::string input) {
|
||||
char tmp[3];
|
||||
std::string ret;
|
||||
const unsigned char * res = MD5((const unsigned char*)input.c_str(), input.length(), 0);
|
||||
for (int i = 0; i < 16; ++i){
|
||||
const unsigned char * res = MD5((const unsigned char *)input.c_str(), input.length(), 0);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
snprintf(tmp, 3, "%02x", res[i]);
|
||||
ret += tmp;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <string>
|
||||
|
||||
namespace Secure {
|
||||
class Auth{
|
||||
class Auth {
|
||||
private:
|
||||
void * pubkey; ///< Holds the public key.
|
||||
public:
|
||||
|
|
|
@ -4,39 +4,39 @@
|
|||
const std::string Base64::chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/// Helper for base64_decode function
|
||||
inline bool Base64::is_base64(unsigned char c){
|
||||
inline bool Base64::is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
/// Used to base64 encode data. Input is the plaintext as std::string, output is the encoded data as std::string.
|
||||
/// \param input Plaintext data to encode.
|
||||
/// \returns Base64 encoded data.
|
||||
std::string Base64::encode(std::string const input){
|
||||
std::string Base64::encode(std::string const input) {
|
||||
std::string ret;
|
||||
unsigned int in_len = input.size();
|
||||
char quad[4], triple[3];
|
||||
unsigned int i, x, n = 3;
|
||||
for (x = 0; x < in_len; x = x + 3){
|
||||
if ((in_len - x) / 3 == 0){
|
||||
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++){
|
||||
for (i = 0; i < 3; i++) {
|
||||
triple[i] = '0';
|
||||
}
|
||||
for (i = 0; i < n; i++){
|
||||
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){
|
||||
if (n < 3) {
|
||||
quad[3] = '=';
|
||||
}
|
||||
if (n < 2){
|
||||
if (n < 2) {
|
||||
quad[2] = '=';
|
||||
}
|
||||
for (i = 0; i < 4; i++){
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret += quad[i];
|
||||
}
|
||||
}
|
||||
|
@ -46,34 +46,34 @@ std::string Base64::encode(std::string const input){
|
|||
/// Used to base64 decode data. Input is the encoded data as std::string, output is the plaintext data as std::string.
|
||||
/// \param encoded_string Base64 encoded data to decode.
|
||||
/// \returns Plaintext decoded data.
|
||||
std::string Base64::decode(std::string const& encoded_string){
|
||||
std::string Base64::decode(std::string const & encoded_string) {
|
||||
int in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])){
|
||||
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++ ] = encoded_string[in_];
|
||||
in_++;
|
||||
if (i == 4){
|
||||
for (i = 0; i < 4; i++){
|
||||
if (i == 4) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
char_array_4[i] = chars.find(char_array_4[i]);
|
||||
}
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
for (i = 0; (i < 3); i++){
|
||||
for (i = 0; (i < 3); i++) {
|
||||
ret += char_array_3[i];
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
if (i){
|
||||
for (j = i; j < 4; j++){
|
||||
if (i) {
|
||||
for (j = i; j < 4; j++) {
|
||||
char_array_4[j] = 0;
|
||||
}
|
||||
for (j = 0; j < 4; j++){
|
||||
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);
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
#include <string>
|
||||
|
||||
/// Holds base64 decoding and encoding functions.
|
||||
class Base64{
|
||||
class Base64 {
|
||||
private:
|
||||
static const std::string chars;
|
||||
static inline bool is_base64(unsigned char c);
|
||||
public:
|
||||
static std::string encode(std::string const input);
|
||||
static std::string decode(std::string const& encoded_string);
|
||||
static std::string decode(std::string const & encoded_string);
|
||||
};
|
||||
|
|
|
@ -3,51 +3,51 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Utils{
|
||||
bitstream::bitstream(){
|
||||
namespace Utils {
|
||||
bitstream::bitstream() {
|
||||
data = NULL;
|
||||
offset = 0;
|
||||
dataSize = 0;
|
||||
bufferSize = 0;
|
||||
}
|
||||
|
||||
bool bitstream::checkBufferSize(unsigned int size){
|
||||
if (size > bufferSize){
|
||||
void* temp = realloc(data, size);
|
||||
if (temp){
|
||||
data = (char*) temp;
|
||||
|
||||
bool bitstream::checkBufferSize(unsigned int size) {
|
||||
if (size > bufferSize) {
|
||||
void * temp = realloc(data, size);
|
||||
if (temp) {
|
||||
data = (char *) temp;
|
||||
bufferSize = size;
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void bitstream::append(char* input, size_t bytes){
|
||||
if (checkBufferSize(dataSize+bytes)){
|
||||
memcpy(data+dataSize, input, bytes);
|
||||
|
||||
void bitstream::append(char * input, size_t bytes) {
|
||||
if (checkBufferSize(dataSize + bytes)) {
|
||||
memcpy(data + dataSize, input, bytes);
|
||||
dataSize += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void bitstream::append(std::string input){
|
||||
append((char*)input.c_str(), input.size());
|
||||
void bitstream::append(std::string input) {
|
||||
append((char *)input.c_str(), input.size());
|
||||
}
|
||||
|
||||
bool bitstream::peekOffset(size_t peekOffset){
|
||||
|
||||
bool bitstream::peekOffset(size_t peekOffset) {
|
||||
peekOffset += offset;
|
||||
return ((data[peekOffset >> 3]) >> (7 - (peekOffset & 7))) & 1;
|
||||
}
|
||||
|
||||
long long unsigned int bitstream::peek(size_t count){
|
||||
if (count > 64){
|
||||
|
||||
long long unsigned int bitstream::peek(size_t count) {
|
||||
if (count > 64) {
|
||||
DEBUG_MSG(DLVL_WARN, "Can not read %d bits into a long long unsigned int!", (int)count);
|
||||
//return 0;
|
||||
}
|
||||
if (count > size()){
|
||||
if (count > size()) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Not enough bits left in stream. Left: %d requested: %d", (int)size(), (int)count);
|
||||
return 0;
|
||||
}
|
||||
|
@ -56,11 +56,11 @@ namespace Utils{
|
|||
size_t readSize;
|
||||
size_t readOff;
|
||||
char readBuff;
|
||||
while (curPlace < count){
|
||||
readBuff = data[(int)((offset+curPlace)/8)];
|
||||
while (curPlace < count) {
|
||||
readBuff = data[(int)((offset + curPlace) / 8)];
|
||||
readSize = 8;
|
||||
readOff = (offset + curPlace) % 8; //the reading offset within the byte
|
||||
if (readOff != 0){
|
||||
if (readOff != 0) {
|
||||
//if we start our read not on the start of a byte
|
||||
//curplace and retval should both be 0
|
||||
//this should be the first read that aligns reading to bytes, if we read over the end of read byte
|
||||
|
@ -69,7 +69,7 @@ namespace Utils{
|
|||
readBuff = readBuff & ((1 << readSize) - 1);//bitmasking
|
||||
}
|
||||
//up until here we assume we read to the end of the byte
|
||||
if (count - curPlace < readSize){//if we do not read to the end of the byte
|
||||
if (count - curPlace < readSize) { //if we do not read to the end of the byte
|
||||
//we cut off the LSb off of the read buffer by bitshift
|
||||
readSize = count - curPlace;
|
||||
readBuff = readBuff >> (8 - readSize - readOff);
|
||||
|
@ -79,99 +79,99 @@ namespace Utils{
|
|||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
long long unsigned int bitstream::get(size_t count){
|
||||
if(count <= size()){
|
||||
|
||||
long long unsigned int bitstream::get(size_t count) {
|
||||
if (count <= size()) {
|
||||
long long unsigned int retVal;
|
||||
retVal = peek(count);
|
||||
skip(count);
|
||||
return retVal;
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void bitstream::skip(size_t count){
|
||||
if(count <= size()){
|
||||
|
||||
void bitstream::skip(size_t count) {
|
||||
if (count <= size()) {
|
||||
offset += count;
|
||||
}else{
|
||||
offset = dataSize*8;
|
||||
} else {
|
||||
offset = dataSize * 8;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
long long unsigned int bitstream::size(){
|
||||
|
||||
long long unsigned int bitstream::size() {
|
||||
return (dataSize * 8) - offset;
|
||||
}
|
||||
|
||||
void bitstream::clear(){
|
||||
|
||||
void bitstream::clear() {
|
||||
dataSize = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
void bitstream::flush(){
|
||||
memmove(data, data + (offset/8), dataSize - (offset/8));
|
||||
|
||||
void bitstream::flush() {
|
||||
memmove(data, data + (offset / 8), dataSize - (offset / 8));
|
||||
dataSize -= offset / 8;
|
||||
offset %= 8;
|
||||
}
|
||||
|
||||
long long unsigned int bitstream::golombPeeker(){
|
||||
for (size_t i = 0; i < 64 && i < size(); i++){
|
||||
if (peekOffset(i)){
|
||||
return peek((i * 2) + 1 );
|
||||
|
||||
long long unsigned int bitstream::golombPeeker() {
|
||||
for (size_t i = 0; i < 64 && i < size(); i++) {
|
||||
if (peekOffset(i)) {
|
||||
return peek((i * 2) + 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long long unsigned int bitstream::golombGetter(){
|
||||
for (size_t i = 0; i < 64 && i < size(); i++){
|
||||
if (peekOffset(i)){
|
||||
|
||||
long long unsigned int bitstream::golombGetter() {
|
||||
for (size_t i = 0; i < 64 && i < size(); i++) {
|
||||
if (peekOffset(i)) {
|
||||
return get((i * 2) + 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long long int bitstream::getExpGolomb(){
|
||||
|
||||
long long int bitstream::getExpGolomb() {
|
||||
long long unsigned int temp = golombGetter();
|
||||
return (temp >> 1) * (1 - ((temp & 1) << 1)); //Is actually return (temp / 2) * (1 - (temp & 1) * 2);
|
||||
}
|
||||
|
||||
long long unsigned int bitstream::getUExpGolomb(){
|
||||
|
||||
long long unsigned int bitstream::getUExpGolomb() {
|
||||
return golombGetter() - 1;
|
||||
}
|
||||
|
||||
long long int bitstream::peekExpGolomb(){
|
||||
|
||||
long long int bitstream::peekExpGolomb() {
|
||||
long long unsigned int temp = golombPeeker();
|
||||
return (temp >> 1) * (1 - ((temp & 1) << 1)); //Is actually return (temp / 2) * (1 - (temp & 1) * 2);
|
||||
}
|
||||
|
||||
long long unsigned int bitstream::peekUExpGolomb(){
|
||||
|
||||
long long unsigned int bitstream::peekUExpGolomb() {
|
||||
return golombPeeker() - 1;
|
||||
}
|
||||
|
||||
//Note: other bitstream here
|
||||
bitstreamLSBF::bitstreamLSBF(){
|
||||
|
||||
//Note: other bitstream here
|
||||
bitstreamLSBF::bitstreamLSBF() {
|
||||
readBufferOffset = 0;
|
||||
readBuffer = 0;
|
||||
}
|
||||
|
||||
void bitstreamLSBF::append (char* input, size_t bytes){
|
||||
append(std::string(input,bytes));
|
||||
|
||||
void bitstreamLSBF::append(char * input, size_t bytes) {
|
||||
append(std::string(input, bytes));
|
||||
}
|
||||
|
||||
void bitstreamLSBF::append (std::string input){
|
||||
|
||||
void bitstreamLSBF::append(std::string input) {
|
||||
data += input;
|
||||
fixData();
|
||||
}
|
||||
|
||||
long long unsigned int bitstreamLSBF::size(){
|
||||
|
||||
long long unsigned int bitstreamLSBF::size() {
|
||||
return data.size() * 8 + readBufferOffset;
|
||||
}
|
||||
|
||||
long long unsigned int bitstreamLSBF::get(size_t count){
|
||||
if (count <= 32 && count <= readBufferOffset){
|
||||
|
||||
long long unsigned int bitstreamLSBF::get(size_t count) {
|
||||
if (count <= 32 && count <= readBufferOffset) {
|
||||
long long unsigned int retval = readBuffer & (((long long unsigned int)1 << count) - 1);
|
||||
readBuffer = readBuffer >> count;
|
||||
readBufferOffset -= count;
|
||||
|
@ -181,29 +181,29 @@ namespace Utils{
|
|||
return 42;
|
||||
}
|
||||
|
||||
void bitstreamLSBF::skip(size_t count){
|
||||
if (count <= 32 && count <= readBufferOffset){
|
||||
void bitstreamLSBF::skip(size_t count) {
|
||||
if (count <= 32 && count <= readBufferOffset) {
|
||||
readBuffer = readBuffer >> count;
|
||||
readBufferOffset -= count;
|
||||
fixData();
|
||||
}
|
||||
}
|
||||
|
||||
long long unsigned int bitstreamLSBF::peek(size_t count){
|
||||
if (count <= 32 && count <= readBufferOffset){
|
||||
|
||||
long long unsigned int bitstreamLSBF::peek(size_t count) {
|
||||
if (count <= 32 && count <= readBufferOffset) {
|
||||
return readBuffer & ((1 << count) - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bitstreamLSBF::clear(){
|
||||
|
||||
void bitstreamLSBF::clear() {
|
||||
data = "";
|
||||
readBufferOffset = 0;
|
||||
readBuffer = 0;
|
||||
}
|
||||
|
||||
void bitstreamLSBF::fixData(){
|
||||
while (readBufferOffset <= 32 && data.size() != 0){
|
||||
|
||||
void bitstreamLSBF::fixData() {
|
||||
while (readBufferOffset <= 32 && data.size() != 0) {
|
||||
//readBuffer = readBuffer & ((1 << readBufferOffset) - 1) | (data[0] << readBufferOffset);
|
||||
readBuffer |= (((long long unsigned int)data[0]) << readBufferOffset);
|
||||
data = data.substr(1);
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#include<string>
|
||||
|
||||
namespace Utils{
|
||||
class bitstream{
|
||||
namespace Utils {
|
||||
class bitstream {
|
||||
public:
|
||||
bitstream();
|
||||
bitstream& operator<< (std::string input){
|
||||
bitstream & operator<< (std::string input) {
|
||||
append(input);
|
||||
return *this;
|
||||
};
|
||||
bitstream& operator<< (char input){
|
||||
bitstream & operator<< (char input) {
|
||||
append(std::string(input, 1));
|
||||
return *this;
|
||||
};
|
||||
void append (char* input, size_t bytes);
|
||||
void append (std::string input);
|
||||
void append(char * input, size_t bytes);
|
||||
void append(std::string input);
|
||||
long long unsigned int size();
|
||||
void skip(size_t count);
|
||||
long long unsigned int get(size_t count);
|
||||
|
@ -29,21 +29,21 @@ namespace Utils{
|
|||
bool checkBufferSize(unsigned int size);
|
||||
long long unsigned int golombGetter();
|
||||
long long unsigned int golombPeeker();
|
||||
char* data;
|
||||
char * data;
|
||||
size_t offset;
|
||||
size_t dataSize;
|
||||
size_t bufferSize;
|
||||
};
|
||||
|
||||
class bitstreamLSBF{
|
||||
class bitstreamLSBF {
|
||||
public:
|
||||
bitstreamLSBF();
|
||||
bitstreamLSBF& operator<< (std::string input){
|
||||
bitstreamLSBF & operator<< (std::string input) {
|
||||
append(input);
|
||||
return *this;
|
||||
};
|
||||
void append (char* input, size_t bytes);
|
||||
void append (std::string input);
|
||||
void append(char * input, size_t bytes);
|
||||
void append(std::string input);
|
||||
long long unsigned int size();
|
||||
void skip(size_t count);
|
||||
long long unsigned int get(size_t count);
|
||||
|
|
312
lib/config.cpp
312
lib/config.cpp
|
@ -37,7 +37,7 @@ bool Util::Config::is_active = false;
|
|||
unsigned int Util::Config::printDebugLevel = DEBUG;//
|
||||
std::string Util::Config::libver = PACKAGE_VERSION;
|
||||
|
||||
Util::Config::Config(){
|
||||
Util::Config::Config() {
|
||||
//global options here
|
||||
vals["debug"]["long"] = "debug";
|
||||
vals["debug"]["short"] = "g";
|
||||
|
@ -51,7 +51,7 @@ Util::Config::Config(){
|
|||
}
|
||||
|
||||
/// Creates a new configuration manager.
|
||||
Util::Config::Config(std::string cmd, std::string version){
|
||||
Util::Config::Config(std::string cmd, std::string version) {
|
||||
vals.null();
|
||||
long_count = 2;
|
||||
vals["cmd"]["value"].append(cmd);
|
||||
|
@ -67,7 +67,7 @@ Util::Config::Config(std::string cmd, std::string version){
|
|||
vals["debug"]["short"] = "g";
|
||||
vals["debug"]["arg"] = "integer";
|
||||
vals["debug"]["help"] = "The debug level at which messages need to be printed.";
|
||||
vals["debug"]["value"].append((long long)DEBUG);
|
||||
vals["debug"]["value"].append((long long)DEBUG);
|
||||
}
|
||||
|
||||
/// Adds an option to the configuration parser.
|
||||
|
@ -84,110 +84,110 @@ Util::Config::Config(std::string cmd, std::string version){
|
|||
/// "help":"Blahblahblah" //The helptext for this option.
|
||||
/// }
|
||||
///\endcode
|
||||
void Util::Config::addOption(std::string optname, JSON::Value option){
|
||||
void Util::Config::addOption(std::string optname, JSON::Value option) {
|
||||
vals[optname] = option;
|
||||
if ( !vals[optname].isMember("value") && vals[optname].isMember("default")){
|
||||
if (!vals[optname].isMember("value") && vals[optname].isMember("default")) {
|
||||
vals[optname]["value"].append(vals[optname]["default"]);
|
||||
vals[optname].removeMember("default");
|
||||
}
|
||||
long_count = 0;
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
|
||||
if (it->second.isMember("long")){
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++) {
|
||||
if (it->second.isMember("long")) {
|
||||
long_count++;
|
||||
}
|
||||
if (it->second.isMember("long_off")){
|
||||
if (it->second.isMember("long_off")) {
|
||||
long_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a usage message to the given output.
|
||||
void Util::Config::printHelp(std::ostream & output){
|
||||
void Util::Config::printHelp(std::ostream & output) {
|
||||
unsigned int longest = 0;
|
||||
std::map<long long int, std::string> args;
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++) {
|
||||
unsigned int current = 0;
|
||||
if (it->second.isMember("long")){
|
||||
if (it->second.isMember("long")) {
|
||||
current += it->second["long"].asString().size() + 4;
|
||||
}
|
||||
if (it->second.isMember("short")){
|
||||
if (it->second.isMember("short")) {
|
||||
current += it->second["short"].asString().size() + 3;
|
||||
}
|
||||
if (current > longest){
|
||||
if (current > longest) {
|
||||
longest = current;
|
||||
}
|
||||
current = 0;
|
||||
if (it->second.isMember("long_off")){
|
||||
if (it->second.isMember("long_off")) {
|
||||
current += it->second["long_off"].asString().size() + 4;
|
||||
}
|
||||
if (it->second.isMember("short_off")){
|
||||
if (it->second.isMember("short_off")) {
|
||||
current += it->second["short_off"].asString().size() + 3;
|
||||
}
|
||||
if (current > longest){
|
||||
if (current > longest) {
|
||||
longest = current;
|
||||
}
|
||||
if (it->second.isMember("arg_num")){
|
||||
if (it->second.isMember("arg_num")) {
|
||||
current = it->first.size() + 3;
|
||||
if (current > longest){
|
||||
if (current > longest) {
|
||||
longest = current;
|
||||
}
|
||||
args[it->second["arg_num"].asInt()] = it->first;
|
||||
}
|
||||
}
|
||||
output << "Usage: " << getString("cmd") << " [options]";
|
||||
for (std::map<long long int, std::string>::iterator i = args.begin(); i != args.end(); i++){
|
||||
if (vals[i->second].isMember("value") && vals[i->second]["value"].size()){
|
||||
for (std::map<long long int, std::string>::iterator i = args.begin(); i != args.end(); i++) {
|
||||
if (vals[i->second].isMember("value") && vals[i->second]["value"].size()) {
|
||||
output << " [" << i->second << "]";
|
||||
}else{
|
||||
} else {
|
||||
output << " " << i->second;
|
||||
}
|
||||
}
|
||||
output << std::endl << std::endl;
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++) {
|
||||
std::string f;
|
||||
if (it->second.isMember("long") || it->second.isMember("short")){
|
||||
if (it->second.isMember("long") && it->second.isMember("short")){
|
||||
if (it->second.isMember("long") || it->second.isMember("short")) {
|
||||
if (it->second.isMember("long") && it->second.isMember("short")) {
|
||||
f = "--" + it->second["long"].asString() + ", -" + it->second["short"].asString();
|
||||
}else{
|
||||
if (it->second.isMember("long")){
|
||||
} else {
|
||||
if (it->second.isMember("long")) {
|
||||
f = "--" + it->second["long"].asString();
|
||||
}
|
||||
if (it->second.isMember("short")){
|
||||
if (it->second.isMember("short")) {
|
||||
f = "-" + it->second["short"].asString();
|
||||
}
|
||||
}
|
||||
while (f.size() < longest){
|
||||
while (f.size() < longest) {
|
||||
f.append(" ");
|
||||
}
|
||||
if (it->second.isMember("arg")){
|
||||
if (it->second.isMember("arg")) {
|
||||
output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl;
|
||||
}else{
|
||||
} else {
|
||||
output << f << it->second["help"].asString() << std::endl;
|
||||
}
|
||||
}
|
||||
if (it->second.isMember("long_off") || it->second.isMember("short_off")){
|
||||
if (it->second.isMember("long_off") && it->second.isMember("short_off")){
|
||||
if (it->second.isMember("long_off") || it->second.isMember("short_off")) {
|
||||
if (it->second.isMember("long_off") && it->second.isMember("short_off")) {
|
||||
f = "--" + it->second["long_off"].asString() + ", -" + it->second["short_off"].asString();
|
||||
}else{
|
||||
if (it->second.isMember("long_off")){
|
||||
} else {
|
||||
if (it->second.isMember("long_off")) {
|
||||
f = "--" + it->second["long_off"].asString();
|
||||
}
|
||||
if (it->second.isMember("short_off")){
|
||||
if (it->second.isMember("short_off")) {
|
||||
f = "-" + it->second["short_off"].asString();
|
||||
}
|
||||
}
|
||||
while (f.size() < longest){
|
||||
while (f.size() < longest) {
|
||||
f.append(" ");
|
||||
}
|
||||
if (it->second.isMember("arg")){
|
||||
if (it->second.isMember("arg")) {
|
||||
output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl;
|
||||
}else{
|
||||
} else {
|
||||
output << f << it->second["help"].asString() << std::endl;
|
||||
}
|
||||
}
|
||||
if (it->second.isMember("arg_num")){
|
||||
if (it->second.isMember("arg_num")) {
|
||||
f = it->first;
|
||||
while (f.size() < longest){
|
||||
while (f.size() < longest) {
|
||||
f.append(" ");
|
||||
}
|
||||
output << f << "(" << it->second["arg"].asString() << ") " << it->second["help"].asString() << std::endl;
|
||||
|
@ -197,51 +197,51 @@ void Util::Config::printHelp(std::ostream & output){
|
|||
|
||||
/// Parses commandline arguments.
|
||||
/// Calls exit if an unknown option is encountered, printing a help message.
|
||||
bool Util::Config::parseArgs(int & argc, char ** & argv){
|
||||
bool Util::Config::parseArgs(int & argc, char ** & argv) {
|
||||
int opt = 0;
|
||||
std::string shortopts;
|
||||
struct option * longOpts = (struct option*)calloc(long_count + 1, sizeof(struct option));
|
||||
struct option * longOpts = (struct option *)calloc(long_count + 1, sizeof(struct option));
|
||||
int long_i = 0;
|
||||
int arg_count = 0;
|
||||
if (vals.size()){
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
|
||||
if (it->second.isMember("short")){
|
||||
if (vals.size()) {
|
||||
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")){
|
||||
if (it->second.isMember("arg")) {
|
||||
shortopts += ":";
|
||||
}
|
||||
}
|
||||
if (it->second.isMember("short_off")){
|
||||
if (it->second.isMember("short_off")) {
|
||||
shortopts += it->second["short_off"].asString();
|
||||
if (it->second.isMember("arg")){
|
||||
if (it->second.isMember("arg")) {
|
||||
shortopts += ":";
|
||||
}
|
||||
}
|
||||
if (it->second.isMember("long")){
|
||||
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")){
|
||||
if (it->second.isMember("arg")) {
|
||||
longOpts[long_i].has_arg = 1;
|
||||
}
|
||||
long_i++;
|
||||
}
|
||||
if (it->second.isMember("long_off")){
|
||||
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")){
|
||||
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())){
|
||||
if (it->second["arg_num"].asInt() > arg_count){
|
||||
if (it->second.isMember("arg_num") && !(it->second.isMember("value") && it->second["value"].size())) {
|
||||
if (it->second["arg_num"].asInt() > arg_count) {
|
||||
arg_count = it->second["arg_num"].asInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((opt = getopt_long(argc, argv, shortopts.c_str(), longOpts, 0)) != -1){
|
||||
switch (opt){
|
||||
while ((opt = getopt_long(argc, argv, shortopts.c_str(), longOpts, 0)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
case '?':
|
||||
printHelp(std::cout);
|
||||
|
@ -251,16 +251,16 @@ bool Util::Config::parseArgs(int & argc, char ** & argv){
|
|||
exit(1);
|
||||
break;
|
||||
default:
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
|
||||
if (it->second.isMember("short") && it->second["short"].asString()[0] == opt){
|
||||
if (it->second.isMember("arg")){
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++) {
|
||||
if (it->second.isMember("short") && it->second["short"].asString()[0] == opt) {
|
||||
if (it->second.isMember("arg")) {
|
||||
it->second["value"].append((std::string)optarg);
|
||||
}else{
|
||||
} else {
|
||||
it->second["value"].append((long long int)1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (it->second.isMember("short_off") && it->second["short_off"].asString()[0] == opt){
|
||||
if (it->second.isMember("short_off") && it->second["short_off"].asString()[0] == opt) {
|
||||
it->second["value"].append((long long int)0);
|
||||
}
|
||||
}
|
||||
|
@ -269,9 +269,9 @@ bool Util::Config::parseArgs(int & argc, char ** & argv){
|
|||
} //commandline options parser
|
||||
free(longOpts); //free the long options array
|
||||
long_i = 1; //re-use long_i as an argument counter
|
||||
while (optind < argc){ //parse all remaining options, ignoring anything unexpected.
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++){
|
||||
if (it->second.isMember("arg_num") && it->second["arg_num"].asInt() == long_i){
|
||||
while (optind < argc) { //parse all remaining options, ignoring anything unexpected.
|
||||
for (JSON::ObjIter it = vals.ObjBegin(); it != vals.ObjEnd(); it++) {
|
||||
if (it->second.isMember("arg_num") && it->second["arg_num"].asInt() == long_i) {
|
||||
it->second["value"].append((std::string)argv[optind]);
|
||||
break;
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ bool Util::Config::parseArgs(int & argc, char ** & argv){
|
|||
optind++;
|
||||
long_i++;
|
||||
}
|
||||
if (long_i <= arg_count){
|
||||
if (long_i <= arg_count) {
|
||||
return false;
|
||||
}
|
||||
printDebugLevel = getInteger("debug");
|
||||
|
@ -288,17 +288,17 @@ bool Util::Config::parseArgs(int & argc, char ** & argv){
|
|||
|
||||
/// Returns a reference to the current value of an option or default if none was set.
|
||||
/// If the option does not exist, this exits the application with a return code of 37.
|
||||
JSON::Value & Util::Config::getOption(std::string optname, bool asArray){
|
||||
if ( !vals.isMember(optname)){
|
||||
JSON::Value & Util::Config::getOption(std::string optname, bool asArray) {
|
||||
if (!vals.isMember(optname)) {
|
||||
std::cout << "Fatal error: a non-existent option '" << optname << "' was accessed." << std::endl;
|
||||
exit(37);
|
||||
}
|
||||
if ( !vals[optname].isMember("value") || !vals[optname]["value"].isArray()){
|
||||
if (!vals[optname].isMember("value") || !vals[optname]["value"].isArray()) {
|
||||
vals[optname]["value"].append(JSON::Value());
|
||||
}
|
||||
if (asArray){
|
||||
if (asArray) {
|
||||
return vals[optname]["value"];
|
||||
}else{
|
||||
} else {
|
||||
int n = vals[optname]["value"].size();
|
||||
return vals[optname]["value"][n - 1];
|
||||
}
|
||||
|
@ -306,30 +306,30 @@ JSON::Value & Util::Config::getOption(std::string optname, bool asArray){
|
|||
|
||||
/// Returns the current value of an option or default if none was set as a string.
|
||||
/// Calls getOption internally.
|
||||
std::string Util::Config::getString(std::string optname){
|
||||
std::string Util::Config::getString(std::string optname) {
|
||||
return getOption(optname).asString();
|
||||
}
|
||||
|
||||
/// Returns the current value of an option or default if none was set as a long long int.
|
||||
/// Calls getOption internally.
|
||||
long long int Util::Config::getInteger(std::string optname){
|
||||
long long int Util::Config::getInteger(std::string optname) {
|
||||
return getOption(optname).asInt();
|
||||
}
|
||||
|
||||
/// Returns the current value of an option or default if none was set as a bool.
|
||||
/// Calls getOption internally.
|
||||
bool Util::Config::getBool(std::string optname){
|
||||
bool Util::Config::getBool(std::string optname) {
|
||||
return getOption(optname).asBool();
|
||||
}
|
||||
|
||||
struct callbackData{
|
||||
struct callbackData {
|
||||
Socket::Connection * sock;
|
||||
int (*cb)(Socket::Connection &);
|
||||
};
|
||||
|
||||
static void callThreadCallback(void * cDataArg){
|
||||
static void callThreadCallback(void * cDataArg) {
|
||||
DEBUG_MSG(DLVL_INSANE, "Thread for %p started", cDataArg);
|
||||
callbackData * cData = (callbackData*)cDataArg;
|
||||
callbackData * cData = (callbackData *)cDataArg;
|
||||
cData->cb(*(cData->sock));
|
||||
cData->sock->close();
|
||||
delete cData->sock;
|
||||
|
@ -337,19 +337,19 @@ static void callThreadCallback(void * cDataArg){
|
|||
DEBUG_MSG(DLVL_INSANE, "Thread for %p ended", cDataArg);
|
||||
}
|
||||
|
||||
int Util::Config::threadServer(Socket::Server & server_socket, int (*callback)(Socket::Connection &)){
|
||||
while (is_active && server_socket.connected()){
|
||||
int Util::Config::threadServer(Socket::Server & server_socket, int (*callback)(Socket::Connection &)) {
|
||||
while (is_active && server_socket.connected()) {
|
||||
Socket::Connection S = server_socket.accept();
|
||||
if (S.connected()){ //check if the new connection is valid
|
||||
if (S.connected()) { //check if the new connection is valid
|
||||
callbackData * cData = new callbackData;
|
||||
cData->sock = new Socket::Connection(S);
|
||||
cData->cb = callback;
|
||||
//spawn a new thread for this connection
|
||||
tthread::thread T(callThreadCallback, (void*)cData);
|
||||
tthread::thread T(callThreadCallback, (void *)cData);
|
||||
//detach it, no need to keep track of it anymore
|
||||
T.detach();
|
||||
DEBUG_MSG(DLVL_HIGH, "Spawned new thread for socket %i", S.getSocket());
|
||||
}else{
|
||||
} else {
|
||||
Util::sleep(10); //sleep 10ms
|
||||
}
|
||||
}
|
||||
|
@ -357,19 +357,19 @@ int Util::Config::threadServer(Socket::Server & server_socket, int (*callback)(S
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Util::Config::forkServer(Socket::Server & server_socket, int (*callback)(Socket::Connection &)){
|
||||
while (is_active && server_socket.connected()){
|
||||
int Util::Config::forkServer(Socket::Server & server_socket, int (*callback)(Socket::Connection &)) {
|
||||
while (is_active && server_socket.connected()) {
|
||||
Socket::Connection S = server_socket.accept();
|
||||
if (S.connected()){ //check if the new connection is valid
|
||||
if (S.connected()) { //check if the new connection is valid
|
||||
pid_t myid = fork();
|
||||
if (myid == 0){ //if new child, start MAINHANDLER
|
||||
if (myid == 0) { //if new child, start MAINHANDLER
|
||||
server_socket.drop();
|
||||
return callback(S);
|
||||
}else{ //otherwise, do nothing or output debugging text
|
||||
} else { //otherwise, do nothing or output debugging text
|
||||
DEBUG_MSG(DLVL_HIGH, "Forked new process %i for socket %i", (int)myid, S.getSocket());
|
||||
S.drop();
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
Util::sleep(10); //sleep 10ms
|
||||
}
|
||||
}
|
||||
|
@ -377,15 +377,15 @@ int Util::Config::forkServer(Socket::Server & server_socket, int (*callback)(Soc
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
|
||||
int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)) {
|
||||
Socket::Server server_socket;
|
||||
if (vals.isMember("socket")){
|
||||
if (vals.isMember("socket")) {
|
||||
server_socket = Socket::Server(Util::getTmpFolder() + getString("socket"));
|
||||
}
|
||||
if (vals.isMember("listen_port") && vals.isMember("listen_interface")){
|
||||
if (vals.isMember("listen_port") && vals.isMember("listen_interface")) {
|
||||
server_socket = Socket::Server(getInteger("listen_port"), getString("listen_interface"), false);
|
||||
}
|
||||
if (!server_socket.connected()){
|
||||
if (!server_socket.connected()) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "Failure to open socket");
|
||||
return 1;
|
||||
}
|
||||
|
@ -394,15 +394,15 @@ int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
|
|||
return threadServer(server_socket, callback);
|
||||
}
|
||||
|
||||
int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection & S)){
|
||||
int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection & S)) {
|
||||
Socket::Server server_socket;
|
||||
if (vals.isMember("socket")){
|
||||
if (vals.isMember("socket")) {
|
||||
server_socket = Socket::Server(Util::getTmpFolder() + getString("socket"));
|
||||
}
|
||||
if (vals.isMember("listen_port") && vals.isMember("listen_interface")){
|
||||
if (vals.isMember("listen_port") && vals.isMember("listen_interface")) {
|
||||
server_socket = Socket::Server(getInteger("listen_port"), getString("listen_interface"), false);
|
||||
}
|
||||
if (!server_socket.connected()){
|
||||
if (!server_socket.connected()) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "Failure to open socket");
|
||||
return 1;
|
||||
}
|
||||
|
@ -416,21 +416,21 @@ int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection & S)){
|
|||
/// - Daemonize the process if "daemonize" exists and is true.
|
||||
/// - Set is_active to true.
|
||||
/// - Set up a signal handler to set is_active to false for the SIGINT, SIGHUP and SIGTERM signals.
|
||||
void Util::Config::activate(){
|
||||
if (vals.isMember("username")){
|
||||
void Util::Config::activate() {
|
||||
if (vals.isMember("username")) {
|
||||
setUser(getString("username"));
|
||||
}
|
||||
if (vals.isMember("daemonize") && getBool("daemonize")){
|
||||
if(vals.isMember("logfile") && getString("logfile") != ""){
|
||||
if (vals.isMember("daemonize") && getBool("daemonize")) {
|
||||
if (vals.isMember("logfile") && getString("logfile") != "") {
|
||||
Daemonize(true);
|
||||
}else{
|
||||
} else {
|
||||
Daemonize(false);
|
||||
}
|
||||
}
|
||||
struct sigaction new_action;
|
||||
struct sigaction cur_action;
|
||||
new_action.sa_handler = signal_handler;
|
||||
sigemptyset( &new_action.sa_mask);
|
||||
sigemptyset(&new_action.sa_mask);
|
||||
new_action.sa_flags = 0;
|
||||
sigaction(SIGINT, &new_action, NULL);
|
||||
sigaction(SIGHUP, &new_action, NULL);
|
||||
|
@ -438,8 +438,8 @@ void Util::Config::activate(){
|
|||
sigaction(SIGPIPE, &new_action, NULL);
|
||||
//check if a child signal handler isn't set already, if so, set it.
|
||||
sigaction(SIGCHLD, 0, &cur_action);
|
||||
if (cur_action.sa_handler == SIG_DFL || cur_action.sa_handler == SIG_IGN){
|
||||
sigaction(SIGCHLD, &new_action, NULL);
|
||||
if (cur_action.sa_handler == SIG_DFL || cur_action.sa_handler == SIG_IGN) {
|
||||
sigaction(SIGCHLD, &new_action, NULL);
|
||||
}
|
||||
is_active = true;
|
||||
}
|
||||
|
@ -447,24 +447,24 @@ void Util::Config::activate(){
|
|||
/// Basic signal handler. Sets is_active to false if it receives
|
||||
/// a SIGINT, SIGHUP or SIGTERM signal, reaps children for the SIGCHLD
|
||||
/// signal, and ignores all other signals.
|
||||
void Util::Config::signal_handler(int signum){
|
||||
switch (signum){
|
||||
void Util::Config::signal_handler(int signum) {
|
||||
switch (signum) {
|
||||
case SIGINT: //these three signals will set is_active to false.
|
||||
case SIGHUP:
|
||||
case SIGTERM:
|
||||
is_active = false;
|
||||
break;
|
||||
case SIGCHLD:{ //when a child dies, reap it.
|
||||
int status;
|
||||
pid_t ret = -1;
|
||||
while (ret != 0){
|
||||
ret = waitpid( -1, &status, WNOHANG);
|
||||
if (ret < 0 && errno != EINTR){
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIGCHLD: { //when a child dies, reap it.
|
||||
int status;
|
||||
pid_t ret = -1;
|
||||
while (ret != 0) {
|
||||
ret = waitpid(-1, &status, WNOHANG);
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: //other signals are ignored
|
||||
break;
|
||||
}
|
||||
|
@ -472,7 +472,7 @@ void Util::Config::signal_handler(int signum){
|
|||
|
||||
/// Adds the default connector options. Also updates the capabilities structure with the default options.
|
||||
/// Besides the options addBasicConnectorOptions adds, this function also adds port and interface options.
|
||||
void Util::Config::addConnectorOptions(int port, JSON::Value & capabilities){
|
||||
void Util::Config::addConnectorOptions(int port, JSON::Value & capabilities) {
|
||||
JSON::Value option;
|
||||
option.null();
|
||||
option["long"] = "port";
|
||||
|
@ -482,11 +482,11 @@ void Util::Config::addConnectorOptions(int port, JSON::Value & capabilities){
|
|||
option["value"].append((long long)port);
|
||||
addOption("listen_port", option);
|
||||
capabilities["optional"]["port"]["name"] = "TCP port";
|
||||
capabilities["optional"]["port"]["help"] = "TCP port to listen on - default if unprovided is "+option["value"][0u].asString();
|
||||
capabilities["optional"]["port"]["help"] = "TCP port to listen on - default if unprovided is " + option["value"][0u].asString();
|
||||
capabilities["optional"]["port"]["type"] = "uint";
|
||||
capabilities["optional"]["port"]["option"] = "--port";
|
||||
capabilities["optional"]["port"]["default"] = option["value"][0u];
|
||||
|
||||
|
||||
option.null();
|
||||
option["long"] = "interface";
|
||||
option["short"] = "i";
|
||||
|
@ -498,12 +498,12 @@ void Util::Config::addConnectorOptions(int port, JSON::Value & capabilities){
|
|||
capabilities["optional"]["interface"]["help"] = "Address of the interface to listen on - default if unprovided is all interfaces";
|
||||
capabilities["optional"]["interface"]["option"] = "--interface";
|
||||
capabilities["optional"]["interface"]["type"] = "str";
|
||||
|
||||
|
||||
addBasicConnectorOptions(capabilities);
|
||||
} //addConnectorOptions
|
||||
|
||||
/// Adds the default connector options. Also updates the capabilities structure with the default options.
|
||||
void Util::Config::addBasicConnectorOptions(JSON::Value & capabilities){
|
||||
void Util::Config::addBasicConnectorOptions(JSON::Value & capabilities) {
|
||||
JSON::Value option;
|
||||
option.null();
|
||||
option["long"] = "username";
|
||||
|
@ -518,7 +518,7 @@ void Util::Config::addBasicConnectorOptions(JSON::Value & capabilities){
|
|||
capabilities["optional"]["username"]["type"] = "str";
|
||||
|
||||
|
||||
if (capabilities.isMember("socket")){
|
||||
if (capabilities.isMember("socket")) {
|
||||
option.null();
|
||||
option["arg"] = "string";
|
||||
option["help"] = "Socket name that can be connected to for this connector.";
|
||||
|
@ -534,7 +534,7 @@ void Util::Config::addBasicConnectorOptions(JSON::Value & capabilities){
|
|||
option["help"] = "Whether or not to daemonize the process after starting.";
|
||||
option["value"].append(0ll);
|
||||
addOption("daemonize", option);
|
||||
|
||||
|
||||
option.null();
|
||||
option["long"] = "json";
|
||||
option["short"] = "j";
|
||||
|
@ -546,29 +546,29 @@ void Util::Config::addBasicConnectorOptions(JSON::Value & capabilities){
|
|||
|
||||
|
||||
/// Gets directory the current executable is stored in.
|
||||
std::string Util::getMyPath(){
|
||||
std::string Util::getMyPath() {
|
||||
char mypath[500];
|
||||
#ifdef __CYGWIN__
|
||||
#ifdef __CYGWIN__
|
||||
GetModuleFileName(0, mypath, 500);
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
memset( mypath, 0, 500);
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
memset(mypath, 0, 500);
|
||||
unsigned int refSize = 500;
|
||||
int ret = _NSGetExecutablePath(mypath,&refSize);
|
||||
#else
|
||||
int ret = _NSGetExecutablePath(mypath, &refSize);
|
||||
#else
|
||||
int ret = readlink("/proc/self/exe", mypath, 500);
|
||||
if (ret != -1){
|
||||
if (ret != -1) {
|
||||
mypath[ret] = 0;
|
||||
}else{
|
||||
} else {
|
||||
mypath[0] = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
std::string tPath = mypath;
|
||||
size_t slash = tPath.rfind('/');
|
||||
if (slash == std::string::npos){
|
||||
if (slash == std::string::npos) {
|
||||
slash = tPath.rfind('\\');
|
||||
if (slash == std::string::npos){
|
||||
if (slash == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -577,46 +577,48 @@ std::string Util::getMyPath(){
|
|||
}
|
||||
|
||||
/// Gets all executables in getMyPath that start with "Mist".
|
||||
void Util::getMyExec(std::deque<std::string> & execs){
|
||||
void Util::getMyExec(std::deque<std::string> & execs) {
|
||||
std::string path = Util::getMyPath();
|
||||
#ifdef __CYGWIN__
|
||||
#ifdef __CYGWIN__
|
||||
path += "\\Mist*";
|
||||
WIN32_FIND_DATA FindFileData;
|
||||
HANDLE hdl = FindFirstFile(path.c_str(), &FindFileData);
|
||||
while (hdl != INVALID_HANDLE_VALUE){
|
||||
while (hdl != INVALID_HANDLE_VALUE) {
|
||||
execs.push_back(FindFileData.cFileName);
|
||||
if (!FindNextFile(hdl, &FindFileData)){
|
||||
if (!FindNextFile(hdl, &FindFileData)) {
|
||||
FindClose(hdl);
|
||||
hdl = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#else
|
||||
DIR * d = opendir(path.c_str());
|
||||
if (!d){return;}
|
||||
struct dirent *dp;
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
struct dirent * dp;
|
||||
do {
|
||||
errno = 0;
|
||||
if ((dp = readdir(d))){
|
||||
if (strncmp(dp->d_name, "Mist", 4) == 0){
|
||||
if ((dp = readdir(d))) {
|
||||
if (strncmp(dp->d_name, "Mist", 4) == 0) {
|
||||
execs.push_back(dp->d_name);
|
||||
}
|
||||
}
|
||||
} while (dp != NULL);
|
||||
closedir(d);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Sets the current process' running user
|
||||
void Util::setUser(std::string username){
|
||||
if (username != "root"){
|
||||
void Util::setUser(std::string username) {
|
||||
if (username != "root") {
|
||||
struct passwd * user_info = getpwnam(username.c_str());
|
||||
if ( !user_info){
|
||||
if (!user_info) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Error: could not setuid %s: could not get PID", username.c_str());
|
||||
return;
|
||||
}else{
|
||||
if (setuid(user_info->pw_uid) != 0){
|
||||
} else {
|
||||
if (setuid(user_info->pw_uid) != 0) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Error: could not setuid %s: not allowed", username.c_str());
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_DEVEL, "Change user to %s", username.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -627,13 +629,13 @@ void Util::setUser(std::string username){
|
|||
/// Works by calling daemon(1,0):
|
||||
/// Does not change directory to root.
|
||||
/// Does redirect output to /dev/null
|
||||
void Util::Daemonize(bool notClose){
|
||||
void Util::Daemonize(bool notClose) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "Going into background mode...");
|
||||
int noClose = 0;
|
||||
if(notClose){
|
||||
if (notClose) {
|
||||
noClose = 1;
|
||||
}
|
||||
if (daemon(1, noClose) < 0){
|
||||
if (daemon(1, noClose) < 0) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Failed to daemonize: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
namespace Util {
|
||||
|
||||
/// Deals with parsing configuration from commandline options.
|
||||
class Config{
|
||||
class Config {
|
||||
private:
|
||||
JSON::Value vals; ///< Holds all current config values
|
||||
int long_count;
|
||||
|
@ -49,7 +49,7 @@ namespace Util {
|
|||
|
||||
/// Gets all executables in getMyPath that start with "Mist".
|
||||
void getMyExec(std::deque<std::string> & execs);
|
||||
|
||||
|
||||
/// Will set the active user to the named username.
|
||||
void setUser(std::string user);
|
||||
|
||||
|
|
|
@ -11,62 +11,64 @@
|
|||
#include "config.h"
|
||||
|
||||
namespace Converter {
|
||||
|
||||
|
||||
///\brief The base constructor
|
||||
Converter::Converter(){
|
||||
Converter::Converter() {
|
||||
fillFFMpegEncoders();
|
||||
}
|
||||
|
||||
|
||||
///\brief A function that fill the internal variables with values provided by examing ffmpeg output
|
||||
///
|
||||
///Checks for the following encoders:
|
||||
/// - AAC
|
||||
/// - H264
|
||||
/// - MP3
|
||||
void Converter::fillFFMpegEncoders(){
|
||||
std::vector<char*> cmd;
|
||||
void Converter::fillFFMpegEncoders() {
|
||||
std::vector<char *> cmd;
|
||||
cmd.reserve(3);
|
||||
cmd.push_back((char*)"ffmpeg");
|
||||
cmd.push_back((char*)"-encoders");
|
||||
cmd.push_back((char *)"ffmpeg");
|
||||
cmd.push_back((char *)"-encoders");
|
||||
cmd.push_back(NULL);
|
||||
int outFD = -1;
|
||||
Util::Procs::StartPiped("FFMpegInfo", &cmd[0], 0, &outFD, 0);
|
||||
while( Util::Procs::isActive("FFMpegInfo")){ Util::sleep(100); }
|
||||
FILE * outFile = fdopen( outFD, "r" );
|
||||
while (Util::Procs::isActive("FFMpegInfo")) {
|
||||
Util::sleep(100);
|
||||
}
|
||||
FILE * outFile = fdopen(outFD, "r");
|
||||
char * fileBuf = 0;
|
||||
size_t fileBufLen = 0;
|
||||
while ( !(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){
|
||||
if (strstr(fileBuf, "aac") || strstr(fileBuf, "AAC")){
|
||||
while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)) {
|
||||
if (strstr(fileBuf, "aac") || strstr(fileBuf, "AAC")) {
|
||||
strtok(fileBuf, " \t");
|
||||
allCodecs["ffmpeg"][strtok(NULL, " \t")] = "aac";
|
||||
}
|
||||
if (strstr(fileBuf, "h264") || strstr(fileBuf, "H264")){
|
||||
if (strstr(fileBuf, "h264") || strstr(fileBuf, "H264")) {
|
||||
strtok(fileBuf, " \t");
|
||||
allCodecs["ffmpeg"][strtok(NULL, " \t")] = "h264";
|
||||
}
|
||||
if (strstr(fileBuf, "mp3") || strstr(fileBuf, "MP3")){
|
||||
if (strstr(fileBuf, "mp3") || strstr(fileBuf, "MP3")) {
|
||||
strtok(fileBuf, " \t");
|
||||
allCodecs["ffmpeg"][strtok(NULL, " \t")] = "mp3";
|
||||
}
|
||||
}
|
||||
fclose( outFile );
|
||||
fclose(outFile);
|
||||
}
|
||||
|
||||
|
||||
///\brief A function to obtain all available codecs that have been obtained from the encoders.
|
||||
///\return A reference to the allCodecs member.
|
||||
converterInfo & Converter::getCodecs(){
|
||||
converterInfo & Converter::getCodecs() {
|
||||
return allCodecs;
|
||||
}
|
||||
|
||||
///\brief A function to obtain the available encoders in JSON format.
|
||||
///\return A JSON::Value containing all encoder:codec pairs.
|
||||
JSON::Value Converter::getEncoders(){
|
||||
JSON::Value Converter::getEncoders() {
|
||||
JSON::Value result;
|
||||
for (converterInfo::iterator convIt = allCodecs.begin(); convIt != allCodecs.end(); convIt++){
|
||||
for (codecInfo::iterator codIt = convIt->second.begin(); codIt != convIt->second.end(); codIt++){
|
||||
if (codIt->second == "h264"){
|
||||
for (converterInfo::iterator convIt = allCodecs.begin(); convIt != allCodecs.end(); convIt++) {
|
||||
for (codecInfo::iterator codIt = convIt->second.begin(); codIt != convIt->second.end(); codIt++) {
|
||||
if (codIt->second == "h264") {
|
||||
result[convIt->first]["video"][codIt->first] = codIt->second;
|
||||
}else{
|
||||
} else {
|
||||
result[convIt->first]["audio"][codIt->first] = codIt->second;
|
||||
|
||||
}
|
||||
|
@ -74,30 +76,30 @@ namespace Converter {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///\brief Looks in a given path for all files that could be converted
|
||||
///\param myPath The location to look at, this should be a folder.
|
||||
///\return A JSON::Value containing all media files in the location, with their corresponding metadata values.
|
||||
JSON::Value Converter::queryPath(std::string myPath){
|
||||
JSON::Value Converter::queryPath(std::string myPath) {
|
||||
char const * cmd[3] = {0, 0, 0};
|
||||
std::string mistPath = Util::getMyPath() + "MistInfo";
|
||||
cmd[0] = mistPath.c_str();
|
||||
JSON::Value result;
|
||||
DIR * Dirp = opendir(myPath.c_str());
|
||||
struct stat StatBuf;
|
||||
if (Dirp){
|
||||
if (Dirp) {
|
||||
dirent * entry;
|
||||
while ((entry = readdir(Dirp))){
|
||||
if (stat(std::string(myPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){
|
||||
while ((entry = readdir(Dirp))) {
|
||||
if (stat(std::string(myPath + "/" + entry->d_name).c_str(), &StatBuf) == -1) {
|
||||
continue;
|
||||
}
|
||||
if ((StatBuf.st_mode & S_IFREG) == 0){
|
||||
if ((StatBuf.st_mode & S_IFREG) == 0) {
|
||||
continue;
|
||||
}
|
||||
std::string fileName = entry->d_name;
|
||||
std::string mijnPad = std::string(myPath + (myPath[myPath.size()-1] == '/' ? "" : "/") + entry->d_name);
|
||||
std::string mijnPad = std::string(myPath + (myPath[myPath.size() - 1] == '/' ? "" : "/") + entry->d_name);
|
||||
cmd[1] = mijnPad.c_str();
|
||||
result[fileName] = JSON::fromString(Util::Procs::getOutputOf((char* const*)cmd));
|
||||
result[fileName] = JSON::fromString(Util::Procs::getOutputOf((char * const *)cmd));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -118,11 +120,11 @@ namespace Converter {
|
|||
/// - codec The codec to encode audio in, or copy to use the current codec
|
||||
/// - samplerate The target samplerate for the audio, in hz
|
||||
void Converter::startConversion(std::string name, JSON::Value parameters) {
|
||||
if ( !parameters.isMember("input")){
|
||||
if (!parameters.isMember("input")) {
|
||||
statusHistory[name] = "No input file supplied";
|
||||
return;
|
||||
}
|
||||
if ( !parameters.isMember("output")){
|
||||
if (!parameters.isMember("output")) {
|
||||
statusHistory[name] = "No output file supplied";
|
||||
return;
|
||||
}
|
||||
|
@ -130,81 +132,81 @@ namespace Converter {
|
|||
std::string outPath = parameters["output"].asString();
|
||||
outPath = outPath.substr(0, outPath.rfind('/'));
|
||||
int statRes = stat(outPath.c_str(), & statBuf);
|
||||
if (statRes == -1 || !S_ISDIR(statBuf.st_mode)){
|
||||
if (statRes == -1 || !S_ISDIR(statBuf.st_mode)) {
|
||||
statusHistory[name] = "Output path is either non-existent, or not a path.";
|
||||
return;
|
||||
}
|
||||
if ( !parameters.isMember("encoder")){
|
||||
if (!parameters.isMember("encoder")) {
|
||||
statusHistory[name] = "No encoder specified";
|
||||
return;
|
||||
}
|
||||
if (allCodecs.find(parameters["encoder"]) == allCodecs.end()){
|
||||
if (allCodecs.find(parameters["encoder"]) == allCodecs.end()) {
|
||||
statusHistory[name] = "Can not find encoder " + parameters["encoder"].asString();
|
||||
return;
|
||||
}
|
||||
if (parameters.isMember("video")){
|
||||
if (parameters["video"].isMember("width") && !parameters["video"].isMember("height")){
|
||||
if (parameters.isMember("video")) {
|
||||
if (parameters["video"].isMember("width") && !parameters["video"].isMember("height")) {
|
||||
statusHistory[name] = "No height parameter given";
|
||||
return;
|
||||
}
|
||||
if (parameters["video"].isMember("height") && !parameters["video"].isMember("width")){
|
||||
if (parameters["video"].isMember("height") && !parameters["video"].isMember("width")) {
|
||||
statusHistory[name] = "No width parameter given";
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::stringstream encoderCommand;
|
||||
if (parameters["encoder"] == "ffmpeg"){
|
||||
if (parameters["encoder"] == "ffmpeg") {
|
||||
encoderCommand << "ffmpeg -i ";
|
||||
encoderCommand << parameters["input"].asString() << " ";
|
||||
if (parameters.isMember("video")){
|
||||
if ( !parameters["video"].isMember("codec") || parameters["video"]["codec"] == "copy"){
|
||||
if (parameters.isMember("video")) {
|
||||
if (!parameters["video"].isMember("codec") || parameters["video"]["codec"] == "copy") {
|
||||
encoderCommand << "-vcodec copy ";
|
||||
}else{
|
||||
} else {
|
||||
codecInfo::iterator vidCodec = allCodecs["ffmpeg"].find(parameters["video"]["codec"]);
|
||||
if (vidCodec == allCodecs["ffmpeg"].end()){
|
||||
if (vidCodec == allCodecs["ffmpeg"].end()) {
|
||||
statusHistory[name] = "Can not find video codec " + parameters["video"]["codec"].asString();
|
||||
return;
|
||||
}
|
||||
encoderCommand << "-vcodec " << vidCodec->first << " ";
|
||||
if (parameters["video"]["codec"].asString() == "h264"){
|
||||
if (parameters["video"]["codec"].asString() == "h264") {
|
||||
//Enforce baseline
|
||||
encoderCommand << "-preset slow -profile:v baseline -level 30 ";
|
||||
encoderCommand << "-preset slow -profile:v baseline -level 30 ";
|
||||
}
|
||||
if (parameters["video"].isMember("fpks")){
|
||||
encoderCommand << "-r " << parameters["video"]["fpks"].asInt() / 1000 << " ";
|
||||
if (parameters["video"].isMember("fpks")) {
|
||||
encoderCommand << "-r " << parameters["video"]["fpks"].asInt() / 1000 << " ";
|
||||
}
|
||||
if (parameters["video"].isMember("width")){
|
||||
if (parameters["video"].isMember("width")) {
|
||||
encoderCommand << "-s " << parameters["video"]["width"].asInt() << "x" << parameters["video"]["height"].asInt() << " ";
|
||||
}
|
||||
///\todo Keyframe interval (different in older and newer versions of ffmpeg?)
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
encoderCommand << "-vn ";
|
||||
}
|
||||
if (parameters.isMember("audio")){
|
||||
if ( !parameters["audio"].isMember("codec")){
|
||||
if (parameters.isMember("audio")) {
|
||||
if (!parameters["audio"].isMember("codec")) {
|
||||
encoderCommand << "-acodec copy ";
|
||||
}else{
|
||||
} else {
|
||||
codecInfo::iterator audCodec = allCodecs["ffmpeg"].find(parameters["audio"]["codec"]);
|
||||
if (audCodec == allCodecs["ffmpeg"].end()){
|
||||
if (audCodec == allCodecs["ffmpeg"].end()) {
|
||||
statusHistory[name] = "Can not find audio codec " + parameters["audio"]["codec"].asString();
|
||||
return;
|
||||
}
|
||||
if (audCodec->second == "aac"){
|
||||
if (audCodec->second == "aac") {
|
||||
encoderCommand << "-strict -2 ";
|
||||
}
|
||||
encoderCommand << "-acodec " << audCodec->first << " ";
|
||||
if (parameters["audio"].isMember("samplerate")){
|
||||
if (parameters["audio"].isMember("samplerate")) {
|
||||
encoderCommand << "-ar " << parameters["audio"]["samplerate"].asInt() << " ";
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
encoderCommand << "-an ";
|
||||
}
|
||||
encoderCommand << "-f flv -";
|
||||
}
|
||||
int statusFD = -1;
|
||||
Util::Procs::StartPiped2(name,encoderCommand.str(),Util::getMyPath() + "MistFLV2DTSC -o " + parameters["output"].asString(),0,0,&statusFD,0);
|
||||
Util::Procs::StartPiped2(name, encoderCommand.str(), Util::getMyPath() + "MistFLV2DTSC -o " + parameters["output"].asString(), 0, 0, &statusFD, 0);
|
||||
parameters["statusFD"] = statusFD;
|
||||
allConversions[name] = parameters;
|
||||
allConversions[name]["status"]["duration"] = "?";
|
||||
|
@ -212,53 +214,53 @@ namespace Converter {
|
|||
allConversions[name]["status"]["frame"] = 0;
|
||||
allConversions[name]["status"]["time"] = 0;
|
||||
}
|
||||
|
||||
|
||||
///\brief Updates the internal status of the converter class.
|
||||
///
|
||||
///Will check for each running conversion whether it is still running, and update its status accordingly
|
||||
void Converter::updateStatus(){
|
||||
if (allConversions.size()){
|
||||
std::map<std::string,JSON::Value>::iterator cIt;
|
||||
void Converter::updateStatus() {
|
||||
if (allConversions.size()) {
|
||||
std::map<std::string, JSON::Value>::iterator cIt;
|
||||
bool hasChanged = true;
|
||||
while (hasChanged && allConversions.size()){
|
||||
while (hasChanged && allConversions.size()) {
|
||||
hasChanged = false;
|
||||
for (cIt = allConversions.begin(); cIt != allConversions.end(); cIt++){
|
||||
if (Util::Procs::isActive(cIt->first)){
|
||||
for (cIt = allConversions.begin(); cIt != allConversions.end(); cIt++) {
|
||||
if (Util::Procs::isActive(cIt->first)) {
|
||||
int statusFD = dup(cIt->second["statusFD"].asInt());
|
||||
fsync( statusFD );
|
||||
FILE* statusFile = fdopen( statusFD, "r" );
|
||||
fsync(statusFD);
|
||||
FILE * statusFile = fdopen(statusFD, "r");
|
||||
char * fileBuf = 0;
|
||||
size_t fileBufLen = 0;
|
||||
fseek(statusFile,0,SEEK_END);
|
||||
fseek(statusFile, 0, SEEK_END);
|
||||
std::string line;
|
||||
int totalTime = 0;
|
||||
do{
|
||||
do {
|
||||
getdelim(&fileBuf, &fileBufLen, '\r', statusFile);
|
||||
line = fileBuf;
|
||||
if (line.find("Duration") != std::string::npos){
|
||||
if (line.find("Duration") != std::string::npos) {
|
||||
int curOffset = line.find("Duration: ") + 10;
|
||||
totalTime += atoi(line.substr(curOffset, 2).c_str()) * 60 * 60 * 1000;
|
||||
totalTime += atoi(line.substr(curOffset+3, 2).c_str()) * 60 * 1000;
|
||||
totalTime += atoi(line.substr(curOffset+6, 2).c_str()) *1000;
|
||||
totalTime += atoi(line.substr(curOffset+9, 2).c_str()) * 10;
|
||||
totalTime += atoi(line.substr(curOffset + 3, 2).c_str()) * 60 * 1000;
|
||||
totalTime += atoi(line.substr(curOffset + 6, 2).c_str()) * 1000;
|
||||
totalTime += atoi(line.substr(curOffset + 9, 2).c_str()) * 10;
|
||||
cIt->second["duration"] = totalTime;
|
||||
}
|
||||
}while ( !feof(statusFile) && line.find("frame") != 0);//"frame" is the fist word on an actual status line of ffmpeg
|
||||
if ( !feof(statusFile)){
|
||||
cIt->second["status"] = parseFFMpegStatus( line );
|
||||
} while (!feof(statusFile) && line.find("frame") != 0); //"frame" is the fist word on an actual status line of ffmpeg
|
||||
if (!feof(statusFile)) {
|
||||
cIt->second["status"] = parseFFMpegStatus(line);
|
||||
cIt->second["status"]["duration"] = cIt->second["duration"];
|
||||
cIt->second["status"]["progress"] = (cIt->second["status"]["time"].asInt() * 100) / cIt->second["duration"].asInt();
|
||||
}else{
|
||||
line.erase(line.end()-1);
|
||||
line = line.substr( line.rfind("\n") + 1 );
|
||||
} else {
|
||||
line.erase(line.end() - 1);
|
||||
line = line.substr(line.rfind("\n") + 1);
|
||||
cIt->second["status"] = line;
|
||||
}
|
||||
free(fileBuf);
|
||||
fclose(statusFile);
|
||||
}else{
|
||||
if (statusHistory.find( cIt->first ) == statusHistory.end()){
|
||||
} else {
|
||||
if (statusHistory.find(cIt->first) == statusHistory.end()) {
|
||||
statusHistory[cIt->first] = "Conversion successful, running DTSCFix";
|
||||
Util::Procs::Start(cIt->first+"DTSCFix",Util::getMyPath() + "MistDTSCFix " + cIt->second["output"].asString());
|
||||
Util::Procs::Start(cIt->first + "DTSCFix", Util::getMyPath() + "MistDTSCFix " + cIt->second["output"].asString());
|
||||
}
|
||||
allConversions.erase(cIt);
|
||||
hasChanged = true;
|
||||
|
@ -267,11 +269,11 @@ namespace Converter {
|
|||
}
|
||||
}
|
||||
}
|
||||
if(statusHistory.size()){
|
||||
std::map<std::string,std::string>::iterator sIt;
|
||||
for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++){
|
||||
if (statusHistory[sIt->first].find("DTSCFix") != std::string::npos){
|
||||
if (Util::Procs::isActive(sIt->first+"DTSCFIX")){
|
||||
if (statusHistory.size()) {
|
||||
std::map<std::string, std::string>::iterator sIt;
|
||||
for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++) {
|
||||
if (statusHistory[sIt->first].find("DTSCFix") != std::string::npos) {
|
||||
if (Util::Procs::isActive(sIt->first + "DTSCFIX")) {
|
||||
continue;
|
||||
}
|
||||
statusHistory[sIt->first] = "Conversion successful";
|
||||
|
@ -279,48 +281,48 @@ namespace Converter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///\brief Parses a single ffmpeg status line into a JSON format
|
||||
///\param statusLine The current status of ffmpeg
|
||||
///\return A JSON::Value with the following values set:
|
||||
/// - frame The current last encoded frame
|
||||
/// - time The current last encoded timestamp
|
||||
JSON::Value Converter::parseFFMpegStatus(std::string statusLine){
|
||||
JSON::Value Converter::parseFFMpegStatus(std::string statusLine) {
|
||||
JSON::Value result;
|
||||
int curOffset = statusLine.find("frame=") + 6;
|
||||
result["frame"] = atoi(statusLine.substr(curOffset, statusLine.find("fps=") - curOffset).c_str() );
|
||||
result["frame"] = atoi(statusLine.substr(curOffset, statusLine.find("fps=") - curOffset).c_str());
|
||||
curOffset = statusLine.find("time=") + 5;
|
||||
int myTime = 0;
|
||||
myTime += atoi(statusLine.substr(curOffset, 2).c_str()) * 60 * 60 * 1000;
|
||||
myTime += atoi(statusLine.substr(curOffset+3, 2).c_str()) * 60 * 1000;
|
||||
myTime += atoi(statusLine.substr(curOffset+6, 2).c_str()) *1000;
|
||||
myTime += atoi(statusLine.substr(curOffset+9, 2).c_str()) * 10;
|
||||
myTime += atoi(statusLine.substr(curOffset + 3, 2).c_str()) * 60 * 1000;
|
||||
myTime += atoi(statusLine.substr(curOffset + 6, 2).c_str()) * 1000;
|
||||
myTime += atoi(statusLine.substr(curOffset + 9, 2).c_str()) * 10;
|
||||
result["time"] = myTime;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///\brief Obtain the current internal status of the conversion class
|
||||
///\return A JSON::Value with the status of each conversion
|
||||
JSON::Value Converter::getStatus(){
|
||||
JSON::Value Converter::getStatus() {
|
||||
updateStatus();
|
||||
JSON::Value result;
|
||||
if (allConversions.size()){
|
||||
for (std::map<std::string,JSON::Value>::iterator cIt = allConversions.begin(); cIt != allConversions.end(); cIt++){
|
||||
if (allConversions.size()) {
|
||||
for (std::map<std::string, JSON::Value>::iterator cIt = allConversions.begin(); cIt != allConversions.end(); cIt++) {
|
||||
result[cIt->first] = cIt->second["status"];
|
||||
result[cIt->first]["details"] = cIt->second;
|
||||
}
|
||||
}
|
||||
if (statusHistory.size()){
|
||||
std::map<std::string,std::string>::iterator sIt;
|
||||
for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++){
|
||||
if (statusHistory.size()) {
|
||||
std::map<std::string, std::string>::iterator sIt;
|
||||
for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++) {
|
||||
result[sIt->first] = sIt->second;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///\brief Clears the status history of all conversions
|
||||
void Converter::clearStatus(){
|
||||
void Converter::clearStatus() {
|
||||
statusHistory.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
#include "json.h"
|
||||
|
||||
///\brief A typedef to simplify accessing all codecs
|
||||
typedef std::map<std::string,std::string> codecInfo;
|
||||
typedef std::map<std::string, std::string> codecInfo;
|
||||
///\brief A typedef to simplify accessing all encoders
|
||||
typedef std::map<std::string,codecInfo> converterInfo;
|
||||
typedef std::map<std::string, codecInfo> converterInfo;
|
||||
|
||||
///\brief A namespace containing all functions for handling the conversion API
|
||||
namespace Converter {
|
||||
|
@ -28,8 +28,8 @@ namespace Converter {
|
|||
///\brief Holds a list of all current known codecs
|
||||
converterInfo allCodecs;
|
||||
///\brief Holds a list of all the current conversions
|
||||
std::map<std::string,JSON::Value> allConversions;
|
||||
std::map<std::string, JSON::Value> allConversions;
|
||||
///\brief Stores the status of all conversions, and the history
|
||||
std::map<std::string,std::string> statusHistory;
|
||||
std::map<std::string, std::string> statusHistory;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,52 +1,52 @@
|
|||
// Defines to print debug messages.
|
||||
#ifndef MIST_DEBUG
|
||||
#define MIST_DEBUG 1
|
||||
#define DLVL_NONE 0 // All debugging disabled.
|
||||
#define DLVL_FAIL 1 // Only messages about failed operations.
|
||||
#define DLVL_ERROR 2 // Only messages about errors and failed operations.
|
||||
#define DLVL_WARN 3 // Warnings, errors, and fail messages.
|
||||
#define DLVL_DEVEL 4 // All of the above, plus status messages handy during development.
|
||||
#define DLVL_INFO 4 // All of the above, plus status messages handy during development.
|
||||
#define DLVL_MEDIUM 5 // Slightly more than just development-level messages.
|
||||
#define DLVL_HIGH 6 // Verbose debugging messages.
|
||||
#define DLVL_VERYHIGH 7 // Very verbose debugging messages.
|
||||
#define DLVL_EXTREME 8 // Everything is reported in extreme detail.
|
||||
#define DLVL_INSANE 9 // Everything is reported in insane detail.
|
||||
#define DLVL_DONTEVEN 10 // All messages enabled, even pointless ones.
|
||||
#if DEBUG > -1
|
||||
#define MIST_DEBUG 1
|
||||
#define DLVL_NONE 0 // All debugging disabled.
|
||||
#define DLVL_FAIL 1 // Only messages about failed operations.
|
||||
#define DLVL_ERROR 2 // Only messages about errors and failed operations.
|
||||
#define DLVL_WARN 3 // Warnings, errors, and fail messages.
|
||||
#define DLVL_DEVEL 4 // All of the above, plus status messages handy during development.
|
||||
#define DLVL_INFO 4 // All of the above, plus status messages handy during development.
|
||||
#define DLVL_MEDIUM 5 // Slightly more than just development-level messages.
|
||||
#define DLVL_HIGH 6 // Verbose debugging messages.
|
||||
#define DLVL_VERYHIGH 7 // Very verbose debugging messages.
|
||||
#define DLVL_EXTREME 8 // Everything is reported in extreme detail.
|
||||
#define DLVL_INSANE 9 // Everything is reported in insane detail.
|
||||
#define DLVL_DONTEVEN 10 // All messages enabled, even pointless ones.
|
||||
#if DEBUG > -1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "config.h"
|
||||
static const char* DBG_LVL_LIST[] = {"NONE","FAIL","ERROR","WARN","INFO","MEDIUM","HIGH","VERYHIGH","EXTREME","INSANE","DONTEVEN"};
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__MACH__) && defined(__GNUC__)
|
||||
#include <errno.h>
|
||||
extern char * program_invocation_short_name;
|
||||
|
||||
#if DEBUG >= DLVL_DEVEL
|
||||
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s|%s|%d|%s:%d|" msg "\n", DBG_LVL_LIST[lvl], program_invocation_short_name, getpid(), __FILE__, __LINE__, ##__VA_ARGS__);}
|
||||
#else
|
||||
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s|%s|%d||" msg "\n", DBG_LVL_LIST[lvl], program_invocation_short_name, getpid(), ##__VA_ARGS__);}
|
||||
#endif
|
||||
#else
|
||||
#if DEBUG >= DLVL_DEVEL
|
||||
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s||%d|%s:%d|" msg "\n", DBG_LVL_LIST[lvl], getpid(), __FILE__, __LINE__, ##__VA_ARGS__);}
|
||||
#else
|
||||
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s||%d||" msg "\n", DBG_LVL_LIST[lvl], getpid(), ##__VA_ARGS__);}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "config.h"
|
||||
static const char * DBG_LVL_LIST[] = {"NONE", "FAIL", "ERROR", "WARN", "INFO", "MEDIUM", "HIGH", "VERYHIGH", "EXTREME", "INSANE", "DONTEVEN"};
|
||||
|
||||
#define DEBUG_MSG(lvl, msg, ...) // Debugging disabled.
|
||||
#if !defined(__APPLE__) && !defined(__MACH__) && defined(__GNUC__)
|
||||
#include <errno.h>
|
||||
extern char * program_invocation_short_name;
|
||||
|
||||
#if DEBUG >= DLVL_DEVEL
|
||||
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s|%s|%d|%s:%d|" msg "\n", DBG_LVL_LIST[lvl], program_invocation_short_name, getpid(), __FILE__, __LINE__, ##__VA_ARGS__);}
|
||||
#else
|
||||
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s|%s|%d||" msg "\n", DBG_LVL_LIST[lvl], program_invocation_short_name, getpid(), ##__VA_ARGS__);}
|
||||
#endif
|
||||
#else
|
||||
#if DEBUG >= DLVL_DEVEL
|
||||
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s||%d|%s:%d|" msg "\n", DBG_LVL_LIST[lvl], getpid(), __FILE__, __LINE__, ##__VA_ARGS__);}
|
||||
#else
|
||||
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s||%d||" msg "\n", DBG_LVL_LIST[lvl], getpid(), ##__VA_ARGS__);}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define DEBUG_MSG(lvl, msg, ...) // Debugging disabled.
|
||||
|
||||
#endif
|
||||
|
||||
#define FAIL_MSG(msg, ...) DEBUG_MSG(DLVL_FAIL, msg, ##__VA_ARGS__)
|
||||
#define ERROR_MSG(msg, ...) DEBUG_MSG(DLVL_ERROR, msg, ##__VA_ARGS__)
|
||||
#define WARN_MSG(msg, ...) DEBUG_MSG(DLVL_WARN, msg, ##__VA_ARGS__)
|
||||
#define DEVEL_MSG(msg, ...) DEBUG_MSG(DLVL_DEVEL, msg, ##__VA_ARGS__)
|
||||
#define INFO_MSG(msg, ...) DEBUG_MSG(DLVL_DEVEL, msg, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#define FAIL_MSG(msg, ...) DEBUG_MSG(DLVL_FAIL, msg, ##__VA_ARGS__)
|
||||
#define ERROR_MSG(msg, ...) DEBUG_MSG(DLVL_ERROR, msg, ##__VA_ARGS__)
|
||||
#define WARN_MSG(msg, ...) DEBUG_MSG(DLVL_WARN, msg, ##__VA_ARGS__)
|
||||
#define DEVEL_MSG(msg, ...) DEBUG_MSG(DLVL_DEVEL, msg, ##__VA_ARGS__)
|
||||
#define INFO_MSG(msg, ...) DEBUG_MSG(DLVL_DEVEL, msg, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
|
596
lib/dtsc.cpp
596
lib/dtsc.cpp
File diff suppressed because it is too large
Load diff
44
lib/dtsc.h
44
lib/dtsc.h
|
@ -58,7 +58,7 @@ namespace DTSC {
|
|||
unsigned int trackID;///< Stores the track the DTSC packet referenced by this structure is associated with.
|
||||
};
|
||||
|
||||
enum packType{
|
||||
enum packType {
|
||||
DTSC_INVALID,
|
||||
DTSC_HEAD,
|
||||
DTSC_V1,
|
||||
|
@ -67,26 +67,26 @@ namespace DTSC {
|
|||
|
||||
/// This class allows scanning through raw binary format DTSC data.
|
||||
/// It can be used as an iterator or as a direct accessor.
|
||||
class Scan{
|
||||
public:
|
||||
Scan();
|
||||
Scan(char * pointer, size_t len);
|
||||
std::string toPrettyString(unsigned int indent = 0);
|
||||
Scan getMember(std::string indice);
|
||||
Scan getMember(const char * indice);
|
||||
Scan getMember(const char * indice, const unsigned int ind_len);
|
||||
Scan getIndice(unsigned int num);
|
||||
|
||||
char getType();
|
||||
bool asBool();
|
||||
long long asInt();
|
||||
std::string asString();
|
||||
void getString(char *& result, unsigned int & len);
|
||||
private:
|
||||
char * p;
|
||||
size_t len;
|
||||
class Scan {
|
||||
public:
|
||||
Scan();
|
||||
Scan(char * pointer, size_t len);
|
||||
std::string toPrettyString(unsigned int indent = 0);
|
||||
Scan getMember(std::string indice);
|
||||
Scan getMember(const char * indice);
|
||||
Scan getMember(const char * indice, const unsigned int ind_len);
|
||||
Scan getIndice(unsigned int num);
|
||||
|
||||
char getType();
|
||||
bool asBool();
|
||||
long long asInt();
|
||||
std::string asString();
|
||||
void getString(char *& result, unsigned int & len);
|
||||
private:
|
||||
char * p;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
|
||||
/// DTSC::Packets can currently be three types:
|
||||
/// DTSC_HEAD packets are the "DTSC" header string, followed by 4 bytes len and packed content.
|
||||
/// DTSC_V1 packets are "DTPD", followed by 4 bytes len and packed content.
|
||||
|
@ -125,7 +125,7 @@ namespace DTSC {
|
|||
unsigned int bufferLen;
|
||||
unsigned int dataLen;
|
||||
};
|
||||
|
||||
|
||||
/// A simple structure used for ordering byte seek positions.
|
||||
struct livePos {
|
||||
livePos() {
|
||||
|
@ -375,7 +375,7 @@ namespace DTSC {
|
|||
private:
|
||||
long int endPos;
|
||||
void readHeader(int pos);
|
||||
DTSC::Packet myPack;
|
||||
DTSC::Packet myPack;
|
||||
JSON::Value metaStorage;
|
||||
readOnlyMeta metadata;
|
||||
std::map<int, std::string> trackMapping;
|
||||
|
|
486
lib/dtscmeta.cpp
486
lib/dtscmeta.cpp
File diff suppressed because it is too large
Load diff
|
@ -1,32 +1,32 @@
|
|||
#include "filesystem.h"
|
||||
#include "defines.h"
|
||||
|
||||
Filesystem::Directory::Directory(std::string PathName, std::string BasePath){
|
||||
Filesystem::Directory::Directory(std::string PathName, std::string BasePath) {
|
||||
MyBase = BasePath;
|
||||
if (PathName[0] == '/'){
|
||||
if (PathName[0] == '/') {
|
||||
PathName.erase(0, 1);
|
||||
}
|
||||
if (BasePath[BasePath.size() - 1] != '/'){
|
||||
if (BasePath[BasePath.size() - 1] != '/') {
|
||||
BasePath += "/";
|
||||
}
|
||||
MyPath = PathName;
|
||||
FillEntries();
|
||||
}
|
||||
|
||||
Filesystem::Directory::~Directory(){
|
||||
Filesystem::Directory::~Directory() {
|
||||
}
|
||||
|
||||
void Filesystem::Directory::FillEntries(){
|
||||
void Filesystem::Directory::FillEntries() {
|
||||
ValidDir = true;
|
||||
struct stat StatBuf;
|
||||
Entries.clear();
|
||||
DIR * Dirp = opendir((MyBase + MyPath).c_str());
|
||||
if ( !Dirp){
|
||||
if (!Dirp) {
|
||||
ValidDir = false;
|
||||
}else{
|
||||
} else {
|
||||
dirent * entry;
|
||||
while ((entry = readdir(Dirp))){
|
||||
if (stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1){
|
||||
while ((entry = readdir(Dirp))) {
|
||||
if (stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "Skipping %s, reason %s", entry->d_name, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
@ -36,173 +36,173 @@ void Filesystem::Directory::FillEntries(){
|
|||
}
|
||||
}
|
||||
|
||||
void Filesystem::Directory::Print(){
|
||||
void Filesystem::Directory::Print() {
|
||||
/// \todo Remove? Libraries shouldn't print stuff.
|
||||
if ( !ValidDir){
|
||||
if (!ValidDir) {
|
||||
DEBUG_MSG(DLVL_ERROR, "%s is not a valid directory", (MyBase + MyPath).c_str());
|
||||
return;
|
||||
}
|
||||
printf("%s:\n", (MyBase + MyPath).c_str());
|
||||
for (std::map<std::string, struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++){
|
||||
printf("\t%s\n", ( *it).first.c_str());
|
||||
for (std::map<std::string, struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++) {
|
||||
printf("\t%s\n", (*it).first.c_str());
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
bool Filesystem::Directory::IsDir(){
|
||||
bool Filesystem::Directory::IsDir() {
|
||||
return ValidDir;
|
||||
}
|
||||
|
||||
std::string Filesystem::Directory::PWD(){
|
||||
std::string Filesystem::Directory::PWD() {
|
||||
return "/" + MyPath;
|
||||
}
|
||||
|
||||
std::string Filesystem::Directory::LIST(std::vector<std::string> ActiveStreams){
|
||||
std::string Filesystem::Directory::LIST(std::vector<std::string> ActiveStreams) {
|
||||
FillEntries();
|
||||
int MyPermissions;
|
||||
std::stringstream Converter;
|
||||
passwd* pwd; //For Username
|
||||
group* grp; //For Groupname
|
||||
tm* tm; //For time localisation
|
||||
passwd * pwd; //For Username
|
||||
group * grp; //For Groupname
|
||||
tm * tm; //For time localisation
|
||||
char datestring[256]; //For time localisation
|
||||
|
||||
std::string MyLoc = MyBase + MyPath;
|
||||
if (MyLoc[MyLoc.size() - 1] != '/'){
|
||||
if (MyLoc[MyLoc.size() - 1] != '/') {
|
||||
MyLoc += "/";
|
||||
}
|
||||
|
||||
for (std::map<std::string, struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++){
|
||||
for (std::map<std::string, struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++) {
|
||||
|
||||
bool Active = (std::find(ActiveStreams.begin(), ActiveStreams.end(), ( *it).first) != ActiveStreams.end());
|
||||
if ((Active && (MyVisible[MyPath] & S_ACTIVE)) || (( !Active) && (MyVisible[MyPath] & S_INACTIVE)) || ((( *it).second.st_mode / 010000) == 4)){
|
||||
if ((( *it).second.st_mode / 010000) == 4){
|
||||
bool Active = (std::find(ActiveStreams.begin(), ActiveStreams.end(), (*it).first) != ActiveStreams.end());
|
||||
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{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
MyPermissions = ((( *it).second.st_mode % 010000) / 0100);
|
||||
if (MyPermissions & 4){
|
||||
MyPermissions = (((*it).second.st_mode % 010000) / 0100);
|
||||
if (MyPermissions & 4) {
|
||||
Converter << 'r';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
if (MyPermissions & 2){
|
||||
if (MyPermissions & 2) {
|
||||
Converter << 'w';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
if (MyPermissions & 1){
|
||||
if (MyPermissions & 1) {
|
||||
Converter << 'x';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
MyPermissions = ((( *it).second.st_mode % 0100) / 010);
|
||||
if (MyPermissions & 4){
|
||||
MyPermissions = (((*it).second.st_mode % 0100) / 010);
|
||||
if (MyPermissions & 4) {
|
||||
Converter << 'r';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
if (MyPermissions & 2){
|
||||
if (MyPermissions & 2) {
|
||||
Converter << 'w';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
if (MyPermissions & 1){
|
||||
if (MyPermissions & 1) {
|
||||
Converter << 'x';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
MyPermissions = (( *it).second.st_mode % 010);
|
||||
if (MyPermissions & 4){
|
||||
MyPermissions = ((*it).second.st_mode % 010);
|
||||
if (MyPermissions & 4) {
|
||||
Converter << 'r';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
if (MyPermissions & 2){
|
||||
if (MyPermissions & 2) {
|
||||
Converter << 'w';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
if (MyPermissions & 1){
|
||||
if (MyPermissions & 1) {
|
||||
Converter << 'x';
|
||||
}else{
|
||||
} else {
|
||||
Converter << '-';
|
||||
}
|
||||
Converter << ' ';
|
||||
Converter << ( *it).second.st_nlink;
|
||||
Converter << (*it).second.st_nlink;
|
||||
Converter << ' ';
|
||||
if ((pwd = getpwuid(( *it).second.st_uid))){
|
||||
if ((pwd = getpwuid((*it).second.st_uid))) {
|
||||
Converter << pwd->pw_name;
|
||||
}else{
|
||||
Converter << ( *it).second.st_uid;
|
||||
} else {
|
||||
Converter << (*it).second.st_uid;
|
||||
}
|
||||
Converter << ' ';
|
||||
if ((grp = getgrgid(( *it).second.st_gid))){
|
||||
if ((grp = getgrgid((*it).second.st_gid))) {
|
||||
Converter << grp->gr_name;
|
||||
}else{
|
||||
Converter << ( *it).second.st_gid;
|
||||
} else {
|
||||
Converter << (*it).second.st_gid;
|
||||
}
|
||||
Converter << ' ';
|
||||
Converter << ( *it).second.st_size;
|
||||
Converter << (*it).second.st_size;
|
||||
Converter << ' ';
|
||||
tm = localtime( &(( *it).second.st_mtime));
|
||||
tm = localtime(&((*it).second.st_mtime));
|
||||
strftime(datestring, sizeof(datestring), "%b %d %H:%M", tm);
|
||||
Converter << datestring;
|
||||
Converter << ' ';
|
||||
Converter << ( *it).first;
|
||||
Converter << (*it).first;
|
||||
Converter << '\n';
|
||||
}
|
||||
}
|
||||
return Converter.str();
|
||||
}
|
||||
|
||||
bool Filesystem::Directory::CWD(std::string Path){
|
||||
if (Path[0] == '/'){
|
||||
bool Filesystem::Directory::CWD(std::string Path) {
|
||||
if (Path[0] == '/') {
|
||||
Path.erase(0, 1);
|
||||
MyPath = Path;
|
||||
}else{
|
||||
if (MyPath != ""){
|
||||
} else {
|
||||
if (MyPath != "") {
|
||||
MyPath += "/";
|
||||
}
|
||||
MyPath += Path;
|
||||
}
|
||||
FillEntries();
|
||||
printf("New Path: %s\n", MyPath.c_str());
|
||||
if (MyPermissions.find(MyPath) != MyPermissions.end()){
|
||||
if (MyPermissions.find(MyPath) != MyPermissions.end()) {
|
||||
printf("\tPermissions: %d\n", MyPermissions[MyPath]);
|
||||
}
|
||||
return SimplifyPath();
|
||||
}
|
||||
|
||||
bool Filesystem::Directory::CDUP(){
|
||||
bool Filesystem::Directory::CDUP() {
|
||||
return CWD("..");
|
||||
}
|
||||
|
||||
std::string Filesystem::Directory::RETR(std::string Path){
|
||||
std::string Filesystem::Directory::RETR(std::string Path) {
|
||||
std::string Result;
|
||||
std::string FileName;
|
||||
if (Path[0] == '/'){
|
||||
if (Path[0] == '/') {
|
||||
Path.erase(0, 1);
|
||||
FileName = MyBase + Path;
|
||||
}else{
|
||||
} else {
|
||||
FileName = MyBase + MyPath + "/" + Path;
|
||||
}
|
||||
std::ifstream File;
|
||||
File.open(FileName.c_str());
|
||||
while (File.good()){
|
||||
while (File.good()) {
|
||||
Result += File.get();
|
||||
}
|
||||
File.close();
|
||||
return Result;
|
||||
}
|
||||
|
||||
void Filesystem::Directory::STOR(std::string Path, std::string Data){
|
||||
if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_STOR)){
|
||||
void Filesystem::Directory::STOR(std::string Path, std::string Data) {
|
||||
if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_STOR)) {
|
||||
std::string FileName;
|
||||
if (Path[0] == '/'){
|
||||
if (Path[0] == '/') {
|
||||
Path.erase(0, 1);
|
||||
FileName = MyBase + Path;
|
||||
}else{
|
||||
} else {
|
||||
FileName = MyBase + MyPath + "/" + Path;
|
||||
}
|
||||
std::ofstream File;
|
||||
|
@ -212,48 +212,48 @@ void Filesystem::Directory::STOR(std::string Path, std::string Data){
|
|||
}
|
||||
}
|
||||
|
||||
bool Filesystem::Directory::SimplifyPath(){
|
||||
bool Filesystem::Directory::SimplifyPath() {
|
||||
MyPath += "/";
|
||||
std::vector<std::string> TempPath;
|
||||
std::string TempString;
|
||||
for (std::string::iterator it = MyPath.begin(); it != MyPath.end(); it++){
|
||||
if (( *it) == '/'){
|
||||
if (TempString == ".."){
|
||||
if ( !TempPath.size()){
|
||||
for (std::string::iterator it = MyPath.begin(); it != MyPath.end(); it++) {
|
||||
if ((*it) == '/') {
|
||||
if (TempString == "..") {
|
||||
if (!TempPath.size()) {
|
||||
return false;
|
||||
}
|
||||
TempPath.erase((TempPath.end() - 1));
|
||||
}else if (TempString != "." && TempString != ""){
|
||||
} else if (TempString != "." && TempString != "") {
|
||||
TempPath.push_back(TempString);
|
||||
}
|
||||
TempString = "";
|
||||
}else{
|
||||
TempString += ( *it);
|
||||
} else {
|
||||
TempString += (*it);
|
||||
}
|
||||
}
|
||||
MyPath = "";
|
||||
for (std::vector<std::string>::iterator it = TempPath.begin(); it != TempPath.end(); it++){
|
||||
MyPath += ( *it);
|
||||
if (it != (TempPath.end() - 1)){
|
||||
for (std::vector<std::string>::iterator it = TempPath.begin(); it != TempPath.end(); it++) {
|
||||
MyPath += (*it);
|
||||
if (it != (TempPath.end() - 1)) {
|
||||
MyPath += "/";
|
||||
}
|
||||
}
|
||||
if (MyVisible.find(MyPath) == MyVisible.end()){
|
||||
if (MyVisible.find(MyPath) == MyVisible.end()) {
|
||||
MyVisible[MyPath] = S_ALL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filesystem::Directory::DELE(std::string Path){
|
||||
if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_DELE)){
|
||||
bool Filesystem::Directory::DELE(std::string Path) {
|
||||
if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_DELE)) {
|
||||
std::string FileName;
|
||||
if (Path[0] == '/'){
|
||||
if (Path[0] == '/') {
|
||||
Path.erase(0, 1);
|
||||
FileName = MyBase + Path;
|
||||
}else{
|
||||
} else {
|
||||
FileName = MyBase + MyPath + "/" + Path;
|
||||
}
|
||||
if (std::remove(FileName.c_str())){
|
||||
if (std::remove(FileName.c_str())) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Removing file %s failed", FileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -262,15 +262,15 @@ bool Filesystem::Directory::DELE(std::string Path){
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Filesystem::Directory::MKD(std::string Path){
|
||||
bool Filesystem::Directory::MKD(std::string Path) {
|
||||
std::string FileName;
|
||||
if (Path[0] == '/'){
|
||||
if (Path[0] == '/') {
|
||||
Path.erase(0, 1);
|
||||
FileName = MyBase + Path;
|
||||
}else{
|
||||
} else {
|
||||
FileName = MyBase + MyPath + "/" + Path;
|
||||
}
|
||||
if (mkdir(FileName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)){
|
||||
if (mkdir(FileName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Creating directory %s failed", FileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -278,22 +278,22 @@ bool Filesystem::Directory::MKD(std::string Path){
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Filesystem::Directory::Rename(std::string From, std::string To){
|
||||
if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_RNFT)){
|
||||
bool Filesystem::Directory::Rename(std::string From, std::string To) {
|
||||
if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & P_RNFT)) {
|
||||
std::string FileFrom;
|
||||
if (From[0] == '/'){
|
||||
if (From[0] == '/') {
|
||||
From.erase(0, 1);
|
||||
FileFrom = MyBase + From;
|
||||
}else{
|
||||
} else {
|
||||
FileFrom = MyBase + MyPath + "/" + From;
|
||||
}
|
||||
std::string FileTo;
|
||||
if (To[0] == '/'){
|
||||
if (To[0] == '/') {
|
||||
FileTo = MyBase + To;
|
||||
}else{
|
||||
} else {
|
||||
FileTo = MyBase + MyPath + "/" + To;
|
||||
}
|
||||
if (std::rename(FileFrom.c_str(), FileTo.c_str())){
|
||||
if (std::rename(FileFrom.c_str(), FileTo.c_str())) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Renaming %s to %s failed", FileFrom.c_str(), FileTo.c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -302,17 +302,17 @@ bool Filesystem::Directory::Rename(std::string From, std::string To){
|
|||
return false;
|
||||
}
|
||||
|
||||
void Filesystem::Directory::SetPermissions(std::string Path, char Permissions){
|
||||
void Filesystem::Directory::SetPermissions(std::string Path, char Permissions) {
|
||||
MyPermissions[Path] = Permissions;
|
||||
}
|
||||
|
||||
bool Filesystem::Directory::HasPermission(char Permission){
|
||||
if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & Permission)){
|
||||
bool Filesystem::Directory::HasPermission(char Permission) {
|
||||
if (MyPermissions.find(MyPath) == MyPermissions.end() || (MyPermissions[MyPath] & Permission)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Filesystem::Directory::SetVisibility(std::string Pathname, char Visible){
|
||||
void Filesystem::Directory::SetVisibility(std::string Pathname, char Visible) {
|
||||
MyVisible[Pathname] = Visible;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <errno.h>
|
||||
|
||||
namespace Filesystem {
|
||||
enum DIR_Permissions{
|
||||
enum DIR_Permissions {
|
||||
P_LIST = 0x01, //List
|
||||
P_RETR = 0x02, //Retrieve
|
||||
P_STOR = 0x04, //Store
|
||||
|
@ -31,11 +31,11 @@ namespace Filesystem {
|
|||
P_RMD = 0x40, //Remove directory
|
||||
};
|
||||
|
||||
enum DIR_Show{
|
||||
enum DIR_Show {
|
||||
S_NONE = 0x00, S_ACTIVE = 0x01, S_INACTIVE = 0x02, S_ALL = 0x03,
|
||||
};
|
||||
|
||||
class Directory{
|
||||
class Directory {
|
||||
public:
|
||||
Directory(std::string PathName = "", std::string BasePath = ".");
|
||||
~Directory();
|
||||
|
|
512
lib/flv_tag.cpp
512
lib/flv_tag.cpp
File diff suppressed because it is too large
Load diff
|
@ -25,7 +25,7 @@ namespace FLV {
|
|||
bool is_header(char * header); ///< Checks the first 3 bytes for the string "FLV".
|
||||
|
||||
/// This class is used to hold, work with and get information about a single FLV tag.
|
||||
class Tag{
|
||||
class Tag {
|
||||
public:
|
||||
int len; ///< Actual length of tag.
|
||||
bool isKeyframe; ///< True if current tag is a video keyframe.
|
||||
|
@ -40,12 +40,12 @@ namespace FLV {
|
|||
int offset();
|
||||
void offset(int o);
|
||||
Tag(); ///< Constructor for a new, empty, tag.
|
||||
Tag(const Tag& O); ///< Copy constructor, copies the contents of an existing tag.
|
||||
Tag & operator=(const Tag& O); ///< Assignment operator - works exactly like the copy constructor.
|
||||
Tag(const RTMPStream::Chunk& O); ///<Copy constructor from a RTMP chunk.
|
||||
Tag(const Tag & O); ///< Copy constructor, copies the contents of an existing tag.
|
||||
Tag & operator=(const Tag & O); ///< Assignment operator - works exactly like the copy constructor.
|
||||
Tag(const RTMPStream::Chunk & O); ///<Copy constructor from a RTMP chunk.
|
||||
~Tag(); ///< Generic destructor.
|
||||
//loader functions
|
||||
bool ChunkLoader(const RTMPStream::Chunk& O);
|
||||
bool ChunkLoader(const RTMPStream::Chunk & O);
|
||||
bool DTSCLoader(DTSC::Stream & S);
|
||||
bool DTSCLoader(DTSC::Packet & packData, DTSC::Track & track);
|
||||
bool DTSCVideoInit(DTSC::Track & video);
|
||||
|
|
790
lib/ftp.cpp
790
lib/ftp.cpp
|
@ -1,6 +1,6 @@
|
|||
#include "ftp.h"
|
||||
|
||||
FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::string> Credentials){
|
||||
FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::string> Credentials) {
|
||||
Conn = NewConnection;
|
||||
MyPassivePort = 0;
|
||||
USER = "";
|
||||
|
@ -23,545 +23,545 @@ FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::str
|
|||
MyDir.SetVisibility("OnDemand", Filesystem::S_ACTIVE);
|
||||
|
||||
JSON::Value MyConfig = JSON::fromFile("/tmp/mist/streamlist");
|
||||
for (JSON::ObjIter it = MyConfig["streams"].ObjBegin(); it != MyConfig["streams"].ObjEnd(); it++){
|
||||
std::string ThisStream = ( *it).second["channel"]["URL"].toString();
|
||||
for (JSON::ObjIter it = MyConfig["streams"].ObjBegin(); it != MyConfig["streams"].ObjEnd(); it++) {
|
||||
std::string ThisStream = (*it).second["channel"]["URL"].toString();
|
||||
ThisStream.erase(ThisStream.begin());
|
||||
ThisStream.erase(ThisStream.end() - 1);
|
||||
while (ThisStream.find('/') != std::string::npos){
|
||||
while (ThisStream.find('/') != std::string::npos) {
|
||||
ThisStream.erase(0, ThisStream.find('/') + 1);
|
||||
}
|
||||
ActiveStreams.push_back(ThisStream);
|
||||
}
|
||||
}
|
||||
|
||||
FTP::User::~User(){
|
||||
FTP::User::~User() {
|
||||
}
|
||||
|
||||
int FTP::User::ParseCommand(std::string Command){
|
||||
int FTP::User::ParseCommand(std::string Command) {
|
||||
Commands ThisCmd = CMD_NOCMD;
|
||||
if (Command.substr(0, 4) == "NOOP"){
|
||||
if (Command.substr(0, 4) == "NOOP") {
|
||||
ThisCmd = CMD_NOOP;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "USER"){
|
||||
if (Command.substr(0, 4) == "USER") {
|
||||
ThisCmd = CMD_USER;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "PASS"){
|
||||
if (Command.substr(0, 4) == "PASS") {
|
||||
ThisCmd = CMD_PASS;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "QUIT"){
|
||||
if (Command.substr(0, 4) == "QUIT") {
|
||||
ThisCmd = CMD_QUIT;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "PORT"){
|
||||
if (Command.substr(0, 4) == "PORT") {
|
||||
ThisCmd = CMD_PORT;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "RETR"){
|
||||
if (Command.substr(0, 4) == "RETR") {
|
||||
ThisCmd = CMD_RETR;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "STOR"){
|
||||
if (Command.substr(0, 4) == "STOR") {
|
||||
ThisCmd = CMD_STOR;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "TYPE"){
|
||||
if (Command.substr(0, 4) == "TYPE") {
|
||||
ThisCmd = CMD_TYPE;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "MODE"){
|
||||
if (Command.substr(0, 4) == "MODE") {
|
||||
ThisCmd = CMD_MODE;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "STRU"){
|
||||
if (Command.substr(0, 4) == "STRU") {
|
||||
ThisCmd = CMD_STRU;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "EPSV"){
|
||||
if (Command.substr(0, 4) == "EPSV") {
|
||||
ThisCmd = CMD_EPSV;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "PASV"){
|
||||
if (Command.substr(0, 4) == "PASV") {
|
||||
ThisCmd = CMD_PASV;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "LIST"){
|
||||
if (Command.substr(0, 4) == "LIST") {
|
||||
ThisCmd = CMD_LIST;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "CDUP"){
|
||||
if (Command.substr(0, 4) == "CDUP") {
|
||||
ThisCmd = CMD_CDUP;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "DELE"){
|
||||
if (Command.substr(0, 4) == "DELE") {
|
||||
ThisCmd = CMD_DELE;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "RNFR"){
|
||||
if (Command.substr(0, 4) == "RNFR") {
|
||||
ThisCmd = CMD_RNFR;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 4) == "RNTO"){
|
||||
if (Command.substr(0, 4) == "RNTO") {
|
||||
ThisCmd = CMD_RNTO;
|
||||
Command.erase(0, 5);
|
||||
}
|
||||
if (Command.substr(0, 3) == "PWD"){
|
||||
if (Command.substr(0, 3) == "PWD") {
|
||||
ThisCmd = CMD_PWD;
|
||||
Command.erase(0, 4);
|
||||
}
|
||||
if (Command.substr(0, 3) == "CWD"){
|
||||
if (Command.substr(0, 3) == "CWD") {
|
||||
ThisCmd = CMD_CWD;
|
||||
Command.erase(0, 4);
|
||||
}
|
||||
if (Command.substr(0, 3) == "RMD"){
|
||||
if (Command.substr(0, 3) == "RMD") {
|
||||
ThisCmd = CMD_RMD;
|
||||
Command.erase(0, 4);
|
||||
}
|
||||
if (Command.substr(0, 3) == "MKD"){
|
||||
if (Command.substr(0, 3) == "MKD") {
|
||||
ThisCmd = CMD_MKD;
|
||||
Command.erase(0, 4);
|
||||
}
|
||||
if (ThisCmd != CMD_RNTO){
|
||||
if (ThisCmd != CMD_RNTO) {
|
||||
RNFR = "";
|
||||
}
|
||||
switch (ThisCmd){
|
||||
switch (ThisCmd) {
|
||||
case CMD_NOOP: {
|
||||
return 200; //Command okay.
|
||||
break;
|
||||
}
|
||||
return 200; //Command okay.
|
||||
break;
|
||||
}
|
||||
case CMD_USER: {
|
||||
USER = "";
|
||||
PASS = "";
|
||||
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.
|
||||
PASS = Command;
|
||||
if ( !LoggedIn()){
|
||||
USER = "";
|
||||
PASS = "";
|
||||
return 530; //Not logged in.
|
||||
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.
|
||||
PASS = Command;
|
||||
if (!LoggedIn()) {
|
||||
USER = "";
|
||||
PASS = "";
|
||||
return 530; //Not logged in.
|
||||
}
|
||||
return 230;
|
||||
break;
|
||||
}
|
||||
return 230;
|
||||
break;
|
||||
}
|
||||
case CMD_LIST: {
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()){
|
||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||
}else{
|
||||
Conn.Send("150 File status okay; about to open data connection.\n");
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()) {
|
||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||
} else {
|
||||
Conn.Send("150 File status okay; about to open data connection.\n");
|
||||
}
|
||||
while (!Connected.connected()) {
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string tmpstr = MyDir.LIST(ActiveStreams);
|
||||
Connected.Send(tmpstr);
|
||||
Connected.close();
|
||||
return 226;
|
||||
break;
|
||||
}
|
||||
while ( !Connected.connected()){
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string tmpstr = MyDir.LIST(ActiveStreams);
|
||||
Connected.Send(tmpstr);
|
||||
Connected.close();
|
||||
return 226;
|
||||
break;
|
||||
}
|
||||
case CMD_QUIT: {
|
||||
return 221; //Service closing control connection. Logged out if appropriate.
|
||||
break;
|
||||
}
|
||||
return 221; //Service closing control connection. Logged out if appropriate.
|
||||
break;
|
||||
}
|
||||
case CMD_PORT: {
|
||||
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;
|
||||
}
|
||||
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.
|
||||
MyPassivePort = (rand() % 9999);
|
||||
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
||||
return 229;
|
||||
break;
|
||||
}
|
||||
if (!LoggedIn()) {
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
MyPassivePort = (rand() % 9999);
|
||||
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
||||
return 229;
|
||||
break;
|
||||
}
|
||||
case CMD_PASV: {
|
||||
if ( !LoggedIn()){
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
MyPassivePort = (rand() % 9999) + 49152;
|
||||
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
||||
return 227;
|
||||
break;
|
||||
}
|
||||
if (!LoggedIn()) {
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
MyPassivePort = (rand() % 9999) + 49152;
|
||||
Passive = Socket::Server(MyPassivePort, "0.0.0.0", true);
|
||||
return 227;
|
||||
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.
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()){
|
||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||
}else{
|
||||
Conn.Send("150 File status okay; about to open data connection.\n");
|
||||
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.
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()) {
|
||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||
} else {
|
||||
Conn.Send("150 File status okay; about to open data connection.\n");
|
||||
}
|
||||
while (!Connected.connected()) {
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string tmpstr = MyDir.RETR(Command);
|
||||
Connected.Send(tmpstr);
|
||||
Connected.close();
|
||||
return 226;
|
||||
break;
|
||||
}
|
||||
while ( !Connected.connected()){
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string tmpstr = MyDir.RETR(Command);
|
||||
Connected.Send(tmpstr);
|
||||
Connected.close();
|
||||
return 226;
|
||||
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.
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()){
|
||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||
}else{
|
||||
Conn.Send("150 File status okay; about to open data connection.\n");
|
||||
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.
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()) {
|
||||
Conn.Send("125 Data connection already open; transfer starting.\n");
|
||||
} else {
|
||||
Conn.Send("150 File status okay; about to open data connection.\n");
|
||||
}
|
||||
while (!Connected.connected()) {
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string Buffer;
|
||||
while (Connected.spool()) {
|
||||
}
|
||||
/// \todo Comment me back in. ^_^
|
||||
//Buffer = Connected.Received();
|
||||
MyDir.STOR(Command, Buffer);
|
||||
return 250;
|
||||
break;
|
||||
}
|
||||
while ( !Connected.connected()){
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string Buffer;
|
||||
while (Connected.spool()){
|
||||
}
|
||||
/// \todo Comment me back in. ^_^
|
||||
//Buffer = Connected.Received();
|
||||
MyDir.STOR(Command, Buffer);
|
||||
return 250;
|
||||
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.
|
||||
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.
|
||||
}
|
||||
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.
|
||||
}
|
||||
TYPE = TYPE_IMAGE_NONPRINT;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return 504; //Command not implemented for that parameter.
|
||||
break;
|
||||
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.
|
||||
}
|
||||
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.
|
||||
}
|
||||
TYPE = TYPE_IMAGE_NONPRINT;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return 504; //Command not implemented for that parameter.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 200; //Command okay.
|
||||
break;
|
||||
}
|
||||
return 200; //Command okay.
|
||||
break;
|
||||
}
|
||||
case CMD_MODE: {
|
||||
if ( !LoggedIn()){
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
if (Command == ""){
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
if (Command.size() != 1){
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
if (Command[0] != 'S'){
|
||||
return 504;
|
||||
} //Command not implemented for that parameter.
|
||||
MODE = MODE_STREAM;
|
||||
return 200; //Command okay.
|
||||
break;
|
||||
}
|
||||
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.
|
||||
switch (Command[0]){
|
||||
case 'F': {
|
||||
STRU = STRU_FILE;
|
||||
break;
|
||||
}
|
||||
case 'R': {
|
||||
STRU = STRU_RECORD;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return 504; //Command not implemented for that parameter.
|
||||
break;
|
||||
if (!LoggedIn()) {
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
if (Command == "") {
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
if (Command.size() != 1) {
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
switch (Command[0]) {
|
||||
case 'F': {
|
||||
STRU = STRU_FILE;
|
||||
break;
|
||||
}
|
||||
case 'R': {
|
||||
STRU = STRU_RECORD;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return 504; //Command not implemented for that parameter.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 200; //Command okay.
|
||||
break;
|
||||
}
|
||||
return 200; //Command okay.
|
||||
break;
|
||||
}
|
||||
case CMD_PWD: {
|
||||
if ( !LoggedIn()){
|
||||
return 550;
|
||||
} //Not logged in.
|
||||
if (Command != ""){
|
||||
return 501;
|
||||
} //Syntax error in parameters or arguments.
|
||||
return 2570; //257 -- 0 to indicate PWD over MKD
|
||||
break;
|
||||
}
|
||||
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.
|
||||
Filesystem::Directory TmpDir = MyDir;
|
||||
if (TmpDir.CWD(Command)){
|
||||
if (TmpDir.IsDir()){
|
||||
MyDir = TmpDir;
|
||||
return 250;
|
||||
if (!LoggedIn()) {
|
||||
return 530;
|
||||
} //Not logged in.
|
||||
Filesystem::Directory TmpDir = MyDir;
|
||||
if (TmpDir.CWD(Command)) {
|
||||
if (TmpDir.IsDir()) {
|
||||
MyDir = TmpDir;
|
||||
return 250;
|
||||
}
|
||||
}
|
||||
return 550;
|
||||
break;
|
||||
}
|
||||
return 550;
|
||||
break;
|
||||
}
|
||||
case CMD_CDUP: {
|
||||
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()){
|
||||
MyDir = TmpDir;
|
||||
return 250;
|
||||
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()) {
|
||||
MyDir = TmpDir;
|
||||
return 250;
|
||||
}
|
||||
}
|
||||
return 550;
|
||||
break;
|
||||
}
|
||||
return 550;
|
||||
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;
|
||||
}
|
||||
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 (!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;
|
||||
}
|
||||
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 (!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;
|
||||
}
|
||||
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.
|
||||
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.
|
||||
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;
|
||||
}
|
||||
return 250;
|
||||
}
|
||||
return 250;
|
||||
}
|
||||
default: {
|
||||
return 502; //Command not implemented.
|
||||
break;
|
||||
}
|
||||
return 502; //Command not implemented.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FTP::User::LoggedIn(){
|
||||
if (USER == "" || PASS == ""){
|
||||
bool FTP::User::LoggedIn() {
|
||||
if (USER == "" || PASS == "") {
|
||||
return false;
|
||||
}
|
||||
if ( !AllCredentials.size()){
|
||||
if (!AllCredentials.size()) {
|
||||
return true;
|
||||
}
|
||||
if ((AllCredentials.find(USER) != AllCredentials.end()) && AllCredentials[USER] == PASS){
|
||||
if ((AllCredentials.find(USER) != AllCredentials.end()) && AllCredentials[USER] == PASS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string FTP::User::NumToMsg(int MsgNum){
|
||||
std::string FTP::User::NumToMsg(int MsgNum) {
|
||||
std::string Result;
|
||||
switch (MsgNum){
|
||||
switch (MsgNum) {
|
||||
case 200: {
|
||||
Result = "200 Message okay.\n";
|
||||
break;
|
||||
}
|
||||
Result = "200 Message okay.\n";
|
||||
break;
|
||||
}
|
||||
case 221: {
|
||||
Result = "221 Service closing control connection. Logged out if appropriate.\n";
|
||||
break;
|
||||
}
|
||||
Result = "221 Service closing control connection. Logged out if appropriate.\n";
|
||||
break;
|
||||
}
|
||||
case 226: {
|
||||
Result = "226 Closing data connection.\n";
|
||||
break;
|
||||
}
|
||||
Result = "226 Closing data connection.\n";
|
||||
break;
|
||||
}
|
||||
case 227: {
|
||||
std::stringstream sstr;
|
||||
sstr << "227 Entering passive mode (0,0,0,0,";
|
||||
sstr << (MyPassivePort >> 8) % 256;
|
||||
sstr << ",";
|
||||
sstr << MyPassivePort % 256;
|
||||
sstr << ").\n";
|
||||
Result = sstr.str();
|
||||
break;
|
||||
}
|
||||
std::stringstream sstr;
|
||||
sstr << "227 Entering passive mode (0,0,0,0,";
|
||||
sstr << (MyPassivePort >> 8) % 256;
|
||||
sstr << ",";
|
||||
sstr << MyPassivePort % 256;
|
||||
sstr << ").\n";
|
||||
Result = sstr.str();
|
||||
break;
|
||||
}
|
||||
case 229: {
|
||||
std::stringstream sstr;
|
||||
sstr << "229 Entering extended passive mode (|||";
|
||||
sstr << MyPassivePort;
|
||||
sstr << "|).\n";
|
||||
Result = sstr.str();
|
||||
break;
|
||||
}
|
||||
std::stringstream sstr;
|
||||
sstr << "229 Entering extended passive mode (|||";
|
||||
sstr << MyPassivePort;
|
||||
sstr << "|).\n";
|
||||
Result = sstr.str();
|
||||
break;
|
||||
}
|
||||
case 230: {
|
||||
Result = "230 User logged in, proceed.\n";
|
||||
break;
|
||||
}
|
||||
Result = "230 User logged in, proceed.\n";
|
||||
break;
|
||||
}
|
||||
case 250: {
|
||||
Result = "250 Requested file action okay, completed.\n";
|
||||
break;
|
||||
}
|
||||
Result = "250 Requested file action okay, completed.\n";
|
||||
break;
|
||||
}
|
||||
case 2570: { //PWD
|
||||
Result = "257 \"" + MyDir.PWD() + "\" selected as PWD\n";
|
||||
break;
|
||||
}
|
||||
Result = "257 \"" + MyDir.PWD() + "\" selected as PWD\n";
|
||||
break;
|
||||
}
|
||||
case 2571: { //MKD
|
||||
Result = "257 \"" + MyDir.PWD() + "\" created\n";
|
||||
break;
|
||||
}
|
||||
Result = "257 \"" + MyDir.PWD() + "\" created\n";
|
||||
break;
|
||||
}
|
||||
case 331: {
|
||||
Result = "331 User name okay, need password.\n";
|
||||
break;
|
||||
}
|
||||
Result = "331 User name okay, need password.\n";
|
||||
break;
|
||||
}
|
||||
case 350: {
|
||||
Result = "350 Requested file action pending further information\n";
|
||||
break;
|
||||
}
|
||||
Result = "350 Requested file action pending further information\n";
|
||||
break;
|
||||
}
|
||||
case 501: {
|
||||
Result = "501 Syntax error in parameters or arguments.\n";
|
||||
break;
|
||||
}
|
||||
Result = "501 Syntax error in parameters or arguments.\n";
|
||||
break;
|
||||
}
|
||||
case 502: {
|
||||
Result = "502 Command not implemented.\n";
|
||||
break;
|
||||
}
|
||||
Result = "502 Command not implemented.\n";
|
||||
break;
|
||||
}
|
||||
case 503: {
|
||||
Result = "503 Bad sequence of commands.\n";
|
||||
break;
|
||||
}
|
||||
Result = "503 Bad sequence of commands.\n";
|
||||
break;
|
||||
}
|
||||
case 504: {
|
||||
Result = "504 Command not implemented for that parameter.\n";
|
||||
break;
|
||||
}
|
||||
Result = "504 Command not implemented for that parameter.\n";
|
||||
break;
|
||||
}
|
||||
case 530: {
|
||||
Result = "530 Not logged in.\n";
|
||||
break;
|
||||
}
|
||||
Result = "530 Not logged in.\n";
|
||||
break;
|
||||
}
|
||||
case 550: {
|
||||
Result = "550 Requested action not taken.\n";
|
||||
break;
|
||||
}
|
||||
Result = "550 Requested action not taken.\n";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Result = "Error msg not implemented?\n";
|
||||
break;
|
||||
}
|
||||
Result = "Error msg not implemented?\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
|
10
lib/ftp.h
10
lib/ftp.h
|
@ -14,22 +14,22 @@
|
|||
namespace FTP {
|
||||
static std::string FTPBasePath = "/tmp/mist/OnDemand/";
|
||||
|
||||
enum Mode{
|
||||
enum Mode {
|
||||
MODE_STREAM,
|
||||
};
|
||||
//FTP::Mode enumeration
|
||||
|
||||
enum Structure{
|
||||
enum Structure {
|
||||
STRU_FILE, STRU_RECORD,
|
||||
};
|
||||
//FTP::Structure enumeration
|
||||
|
||||
enum Type{
|
||||
enum Type {
|
||||
TYPE_ASCII_NONPRINT, TYPE_IMAGE_NONPRINT,
|
||||
};
|
||||
//FTP::Type enumeration
|
||||
|
||||
enum Commands{
|
||||
enum Commands {
|
||||
CMD_NOCMD,
|
||||
CMD_NOOP,
|
||||
CMD_USER,
|
||||
|
@ -55,7 +55,7 @@ namespace FTP {
|
|||
};
|
||||
//FTP::Commands enumeration
|
||||
|
||||
class User{
|
||||
class User {
|
||||
public:
|
||||
User(Socket::Connection NewConnection, std::map<std::string, std::string> Credentials);
|
||||
~User();
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
/// 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(){
|
||||
HTTP::Parser::Parser() {
|
||||
headerOnly = false;
|
||||
Clean();
|
||||
}
|
||||
|
||||
/// Completely re-initializes the HTTP::Parser, leaving it ready for either reading or writing usage.
|
||||
void HTTP::Parser::Clean(){
|
||||
void HTTP::Parser::Clean() {
|
||||
seenHeaders = false;
|
||||
seenReq = false;
|
||||
getChunks = false;
|
||||
|
@ -30,16 +30,16 @@ void HTTP::Parser::Clean(){
|
|||
/// The request is build from internal variables set before this call is made.
|
||||
/// To be precise, method, url, protocol, headers and body are used.
|
||||
/// \return A string containing a valid HTTP 1.0 or 1.1 request, ready for sending.
|
||||
std::string & HTTP::Parser::BuildRequest(){
|
||||
std::string & HTTP::Parser::BuildRequest() {
|
||||
/// \todo Include GET/POST variable parsing?
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
if (protocol.size() < 5 || protocol[4] != '/'){
|
||||
if (protocol.size() < 5 || protocol[4] != '/') {
|
||||
protocol = "HTTP/1.0";
|
||||
}
|
||||
builder = method + " " + url + " " + protocol + "\r\n";
|
||||
for (it = headers.begin(); it != headers.end(); it++){
|
||||
if (( *it).first != "" && ( *it).second != ""){
|
||||
builder += ( *it).first + ": " + ( *it).second + "\r\n";
|
||||
for (it = headers.begin(); it != headers.end(); it++) {
|
||||
if ((*it).first != "" && (*it).second != "") {
|
||||
builder += (*it).first + ": " + (*it).second + "\r\n";
|
||||
}
|
||||
}
|
||||
builder += "\r\n" + body;
|
||||
|
@ -49,17 +49,17 @@ std::string & HTTP::Parser::BuildRequest(){
|
|||
/// Creates and sends a valid HTTP 1.0 or 1.1 request.
|
||||
/// The request is build from internal variables set before this call is made.
|
||||
/// To be precise, method, url, protocol, headers and body are used.
|
||||
void HTTP::Parser::SendRequest(Socket::Connection & conn){
|
||||
void HTTP::Parser::SendRequest(Socket::Connection & conn) {
|
||||
/// \todo Include GET/POST variable parsing?
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
if (protocol.size() < 5 || protocol[4] != '/'){
|
||||
if (protocol.size() < 5 || protocol[4] != '/') {
|
||||
protocol = "HTTP/1.0";
|
||||
}
|
||||
builder = method + " " + url + " " + protocol + "\r\n";
|
||||
conn.SendNow(builder);
|
||||
for (it = headers.begin(); it != headers.end(); it++){
|
||||
if (( *it).first != "" && ( *it).second != ""){
|
||||
builder = ( *it).first + ": " + ( *it).second + "\r\n";
|
||||
for (it = headers.begin(); it != headers.end(); it++) {
|
||||
if ((*it).first != "" && (*it).second != "") {
|
||||
builder = (*it).first + ": " + (*it).second + "\r\n";
|
||||
conn.SendNow(builder);
|
||||
}
|
||||
}
|
||||
|
@ -73,17 +73,17 @@ void HTTP::Parser::SendRequest(Socket::Connection & conn){
|
|||
/// \param code The HTTP response code. Usually you want 200.
|
||||
/// \param message The HTTP response message. Usually you want "OK".
|
||||
/// \return A string containing a valid HTTP 1.0 or 1.1 response, ready for sending.
|
||||
std::string & HTTP::Parser::BuildResponse(std::string code, std::string message){
|
||||
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[4] != '/'){
|
||||
if (protocol.size() < 5 || protocol[4] != '/') {
|
||||
protocol = "HTTP/1.0";
|
||||
}
|
||||
builder = protocol + " " + code + " " + message + "\r\n";
|
||||
for (it = headers.begin(); it != headers.end(); it++){
|
||||
if (( *it).first != "" && ( *it).second != ""){
|
||||
if (( *it).first != "Content-Length" || ( *it).second != "0"){
|
||||
builder += ( *it).first + ": " + ( *it).second + "\r\n";
|
||||
for (it = headers.begin(); it != headers.end(); it++) {
|
||||
if ((*it).first != "" && (*it).second != "") {
|
||||
if ((*it).first != "Content-Length" || (*it).second != "0") {
|
||||
builder += (*it).first + ": " + (*it).second + "\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,18 +99,18 @@ std::string & HTTP::Parser::BuildResponse(std::string code, std::string message)
|
|||
/// \param code The HTTP response code. Usually you want 200.
|
||||
/// \param message The HTTP response message. Usually you want "OK".
|
||||
/// \param conn The Socket::Connection to send the response over.
|
||||
void HTTP::Parser::SendResponse(std::string code, std::string message, Socket::Connection & conn){
|
||||
void HTTP::Parser::SendResponse(std::string code, std::string message, Socket::Connection & conn) {
|
||||
/// \todo Include GET/POST variable parsing?
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
if (protocol.size() < 5 || protocol[4] != '/'){
|
||||
if (protocol.size() < 5 || protocol[4] != '/') {
|
||||
protocol = "HTTP/1.0";
|
||||
}
|
||||
builder = protocol + " " + code + " " + message + "\r\n";
|
||||
conn.SendNow(builder);
|
||||
for (it = headers.begin(); it != headers.end(); it++){
|
||||
if (( *it).first != "" && ( *it).second != ""){
|
||||
if (( *it).first != "Content-Length" || ( *it).second != "0"){
|
||||
builder = ( *it).first + ": " + ( *it).second + "\r\n";
|
||||
for (it = headers.begin(); it != headers.end(); it++) {
|
||||
if ((*it).first != "" && (*it).second != "") {
|
||||
if ((*it).first != "Content-Length" || (*it).second != "0") {
|
||||
builder = (*it).first + ": " + (*it).second + "\r\n";
|
||||
conn.SendNow(builder);
|
||||
}
|
||||
}
|
||||
|
@ -126,12 +126,12 @@ void HTTP::Parser::SendResponse(std::string code, std::string message, Socket::C
|
|||
/// \param message The HTTP response message. Usually you want "OK".
|
||||
/// \param request The HTTP request to respond to.
|
||||
/// \param conn The connection to send over.
|
||||
void HTTP::Parser::StartResponse(std::string code, std::string message, HTTP::Parser & request, Socket::Connection & conn){
|
||||
void HTTP::Parser::StartResponse(std::string code, std::string message, HTTP::Parser & request, Socket::Connection & conn) {
|
||||
protocol = request.protocol;
|
||||
body = "";
|
||||
if (protocol == "HTTP/1.1"){
|
||||
if (protocol == "HTTP/1.1") {
|
||||
SetHeader("Transfer-Encoding", "chunked");
|
||||
}else{
|
||||
} else {
|
||||
SetBody("");
|
||||
}
|
||||
SendResponse(code, message, conn);
|
||||
|
@ -143,7 +143,7 @@ void HTTP::Parser::StartResponse(std::string code, std::string message, HTTP::Pa
|
|||
/// This call simply calls StartResponse("200", "OK", request, conn)
|
||||
/// \param request The HTTP request to respond to.
|
||||
/// \param conn The connection to send over.
|
||||
void HTTP::Parser::StartResponse(HTTP::Parser & request, Socket::Connection & conn){
|
||||
void HTTP::Parser::StartResponse(HTTP::Parser & request, Socket::Connection & conn) {
|
||||
StartResponse("200", "OK", request, conn);
|
||||
}
|
||||
|
||||
|
@ -152,29 +152,29 @@ void HTTP::Parser::StartResponse(HTTP::Parser & request, Socket::Connection & co
|
|||
/// - Retrieve all the body from the 'from' Socket::Connection.
|
||||
/// - Forward those contents as-is to the 'to' Socket::Connection.
|
||||
/// It blocks until completed or either of the connections reaches an error state.
|
||||
void HTTP::Parser::Proxy(Socket::Connection & from, Socket::Connection & to){
|
||||
void HTTP::Parser::Proxy(Socket::Connection & from, Socket::Connection & to) {
|
||||
SendResponse(url, method, to);
|
||||
if (getChunks){
|
||||
if (getChunks) {
|
||||
unsigned int proxyingChunk = 0;
|
||||
while (to.connected() && from.connected()){
|
||||
if ((from.Received().size() && (from.Received().size() > 1 || *(from.Received().get().rbegin()) == '\n')) || from.spool()){
|
||||
if (proxyingChunk){
|
||||
while (proxyingChunk && from.Received().size()){
|
||||
while (to.connected() && from.connected()) {
|
||||
if ((from.Received().size() && (from.Received().size() > 1 || *(from.Received().get().rbegin()) == '\n')) || from.spool()) {
|
||||
if (proxyingChunk) {
|
||||
while (proxyingChunk && from.Received().size()) {
|
||||
unsigned int toappend = from.Received().get().size();
|
||||
if (toappend > proxyingChunk){
|
||||
if (toappend > proxyingChunk) {
|
||||
toappend = proxyingChunk;
|
||||
to.SendNow(from.Received().get().c_str(), toappend);
|
||||
from.Received().get().erase(0, toappend);
|
||||
}else{
|
||||
} else {
|
||||
to.SendNow(from.Received().get());
|
||||
from.Received().get().clear();
|
||||
}
|
||||
proxyingChunk -= toappend;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
//Make sure the received data ends in a newline (\n).
|
||||
if ( *(from.Received().get().rbegin()) != '\n'){
|
||||
if (from.Received().size() > 1){
|
||||
if (*(from.Received().get().rbegin()) != '\n') {
|
||||
if (from.Received().size() > 1) {
|
||||
//make a copy of the first part
|
||||
std::string tmp = from.Received().get();
|
||||
//clear the first part, wiping it from the partlist
|
||||
|
@ -182,26 +182,26 @@ void HTTP::Parser::Proxy(Socket::Connection & from, Socket::Connection & to){
|
|||
from.Received().size();
|
||||
//take the now first (was second) part, insert the stored part in front of it
|
||||
from.Received().get().insert(0, tmp);
|
||||
}else{
|
||||
} else {
|
||||
Util::sleep(100);
|
||||
}
|
||||
if ( *(from.Received().get().rbegin()) != '\n'){
|
||||
if (*(from.Received().get().rbegin()) != '\n') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//forward the size and any empty lines
|
||||
to.SendNow(from.Received().get());
|
||||
|
||||
|
||||
std::string tmpA = from.Received().get().substr(0, from.Received().get().size() - 1);
|
||||
while (tmpA.find('\r') != std::string::npos){
|
||||
while (tmpA.find('\r') != std::string::npos) {
|
||||
tmpA.erase(tmpA.find('\r'));
|
||||
}
|
||||
unsigned int chunkLen = 0;
|
||||
if ( !tmpA.empty()){
|
||||
for (unsigned int i = 0; i < tmpA.size(); ++i){
|
||||
if (!tmpA.empty()) {
|
||||
for (unsigned int i = 0; i < tmpA.size(); ++i) {
|
||||
chunkLen = (chunkLen << 4) | unhex(tmpA[i]);
|
||||
}
|
||||
if (chunkLen == 0){
|
||||
if (chunkLen == 0) {
|
||||
getChunks = false;
|
||||
to.SendNow("\r\n", 2);
|
||||
return;
|
||||
|
@ -210,24 +210,24 @@ void HTTP::Parser::Proxy(Socket::Connection & from, Socket::Connection & to){
|
|||
}
|
||||
from.Received().get().clear();
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
Util::sleep(100);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
unsigned int bodyLen = length;
|
||||
while (bodyLen > 0 && to.connected() && from.connected()){
|
||||
if (from.Received().size() || from.spool()){
|
||||
if (from.Received().get().size() <= bodyLen){
|
||||
while (bodyLen > 0 && to.connected() && from.connected()) {
|
||||
if (from.Received().size() || from.spool()) {
|
||||
if (from.Received().get().size() <= bodyLen) {
|
||||
to.SendNow(from.Received().get());
|
||||
bodyLen -= from.Received().get().size();
|
||||
from.Received().get().clear();
|
||||
}else{
|
||||
} else {
|
||||
to.SendNow(from.Received().get().c_str(), bodyLen);
|
||||
from.Received().get().erase(0, bodyLen);
|
||||
bodyLen = 0;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
Util::sleep(100);
|
||||
}
|
||||
}
|
||||
|
@ -237,19 +237,19 @@ void HTTP::Parser::Proxy(Socket::Connection & from, Socket::Connection & to){
|
|||
/// Trims any whitespace at the front or back of the string.
|
||||
/// Used when getting/setting headers.
|
||||
/// \param s The string to trim. The string itself will be changed, not returned.
|
||||
void HTTP::Parser::Trim(std::string & s){
|
||||
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)){
|
||||
if ((std::string::npos == startpos) || (std::string::npos == endpos)) {
|
||||
s = "";
|
||||
}else{
|
||||
} 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.
|
||||
/// \param s The string to set the body to.
|
||||
void HTTP::Parser::SetBody(std::string s){
|
||||
void HTTP::Parser::SetBody(std::string s) {
|
||||
body = s;
|
||||
SetHeader("Content-Length", s.length());
|
||||
}
|
||||
|
@ -257,39 +257,39 @@ void HTTP::Parser::SetBody(std::string s){
|
|||
/// Function that sets the body of a response or request, along with the correct Content-Length header.
|
||||
/// \param buffer The buffer data to set the body to.
|
||||
/// \param len Length of the buffer data.
|
||||
void HTTP::Parser::SetBody(char * buffer, int len){
|
||||
void HTTP::Parser::SetBody(char * buffer, int len) {
|
||||
body = "";
|
||||
body.append(buffer, len);
|
||||
SetHeader("Content-Length", len);
|
||||
}
|
||||
|
||||
/// Returns header i, if set.
|
||||
std::string HTTP::Parser::getUrl(){
|
||||
if (url.find('?') != std::string::npos){
|
||||
std::string HTTP::Parser::getUrl() {
|
||||
if (url.find('?') != std::string::npos) {
|
||||
return url.substr(0, url.find('?'));
|
||||
}else{
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns header i, if set.
|
||||
std::string HTTP::Parser::GetHeader(std::string 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){
|
||||
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){
|
||||
void HTTP::Parser::SetHeader(std::string i, std::string v) {
|
||||
Trim(i);
|
||||
Trim(v);
|
||||
headers[i] = v;
|
||||
}
|
||||
|
||||
/// Sets header i to integer value v.
|
||||
void HTTP::Parser::SetHeader(std::string i, int v){
|
||||
void HTTP::Parser::SetHeader(std::string i, int v) {
|
||||
Trim(i);
|
||||
char val[23]; //ints are never bigger than 22 chars as decimal
|
||||
sprintf(val, "%i", v);
|
||||
|
@ -297,11 +297,11 @@ void HTTP::Parser::SetHeader(std::string i, int v){
|
|||
}
|
||||
|
||||
/// Sets POST variable i to string value v.
|
||||
void HTTP::Parser::SetVar(std::string i, std::string v){
|
||||
void HTTP::Parser::SetVar(std::string i, std::string v) {
|
||||
Trim(i);
|
||||
Trim(v);
|
||||
//only set if there is actually a key
|
||||
if ( !i.empty()){
|
||||
if (!i.empty()) {
|
||||
vars[i] = v;
|
||||
}
|
||||
}
|
||||
|
@ -311,10 +311,10 @@ void HTTP::Parser::SetVar(std::string i, std::string v){
|
|||
/// If not, as much as can be interpreted is removed and false returned.
|
||||
/// \param conn The socket to read from.
|
||||
/// \return True if a whole request or response was read, false otherwise.
|
||||
bool HTTP::Parser::Read(Socket::Connection & conn){
|
||||
bool HTTP::Parser::Read(Socket::Connection & conn) {
|
||||
//Make sure the received data ends in a newline (\n).
|
||||
while ((!seenHeaders || (getChunks && !doingChunk)) && *(conn.Received().get().rbegin()) != '\n'){
|
||||
if (conn.Received().size() > 1){
|
||||
while ((!seenHeaders || (getChunks && !doingChunk)) && *(conn.Received().get().rbegin()) != '\n') {
|
||||
if (conn.Received().size() > 1) {
|
||||
//make a copy of the first part
|
||||
std::string tmp = conn.Received().get();
|
||||
//clear the first part, wiping it from the partlist
|
||||
|
@ -322,16 +322,16 @@ bool HTTP::Parser::Read(Socket::Connection & conn){
|
|||
conn.Received().size();
|
||||
//take the now first (was second) part, insert the stored part in front of it
|
||||
conn.Received().get().insert(0, tmp);
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//if a parse succeeds, simply return true
|
||||
if (parse(conn.Received().get())){
|
||||
if (parse(conn.Received().get())) {
|
||||
return true;
|
||||
}
|
||||
//otherwise, if we have parts left, call ourselves recursively
|
||||
if (conn.Received().size()){
|
||||
if (conn.Received().size()) {
|
||||
return Read(conn);
|
||||
}
|
||||
return false;
|
||||
|
@ -342,7 +342,7 @@ bool HTTP::Parser::Read(Socket::Connection & conn){
|
|||
/// If not, as much as can be interpreted is removed and false returned.
|
||||
/// \param strbuf The buffer to read from.
|
||||
/// \return True if a whole request or response was read, false otherwise.
|
||||
bool HTTP::Parser::Read(std::string & strbuf){
|
||||
bool HTTP::Parser::Read(std::string & strbuf) {
|
||||
return parse(strbuf);
|
||||
} //HTTPReader::Read
|
||||
|
||||
|
@ -351,74 +351,74 @@ bool HTTP::Parser::Read(std::string & strbuf){
|
|||
/// from the data buffer.
|
||||
/// \param HTTPbuffer The data buffer to read from.
|
||||
/// \return True on success, false otherwise.
|
||||
bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
||||
bool HTTP::Parser::parse(std::string & HTTPbuffer) {
|
||||
size_t f;
|
||||
std::string tmpA, tmpB, tmpC;
|
||||
/// \todo Make this not resize HTTPbuffer in parts, but read all at once and then remove the entire request, like doxygen claims it does?
|
||||
while ( !HTTPbuffer.empty()){
|
||||
if ( !seenHeaders){
|
||||
while (!HTTPbuffer.empty()) {
|
||||
if (!seenHeaders) {
|
||||
f = HTTPbuffer.find('\n');
|
||||
if (f == std::string::npos) return false;
|
||||
tmpA = HTTPbuffer.substr(0, f);
|
||||
if (f + 1 == HTTPbuffer.size()){
|
||||
if (f + 1 == HTTPbuffer.size()) {
|
||||
HTTPbuffer.clear();
|
||||
}else{
|
||||
} else {
|
||||
HTTPbuffer.erase(0, f + 1);
|
||||
}
|
||||
while (tmpA.find('\r') != std::string::npos){
|
||||
while (tmpA.find('\r') != std::string::npos) {
|
||||
tmpA.erase(tmpA.find('\r'));
|
||||
}
|
||||
if ( !seenReq){
|
||||
if (!seenReq) {
|
||||
seenReq = true;
|
||||
f = tmpA.find(' ');
|
||||
if (f != std::string::npos){
|
||||
if (tmpA.substr(0, 4) == "HTTP"){
|
||||
if (f != std::string::npos) {
|
||||
if (tmpA.substr(0, 4) == "HTTP") {
|
||||
protocol = tmpA.substr(0, f);
|
||||
tmpA.erase(0, f + 1);
|
||||
f = tmpA.find(' ');
|
||||
if (f != std::string::npos){
|
||||
if (f != std::string::npos) {
|
||||
url = tmpA.substr(0, f);
|
||||
tmpA.erase(0, f + 1);
|
||||
method = tmpA;
|
||||
if (url.find('?') != std::string::npos){
|
||||
if (url.find('?') != std::string::npos) {
|
||||
parseVars(url.substr(url.find('?') + 1)); //parse GET variables
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
seenReq = false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
method = tmpA.substr(0, f);
|
||||
tmpA.erase(0, f + 1);
|
||||
f = tmpA.find(' ');
|
||||
if (f != std::string::npos){
|
||||
if (f != std::string::npos) {
|
||||
url = tmpA.substr(0, f);
|
||||
tmpA.erase(0, f + 1);
|
||||
protocol = tmpA;
|
||||
if (url.find('?') != std::string::npos){
|
||||
if (url.find('?') != std::string::npos) {
|
||||
parseVars(url.substr(url.find('?') + 1)); //parse GET variables
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
seenReq = false;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
seenReq = false;
|
||||
}
|
||||
}else{
|
||||
if (tmpA.size() == 0){
|
||||
} else {
|
||||
if (tmpA.size() == 0) {
|
||||
seenHeaders = true;
|
||||
body.clear();
|
||||
if (GetHeader("Content-Length") != ""){
|
||||
if (GetHeader("Content-Length") != "") {
|
||||
length = atoi(GetHeader("Content-Length").c_str());
|
||||
if (body.capacity() < length){
|
||||
if (body.capacity() < length) {
|
||||
body.reserve(length);
|
||||
}
|
||||
}
|
||||
if (GetHeader("Transfer-Encoding") == "chunked"){
|
||||
if (GetHeader("Transfer-Encoding") == "chunked") {
|
||||
getChunks = true;
|
||||
doingChunk = 0;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
f = tmpA.find(':');
|
||||
if (f == std::string::npos) continue;
|
||||
tmpB = tmpA.substr(0, f);
|
||||
|
@ -427,61 +427,61 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
|||
}
|
||||
}
|
||||
}
|
||||
if (seenHeaders){
|
||||
if (length > 0){
|
||||
if (headerOnly){
|
||||
if (seenHeaders) {
|
||||
if (length > 0) {
|
||||
if (headerOnly) {
|
||||
return true;
|
||||
}
|
||||
unsigned int toappend = length - body.length();
|
||||
if (toappend > 0){
|
||||
if (toappend > 0) {
|
||||
body.append(HTTPbuffer, 0, toappend);
|
||||
HTTPbuffer.erase(0, toappend);
|
||||
}
|
||||
if (length == body.length()){
|
||||
if (length == body.length()) {
|
||||
parseVars(body); //parse POST variables
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
if (getChunks){
|
||||
if (headerOnly){
|
||||
} else {
|
||||
if (getChunks) {
|
||||
if (headerOnly) {
|
||||
return true;
|
||||
}
|
||||
if (doingChunk){
|
||||
if (doingChunk) {
|
||||
unsigned int toappend = HTTPbuffer.size();
|
||||
if (toappend > doingChunk){
|
||||
if (toappend > doingChunk) {
|
||||
toappend = doingChunk;
|
||||
}
|
||||
body.append(HTTPbuffer, 0, toappend);
|
||||
HTTPbuffer.erase(0, toappend);
|
||||
doingChunk -= toappend;
|
||||
}else{
|
||||
} else {
|
||||
f = HTTPbuffer.find('\n');
|
||||
if (f == std::string::npos) return false;
|
||||
tmpA = HTTPbuffer.substr(0, f);
|
||||
while (tmpA.find('\r') != std::string::npos){
|
||||
while (tmpA.find('\r') != std::string::npos) {
|
||||
tmpA.erase(tmpA.find('\r'));
|
||||
}
|
||||
unsigned int chunkLen = 0;
|
||||
if ( !tmpA.empty()){
|
||||
for (unsigned int i = 0; i < tmpA.size(); ++i){
|
||||
if (!tmpA.empty()) {
|
||||
for (unsigned int i = 0; i < tmpA.size(); ++i) {
|
||||
chunkLen = (chunkLen << 4) | unhex(tmpA[i]);
|
||||
}
|
||||
if (chunkLen == 0){
|
||||
if (chunkLen == 0) {
|
||||
getChunks = false;
|
||||
return true;
|
||||
}
|
||||
doingChunk = chunkLen;
|
||||
}
|
||||
if (f + 1 == HTTPbuffer.size()){
|
||||
if (f + 1 == HTTPbuffer.size()) {
|
||||
HTTPbuffer.clear();
|
||||
}else{
|
||||
} else {
|
||||
HTTPbuffer.erase(0, f + 1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -492,28 +492,28 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
|||
|
||||
/// Parses GET or POST-style variable data.
|
||||
/// Saves to internal variable structure using HTTP::Parser::SetVar.
|
||||
void HTTP::Parser::parseVars(std::string data){
|
||||
void HTTP::Parser::parseVars(std::string data) {
|
||||
std::string varname;
|
||||
std::string varval;
|
||||
// position where a part start (e.g. after &)
|
||||
size_t pos = 0;
|
||||
while (pos < data.length()){
|
||||
while (pos < data.length()) {
|
||||
size_t nextpos = data.find('&', pos);
|
||||
if (nextpos == std::string::npos){
|
||||
if (nextpos == std::string::npos) {
|
||||
nextpos = data.length();
|
||||
}
|
||||
size_t eq_pos = data.find('=', pos);
|
||||
if (eq_pos < nextpos){
|
||||
if (eq_pos < nextpos) {
|
||||
// there is a key and value
|
||||
varname = data.substr(pos, eq_pos - pos);
|
||||
varval = data.substr(eq_pos + 1, nextpos - eq_pos - 1);
|
||||
}else{
|
||||
} else {
|
||||
// no value, only a key
|
||||
varname = data.substr(pos, nextpos - pos);
|
||||
varval.clear();
|
||||
}
|
||||
SetVar(urlunescape(varname), urlunescape(varval));
|
||||
if (nextpos == std::string::npos){
|
||||
if (nextpos == std::string::npos) {
|
||||
// in case the string is gigantic
|
||||
break;
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ void HTTP::Parser::parseVars(std::string data){
|
|||
/// Sends a string in chunked format if protocol is HTTP/1.1, sends as-is otherwise.
|
||||
/// \param bodypart The data to send.
|
||||
/// \param conn The connection to use for sending.
|
||||
void HTTP::Parser::Chunkify(std::string & bodypart, Socket::Connection & conn){
|
||||
void HTTP::Parser::Chunkify(std::string & bodypart, Socket::Connection & conn) {
|
||||
Chunkify(bodypart.c_str(), bodypart.size(), conn);
|
||||
}
|
||||
|
||||
|
@ -533,8 +533,8 @@ void HTTP::Parser::Chunkify(std::string & bodypart, Socket::Connection & conn){
|
|||
/// \param data The data to send.
|
||||
/// \param size The size of the data to send.
|
||||
/// \param conn The connection to use for sending.
|
||||
void HTTP::Parser::Chunkify(const char * data, unsigned int size, Socket::Connection & conn){
|
||||
if (protocol == "HTTP/1.1"){
|
||||
void HTTP::Parser::Chunkify(const char * data, unsigned int size, Socket::Connection & conn) {
|
||||
if (protocol == "HTTP/1.1") {
|
||||
char len[10];
|
||||
int sizelen = snprintf(len, 10, "%x\r\n", size);
|
||||
//prepend the chunk size and \r\n
|
||||
|
@ -543,39 +543,39 @@ void HTTP::Parser::Chunkify(const char * data, unsigned int size, Socket::Connec
|
|||
conn.SendNow(data, size);
|
||||
//append \r\n
|
||||
conn.SendNow("\r\n", 2);
|
||||
if ( !size){
|
||||
if (!size) {
|
||||
//append \r\n again if this was the end of the file (required by chunked transfer encoding according to spec)
|
||||
conn.SendNow("\r\n", 2);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
//just send the chunk itself
|
||||
conn.SendNow(data, size);
|
||||
//close the connection if this was the end of the file
|
||||
if ( !size){
|
||||
if (!size) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unescapes URLencoded std::string data.
|
||||
std::string HTTP::Parser::urlunescape(const std::string & in){
|
||||
std::string HTTP::Parser::urlunescape(const std::string & in) {
|
||||
std::string out;
|
||||
for (unsigned int i = 0; i < in.length(); ++i){
|
||||
if (in[i] == '%'){
|
||||
for (unsigned int i = 0; i < in.length(); ++i) {
|
||||
if (in[i] == '%') {
|
||||
char tmp = 0;
|
||||
++i;
|
||||
if (i < in.length()){
|
||||
if (i < in.length()) {
|
||||
tmp = unhex(in[i]) << 4;
|
||||
}
|
||||
++i;
|
||||
if (i < in.length()){
|
||||
if (i < in.length()) {
|
||||
tmp += unhex(in[i]);
|
||||
}
|
||||
out += tmp;
|
||||
}else{
|
||||
if (in[i] == '+'){
|
||||
} else {
|
||||
if (in[i] == '+') {
|
||||
out += ' ';
|
||||
}else{
|
||||
} else {
|
||||
out += in[i];
|
||||
}
|
||||
}
|
||||
|
@ -585,19 +585,19 @@ std::string HTTP::Parser::urlunescape(const std::string & in){
|
|||
|
||||
/// Helper function for urlunescape.
|
||||
/// Takes a single char input and outputs its integer hex value.
|
||||
int HTTP::Parser::unhex(char c){
|
||||
int HTTP::Parser::unhex(char c) {
|
||||
return (c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10);
|
||||
}
|
||||
|
||||
/// URLencodes std::string data.
|
||||
std::string HTTP::Parser::urlencode(const std::string &c){
|
||||
std::string HTTP::Parser::urlencode(const std::string & c) {
|
||||
std::string escaped = "";
|
||||
int max = c.length();
|
||||
for (int i = 0; i < max; i++){
|
||||
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] == '\'')){
|
||||
escaped.append( &c[i], 1);
|
||||
}else{
|
||||
|| (c[i] == '~' || c[i] == '!' || c[i] == '*' || c[i] == '(' || c[i] == ')' || c[i] == '\'')) {
|
||||
escaped.append(&c[i], 1);
|
||||
} else {
|
||||
escaped.append("%");
|
||||
escaped.append(hex(c[i]));
|
||||
}
|
||||
|
@ -607,7 +607,7 @@ std::string HTTP::Parser::urlencode(const std::string &c){
|
|||
|
||||
/// Helper function for urlescape.
|
||||
/// Encodes a character as two hex digits.
|
||||
std::string HTTP::Parser::hex(char dec){
|
||||
std::string HTTP::Parser::hex(char dec) {
|
||||
char dig1 = (dec & 0xF0) >> 4;
|
||||
char dig2 = (dec & 0x0F);
|
||||
if (dig1 <= 9) dig1 += 48;
|
||||
|
@ -615,7 +615,7 @@ std::string HTTP::Parser::hex(char dec){
|
|||
if (dig2 <= 9) dig2 += 48;
|
||||
if (10 <= dig2 && dig2 <= 15) dig2 += 97 - 10;
|
||||
std::string r;
|
||||
r.append( &dig1, 1);
|
||||
r.append( &dig2, 1);
|
||||
r.append(&dig1, 1);
|
||||
r.append(&dig2, 1);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
/// Holds all HTTP processing related code.
|
||||
namespace HTTP {
|
||||
/// Simple class for reading and writing HTTP 1.0 and 1.1.
|
||||
class Parser{
|
||||
class Parser {
|
||||
public:
|
||||
Parser();
|
||||
bool Read(Socket::Connection & conn);
|
||||
|
|
740
lib/json.cpp
740
lib/json.cpp
File diff suppressed because it is too large
Load diff
56
lib/json.h
56
lib/json.h
|
@ -17,7 +17,7 @@ namespace DTSC {
|
|||
namespace JSON {
|
||||
|
||||
/// Lists all types of JSON::Value.
|
||||
enum ValueType{
|
||||
enum ValueType {
|
||||
EMPTY, BOOL, INTEGER, STRING, ARRAY, OBJECT
|
||||
};
|
||||
|
||||
|
@ -28,9 +28,9 @@ namespace JSON {
|
|||
typedef std::deque<Value>::iterator ArrIter;
|
||||
typedef std::map<std::string, Value>::const_iterator ObjConstIter;
|
||||
typedef std::deque<Value>::const_iterator ArrConstIter;
|
||||
|
||||
|
||||
/// A JSON::Value is either a string or an integer, but may also be an object, array or null.
|
||||
class Value{
|
||||
class Value {
|
||||
private:
|
||||
ValueType myType;
|
||||
long long int intVal;
|
||||
|
@ -48,15 +48,15 @@ namespace JSON {
|
|||
Value(long long int val);
|
||||
Value(bool val);
|
||||
//comparison operators
|
||||
bool operator==(const Value &rhs) const;
|
||||
bool operator!=(const Value &rhs) const;
|
||||
bool operator==(const Value & rhs) const;
|
||||
bool operator!=(const Value & rhs) const;
|
||||
//assignment operators
|
||||
Value & operator=(const std::string &rhs);
|
||||
Value & operator=(const std::string & rhs);
|
||||
Value & operator=(const char * rhs);
|
||||
Value & operator=(const long long int &rhs);
|
||||
Value & operator=(const int &rhs);
|
||||
Value & operator=(const unsigned int &rhs);
|
||||
Value & operator=(const bool &rhs);
|
||||
Value & operator=(const long long int & rhs);
|
||||
Value & operator=(const int & rhs);
|
||||
Value & operator=(const unsigned int & rhs);
|
||||
Value & operator=(const bool & rhs);
|
||||
//converts to basic types
|
||||
operator long long int() const;
|
||||
operator std::string() const;
|
||||
|
@ -105,22 +105,22 @@ namespace JSON {
|
|||
};
|
||||
|
||||
Value fromDTMI2(std::string & data);
|
||||
Value fromDTMI2(const unsigned char * data, unsigned int len, unsigned int &i);
|
||||
Value fromDTMI2(const unsigned char * data, unsigned int len, unsigned int & i);
|
||||
Value fromDTMI(std::string & data);
|
||||
Value fromDTMI(const unsigned char * data, unsigned int len, unsigned int &i);
|
||||
Value fromDTMI(const unsigned char * data, unsigned int len, unsigned int & i);
|
||||
Value fromString(std::string json);
|
||||
Value fromFile(std::string filename);
|
||||
void fromDTMI2(std::string & data, Value & ret);
|
||||
void fromDTMI2(const unsigned char * data, unsigned int len, unsigned int &i, Value & ret);
|
||||
void fromDTMI2(const unsigned char * data, unsigned int len, unsigned int & i, Value & ret);
|
||||
void fromDTMI(std::string & data, Value & ret);
|
||||
void fromDTMI(const unsigned char * data, unsigned int len, unsigned int &i, Value & ret);
|
||||
|
||||
void fromDTMI(const unsigned char * data, unsigned int len, unsigned int & i, Value & ret);
|
||||
|
||||
template <typename T>
|
||||
std::string encodeVector(T begin, T end){
|
||||
std::string encodeVector(T begin, T end) {
|
||||
std::string result;
|
||||
for( T it = begin; it != end; it++){
|
||||
for (T it = begin; it != end; it++) {
|
||||
long long int tmp = (*it);
|
||||
while(tmp >= 0xFFFF){
|
||||
while (tmp >= 0xFFFF) {
|
||||
result += (char)0xFF;
|
||||
result += (char)0xFF;
|
||||
tmp -= 0xFFFF;
|
||||
|
@ -132,13 +132,13 @@ namespace JSON {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void decodeVector( std::string input, T & result ){
|
||||
void decodeVector(std::string input, T & result) {
|
||||
result.clear();
|
||||
unsigned int tmp = 0;
|
||||
for( int i = 0; i < input.size(); i += 2){
|
||||
for (int i = 0; i < input.size(); i += 2) {
|
||||
unsigned int curLen = (input[i] << 8) + input[i + 1];
|
||||
tmp += curLen;
|
||||
if (curLen != 0xFFFF){
|
||||
if (curLen != 0xFFFF) {
|
||||
result.push_back(tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
|
@ -146,11 +146,11 @@ namespace JSON {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
std::string encodeVector4(T begin, T end){
|
||||
std::string encodeVector4(T begin, T end) {
|
||||
std::string result;
|
||||
for( T it = begin; it != end; it++){
|
||||
for (T it = begin; it != end; it++) {
|
||||
long long int tmp = (*it);
|
||||
while(tmp >= 0xFFFFFFFF){
|
||||
while (tmp >= 0xFFFFFFFF) {
|
||||
result += (char)0xFF;
|
||||
result += (char)0xFF;
|
||||
result += (char)0xFF;
|
||||
|
@ -166,13 +166,13 @@ namespace JSON {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void decodeVector4( std::string input, T & result ){
|
||||
void decodeVector4(std::string input, T & result) {
|
||||
result.clear();
|
||||
unsigned int tmp = 0;
|
||||
for( int i = 0; i < input.size(); i += 4){
|
||||
unsigned int curLen = (input[i] << 24) + (input[i+1] << 16) + (input[i+2] << 8) + (input[i+3]);
|
||||
for (int i = 0; i < input.size(); i += 4) {
|
||||
unsigned int curLen = (input[i] << 24) + (input[i + 1] << 16) + (input[i + 2] << 8) + (input[i + 3]);
|
||||
tmp += curLen;
|
||||
if (curLen != 0xFFFFFFFF){
|
||||
if (curLen != 0xFFFFFFFF) {
|
||||
result.push_back(tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
|
|
490
lib/mp4.cpp
490
lib/mp4.cpp
|
@ -16,148 +16,148 @@ namespace MP4 {
|
|||
/// If manage is set to true, the pointer will be realloc'ed when the box needs to be resized.
|
||||
/// If the datapointer is NULL, manage is assumed to be true even if explicitly given as false.
|
||||
/// If managed, the pointer will be free'd upon destruction.
|
||||
Box::Box(char * datapointer, bool manage){
|
||||
|
||||
Box::Box(char * datapointer, bool manage) {
|
||||
|
||||
data = datapointer;
|
||||
managed = manage;
|
||||
payloadOffset = 8;
|
||||
if (data == 0){
|
||||
if (data == 0) {
|
||||
clear();
|
||||
}else{
|
||||
data_size = ntohl(((int*)data)[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Box::Box(const Box & rs){
|
||||
data = rs.data;
|
||||
managed = false;
|
||||
payloadOffset = rs.payloadOffset;
|
||||
if (data == 0){
|
||||
clear();
|
||||
}else{
|
||||
data_size = ntohl(((int*)data)[0]);
|
||||
} else {
|
||||
data_size = ntohl(((int *)data)[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Box& Box::operator = (const Box & rs){
|
||||
Box::Box(const Box & rs) {
|
||||
data = rs.data;
|
||||
managed = false;
|
||||
payloadOffset = rs.payloadOffset;
|
||||
if (data == 0) {
|
||||
clear();
|
||||
} else {
|
||||
data_size = ntohl(((int *)data)[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Box & Box::operator = (const Box & rs) {
|
||||
clear();
|
||||
data = rs.data;
|
||||
managed = false;
|
||||
payloadOffset = rs.payloadOffset;
|
||||
if (data == 0){
|
||||
if (data == 0) {
|
||||
clear();
|
||||
}else{
|
||||
data_size = ntohl(((int*)data)[0]);
|
||||
} else {
|
||||
data_size = ntohl(((int *)data)[0]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// If managed, this will free the data pointer.
|
||||
Box::~Box(){
|
||||
if (managed && data != 0){
|
||||
Box::~Box() {
|
||||
if (managed && data != 0) {
|
||||
free(data);
|
||||
data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the values at byte positions 4 through 7.
|
||||
std::string Box::getType(){
|
||||
std::string Box::getType() {
|
||||
return std::string(data + 4, 4);
|
||||
}
|
||||
|
||||
/// Returns true if the given 4-byte boxtype is equal to the values at byte positions 4 through 7.
|
||||
bool Box::isType(const char* boxType){
|
||||
bool Box::isType(const char * boxType) {
|
||||
return !memcmp(boxType, data + 4, 4);
|
||||
}
|
||||
|
||||
/// Reads the first 8 bytes and returns
|
||||
std::string readBoxType(FILE * newData){
|
||||
/// Reads the first 8 bytes and returns
|
||||
std::string readBoxType(FILE * newData) {
|
||||
char retVal[8] = {0, 0, 0, 0, 'e', 'r', 'r', 'o'};
|
||||
long long unsigned int pos = ftell(newData);
|
||||
fread(retVal,8,1,newData);
|
||||
fseek (newData,pos,SEEK_SET);
|
||||
return std::string(retVal+4,4);
|
||||
fread(retVal, 8, 1, newData);
|
||||
fseek(newData, pos, SEEK_SET);
|
||||
return std::string(retVal + 4, 4);
|
||||
}
|
||||
|
||||
///\todo make good working calcBoxSize with size and payloadoffset calculation
|
||||
unsigned long int calcBoxSize(char readVal[16]){
|
||||
unsigned long int calcBoxSize(char readVal[16]) {
|
||||
return (readVal[0] << 24) | (readVal[1] << 16) | (readVal[2] << 8) | (readVal[3]);
|
||||
}
|
||||
|
||||
bool skipBox(FILE * newData){
|
||||
bool skipBox(FILE * newData) {
|
||||
char readVal[16];
|
||||
long long unsigned int pos = ftell(newData);
|
||||
if (fread(readVal,4,1,newData)){
|
||||
if (fread(readVal, 4, 1, newData)) {
|
||||
uint64_t size = calcBoxSize(readVal);
|
||||
if (size==1){
|
||||
if (fread(readVal+4,12,1,newData)){
|
||||
size = 0 + ntohl(((int*)readVal)[2]);
|
||||
if (size == 1) {
|
||||
if (fread(readVal + 4, 12, 1, newData)) {
|
||||
size = 0 + ntohl(((int *)readVal)[2]);
|
||||
size <<= 32;
|
||||
size += ntohl(((int*)readVal)[3]);
|
||||
}else{
|
||||
size += ntohl(((int *)readVal)[3]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}else if (size==0){
|
||||
} else if (size == 0) {
|
||||
fseek(newData, 0, SEEK_END);
|
||||
}
|
||||
DEBUG_MSG(DLVL_DEVEL,"skipping size 0x%0.8X",size);
|
||||
if (fseek(newData, pos + size, SEEK_SET)==0){
|
||||
DEBUG_MSG(DLVL_DEVEL, "skipping size 0x%0.8X", size);
|
||||
if (fseek(newData, pos + size, SEEK_SET) == 0) {
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Box::read(FILE* newData){
|
||||
bool Box::read(FILE * newData) {
|
||||
char readVal[16];
|
||||
long long unsigned int pos = ftell(newData);
|
||||
if (fread(readVal,4,1,newData)){
|
||||
if (fread(readVal, 4, 1, newData)) {
|
||||
payloadOffset = 8;
|
||||
uint64_t size = calcBoxSize(readVal);
|
||||
if (size==1){
|
||||
if (fread(readVal+4,12,1,newData)){
|
||||
size = 0 + ntohl(((int*)readVal)[2]);
|
||||
if (size == 1) {
|
||||
if (fread(readVal + 4, 12, 1, newData)) {
|
||||
size = 0 + ntohl(((int *)readVal)[2]);
|
||||
size <<= 32;
|
||||
size += ntohl(((int*)readVal)[3]);
|
||||
size += ntohl(((int *)readVal)[3]);
|
||||
payloadOffset = 16;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fseek (newData,pos,SEEK_SET);
|
||||
data = (char*)realloc(data, size);
|
||||
fseek(newData, pos, SEEK_SET);
|
||||
data = (char *)realloc(data, size);
|
||||
data_size = size;
|
||||
return (fread(data,size,1,newData) == 1);
|
||||
}else{
|
||||
return (fread(data, size, 1, newData) == 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads out a whole box (if possible) from newData, copying to the internal data storage and removing from the input string.
|
||||
/// \returns True on success, false otherwise.
|
||||
bool Box::read(std::string & newData){
|
||||
if ( !managed){
|
||||
bool Box::read(std::string & newData) {
|
||||
if (!managed) {
|
||||
return false;
|
||||
}
|
||||
if (newData.size() > 4){
|
||||
if (newData.size() > 4) {
|
||||
payloadOffset = 8;
|
||||
uint64_t size = ntohl(((int*)newData.c_str())[0]);
|
||||
if (size == 1){
|
||||
if (newData.size() > 16){
|
||||
size = 0 + ntohl(((int*)newData.c_str())[2]);
|
||||
uint64_t size = ntohl(((int *)newData.c_str())[0]);
|
||||
if (size == 1) {
|
||||
if (newData.size() > 16) {
|
||||
size = 0 + ntohl(((int *)newData.c_str())[2]);
|
||||
size <<= 32;
|
||||
size += ntohl(((int*)newData.c_str())[3]);
|
||||
size += ntohl(((int *)newData.c_str())[3]);
|
||||
payloadOffset = 16;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (newData.size() >= size){
|
||||
data = (char*)realloc(data, size);
|
||||
if (newData.size() >= size) {
|
||||
data = (char *)realloc(data, size);
|
||||
data_size = size;
|
||||
memcpy(data, newData.data(), size);
|
||||
newData.erase(0, size);
|
||||
|
@ -168,207 +168,207 @@ namespace MP4 {
|
|||
}
|
||||
|
||||
/// Returns the total boxed size of this box, including the header.
|
||||
uint64_t Box::boxedSize(){
|
||||
if (payloadOffset == 16){
|
||||
return ((uint64_t)ntohl(((int*)data)[2]) << 32) + ntohl(((int*)data)[3]);
|
||||
uint64_t Box::boxedSize() {
|
||||
if (payloadOffset == 16) {
|
||||
return ((uint64_t)ntohl(((int *)data)[2]) << 32) + ntohl(((int *)data)[3]);
|
||||
}
|
||||
return ntohl(((int*)data)[0]);
|
||||
return ntohl(((int *)data)[0]);
|
||||
}
|
||||
|
||||
/// Retruns the size of the payload of thix box, excluding the header.
|
||||
/// This value is defined as boxedSize() - 8.
|
||||
uint64_t Box::payloadSize(){
|
||||
uint64_t Box::payloadSize() {
|
||||
return boxedSize() - payloadOffset;
|
||||
}
|
||||
|
||||
/// Returns a copy of the data pointer.
|
||||
char * Box::asBox(){
|
||||
char * Box::asBox() {
|
||||
return data;
|
||||
}
|
||||
|
||||
char * Box::payload(){
|
||||
char * Box::payload() {
|
||||
return data + payloadOffset;
|
||||
}
|
||||
|
||||
/// Makes this box managed if it wasn't already, resetting the internal storage to 8 bytes (the minimum).
|
||||
/// If this box wasn't managed, the original data is left intact - otherwise it is free'd.
|
||||
/// If it was somehow impossible to allocate 8 bytes (should never happen), this will cause segfaults later.
|
||||
void Box::clear(){
|
||||
if (data && managed){
|
||||
void Box::clear() {
|
||||
if (data && managed) {
|
||||
free(data);
|
||||
}
|
||||
managed = true;
|
||||
payloadOffset = 8;
|
||||
data = (char*)malloc(8);
|
||||
if (data){
|
||||
data = (char *)malloc(8);
|
||||
if (data) {
|
||||
data_size = 8;
|
||||
((int*)data)[0] = htonl(data_size);
|
||||
}else{
|
||||
((int *)data)[0] = htonl(data_size);
|
||||
} else {
|
||||
data_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to typecast this Box to a more specific type and call the toPrettyString() function of that type.
|
||||
/// If this failed, it will print out a message saying pretty-printing is not implemented for boxtype.
|
||||
std::string Box::toPrettyString(uint32_t indent){
|
||||
switch (ntohl( *((int*)(data + 4)))){ //type is at this address
|
||||
std::string Box::toPrettyString(uint32_t indent) {
|
||||
switch (ntohl(*((int *)(data + 4)))) { //type is at this address
|
||||
case 0x6D666864:
|
||||
return ((MFHD*)this)->toPrettyString(indent);
|
||||
return ((MFHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D6F6F66:
|
||||
return ((MOOF*)this)->toPrettyString(indent);
|
||||
return ((MOOF *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x61627374:
|
||||
return ((ABST*)this)->toPrettyString(indent);
|
||||
return ((ABST *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x61667274:
|
||||
return ((AFRT*)this)->toPrettyString(indent);
|
||||
return ((AFRT *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x61667261:
|
||||
return ((AFRA*)this)->toPrettyString(indent);
|
||||
return ((AFRA *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x61737274:
|
||||
return ((ASRT*)this)->toPrettyString(indent);
|
||||
return ((ASRT *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x7472756E:
|
||||
return ((TRUN*)this)->toPrettyString(indent);
|
||||
return ((TRUN *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x74726166:
|
||||
return ((TRAF*)this)->toPrettyString(indent);
|
||||
return ((TRAF *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x74666864:
|
||||
return ((TFHD*)this)->toPrettyString(indent);
|
||||
return ((TFHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x61766343:
|
||||
return ((AVCC*)this)->toPrettyString(indent);
|
||||
return ((AVCC *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x73647470:
|
||||
return ((SDTP*)this)->toPrettyString(indent);
|
||||
return ((SDTP *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x66747970:
|
||||
return ((FTYP*)this)->toPrettyString(indent);
|
||||
return ((FTYP *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D6F6F76:
|
||||
return ((MOOV*)this)->toPrettyString(indent);
|
||||
return ((MOOV *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D766578:
|
||||
return ((MVEX*)this)->toPrettyString(indent);
|
||||
return ((MVEX *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x74726578:
|
||||
return ((TREX*)this)->toPrettyString(indent);
|
||||
return ((TREX *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D667261:
|
||||
return ((MFRA*)this)->toPrettyString(indent);
|
||||
return ((MFRA *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x7472616B:
|
||||
return ((TRAK*)this)->toPrettyString(indent);
|
||||
return ((TRAK *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D646961:
|
||||
return ((MDIA*)this)->toPrettyString(indent);
|
||||
return ((MDIA *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D696E66:
|
||||
return ((MINF*)this)->toPrettyString(indent);
|
||||
return ((MINF *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x64696E66:
|
||||
return ((DINF*)this)->toPrettyString(indent);
|
||||
return ((DINF *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D66726F:
|
||||
return ((MFRO*)this)->toPrettyString(indent);
|
||||
return ((MFRO *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x68646C72:
|
||||
return ((HDLR*)this)->toPrettyString(indent);
|
||||
return ((HDLR *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x766D6864:
|
||||
return ((VMHD*)this)->toPrettyString(indent);
|
||||
return ((VMHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x736D6864:
|
||||
return ((SMHD*)this)->toPrettyString(indent);
|
||||
return ((SMHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x686D6864:
|
||||
return ((HMHD*)this)->toPrettyString(indent);
|
||||
return ((HMHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6E6D6864:
|
||||
return ((NMHD*)this)->toPrettyString(indent);
|
||||
return ((NMHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D656864:
|
||||
return ((MEHD*)this)->toPrettyString(indent);
|
||||
return ((MEHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x7374626C:
|
||||
return ((STBL*)this)->toPrettyString(indent);
|
||||
return ((STBL *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x64726566:
|
||||
return ((DREF*)this)->toPrettyString(indent);
|
||||
return ((DREF *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x75726C20:
|
||||
return ((URL*)this)->toPrettyString(indent);
|
||||
return ((URL *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x75726E20:
|
||||
return ((URN*)this)->toPrettyString(indent);
|
||||
return ((URN *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D766864:
|
||||
return ((MVHD*)this)->toPrettyString(indent);
|
||||
return ((MVHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x74667261:
|
||||
return ((TFRA*)this)->toPrettyString(indent);
|
||||
return ((TFRA *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x746B6864:
|
||||
return ((TKHD*)this)->toPrettyString(indent);
|
||||
return ((TKHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D646864:
|
||||
return ((MDHD*)this)->toPrettyString(indent);
|
||||
return ((MDHD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x73747473:
|
||||
return ((STTS*)this)->toPrettyString(indent);
|
||||
return ((STTS *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x63747473:
|
||||
return ((CTTS*)this)->toPrettyString(indent);
|
||||
return ((CTTS *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x73747363:
|
||||
return ((STSC*)this)->toPrettyString(indent);
|
||||
return ((STSC *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x7374636F:
|
||||
return ((STCO*)this)->toPrettyString(indent);
|
||||
return ((STCO *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x7374737A:
|
||||
return ((STSZ*)this)->toPrettyString(indent);
|
||||
return ((STSZ *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x73747364:
|
||||
return ((STSD*)this)->toPrettyString(indent);
|
||||
return ((STSD *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D703461://mp4a
|
||||
case 0x656E6361://enca
|
||||
return ((MP4A*)this)->toPrettyString(indent);
|
||||
return ((MP4A *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x61616320:
|
||||
return ((AAC*)this)->toPrettyString(indent);
|
||||
return ((AAC *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x61766331:
|
||||
return ((AVC1*)this)->toPrettyString(indent);
|
||||
return ((AVC1 *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x68323634://h264
|
||||
case 0x656E6376://encv
|
||||
return ((H264*)this)->toPrettyString(indent);
|
||||
return ((H264 *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x65647473:
|
||||
return ((EDTS*)this)->toPrettyString(indent);
|
||||
return ((EDTS *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x73747373:
|
||||
return ((STSS*)this)->toPrettyString(indent);
|
||||
return ((STSS *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x6D657461:
|
||||
return ((META*)this)->toPrettyString(indent);
|
||||
return ((META *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x656C7374:
|
||||
return ((ELST*)this)->toPrettyString(indent);
|
||||
return ((ELST *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x65736473:
|
||||
return ((ESDS*)this)->toPrettyString(indent);
|
||||
return ((ESDS *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x75647461:
|
||||
return ((UDTA*)this)->toPrettyString(indent);
|
||||
return ((UDTA *)this)->toPrettyString(indent);
|
||||
break;
|
||||
case 0x75756964:
|
||||
return ((UUID*)this)->toPrettyString(indent);
|
||||
return ((UUID *)this)->toPrettyString(indent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -381,10 +381,10 @@ namespace MP4 {
|
|||
/// Sets the 8 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Fails silently if resizing failed.
|
||||
void Box::setInt8(char newData, size_t index){
|
||||
void Box::setInt8(char newData, size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index >= boxedSize()){
|
||||
if ( !reserve(index, 0, 1)){
|
||||
if (index >= boxedSize()) {
|
||||
if (!reserve(index, 0, 1)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -394,10 +394,10 @@ namespace MP4 {
|
|||
/// Gets the 8 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Returns zero if resizing failed.
|
||||
char Box::getInt8(size_t index){
|
||||
char Box::getInt8(size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index >= boxedSize()){
|
||||
if ( !reserve(index, 0, 1)){
|
||||
if (index >= boxedSize()) {
|
||||
if (!reserve(index, 0, 1)) {
|
||||
return 0;
|
||||
}
|
||||
setInt8(0, index - payloadOffset);
|
||||
|
@ -408,40 +408,40 @@ namespace MP4 {
|
|||
/// Sets the 16 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Fails silently if resizing failed.
|
||||
void Box::setInt16(short newData, size_t index){
|
||||
void Box::setInt16(short newData, size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index + 1 >= boxedSize()){
|
||||
if ( !reserve(index, 0, 2)){
|
||||
if (index + 1 >= boxedSize()) {
|
||||
if (!reserve(index, 0, 2)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
newData = htons(newData);
|
||||
memcpy(data + index, (char*) &newData, 2);
|
||||
memcpy(data + index, (char *) &newData, 2);
|
||||
}
|
||||
|
||||
/// Gets the 16 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Returns zero if resizing failed.
|
||||
short Box::getInt16(size_t index){
|
||||
short Box::getInt16(size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index + 1 >= boxedSize()){
|
||||
if ( !reserve(index, 0, 2)){
|
||||
if (index + 1 >= boxedSize()) {
|
||||
if (!reserve(index, 0, 2)) {
|
||||
return 0;
|
||||
}
|
||||
setInt16(0, index - payloadOffset);
|
||||
}
|
||||
short result;
|
||||
memcpy((char*) &result, data + index, 2);
|
||||
memcpy((char *) &result, data + index, 2);
|
||||
return ntohs(result);
|
||||
}
|
||||
|
||||
/// Sets the 24 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Fails silently if resizing failed.
|
||||
void Box::setInt24(uint32_t newData, size_t index){
|
||||
void Box::setInt24(uint32_t newData, size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index + 2 >= boxedSize()){
|
||||
if ( !reserve(index, 0, 3)){
|
||||
if (index + 2 >= boxedSize()) {
|
||||
if (!reserve(index, 0, 3)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -453,10 +453,10 @@ namespace MP4 {
|
|||
/// Gets the 24 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Returns zero if resizing failed.
|
||||
uint32_t Box::getInt24(size_t index){
|
||||
uint32_t Box::getInt24(size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index + 2 >= boxedSize()){
|
||||
if ( !reserve(index, 0, 3)){
|
||||
if (index + 2 >= boxedSize()) {
|
||||
if (!reserve(index, 0, 3)) {
|
||||
return 0;
|
||||
}
|
||||
setInt24(0, index - payloadOffset);
|
||||
|
@ -472,84 +472,84 @@ namespace MP4 {
|
|||
/// Sets the 32 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Fails silently if resizing failed.
|
||||
void Box::setInt32(uint32_t newData, size_t index){
|
||||
void Box::setInt32(uint32_t newData, size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index + 3 >= boxedSize()){
|
||||
if ( !reserve(index, 0, 4)){
|
||||
if (index + 3 >= boxedSize()) {
|
||||
if (!reserve(index, 0, 4)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
newData = htonl(newData);
|
||||
memcpy(data + index, (char*) &newData, 4);
|
||||
memcpy(data + index, (char *) &newData, 4);
|
||||
}
|
||||
|
||||
/// Gets the 32 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Returns zero if resizing failed.
|
||||
uint32_t Box::getInt32(size_t index){
|
||||
uint32_t Box::getInt32(size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index + 3 >= boxedSize()){
|
||||
if ( !reserve(index, 0, 4)){
|
||||
if (index + 3 >= boxedSize()) {
|
||||
if (!reserve(index, 0, 4)) {
|
||||
return 0;
|
||||
}
|
||||
setInt32(0, index - payloadOffset);
|
||||
}
|
||||
uint32_t result;
|
||||
memcpy((char*) &result, data + index, 4);
|
||||
memcpy((char *) &result, data + index, 4);
|
||||
return ntohl(result);
|
||||
}
|
||||
|
||||
/// Sets the 64 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Fails silently if resizing failed.
|
||||
void Box::setInt64(uint64_t newData, size_t index){
|
||||
void Box::setInt64(uint64_t newData, size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index + 7 >= boxedSize()){
|
||||
if ( !reserve(index, 0, 8)){
|
||||
if (index + 7 >= boxedSize()) {
|
||||
if (!reserve(index, 0, 8)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
((int*)(data + index))[0] = htonl((int)(newData >> 32));
|
||||
((int*)(data + index))[1] = htonl((int)(newData & 0xFFFFFFFF));
|
||||
((int *)(data + index))[0] = htonl((int)(newData >> 32));
|
||||
((int *)(data + index))[1] = htonl((int)(newData & 0xFFFFFFFF));
|
||||
}
|
||||
|
||||
/// Gets the 64 bits integer at the given index.
|
||||
/// Attempts to resize the data pointer if the index is out of range.
|
||||
/// Returns zero if resizing failed.
|
||||
uint64_t Box::getInt64(size_t index){
|
||||
uint64_t Box::getInt64(size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index + 7 >= boxedSize()){
|
||||
if ( !reserve(index, 0, 8)){
|
||||
if (index + 7 >= boxedSize()) {
|
||||
if (!reserve(index, 0, 8)) {
|
||||
return 0;
|
||||
}
|
||||
setInt64(0, index - payloadOffset);
|
||||
}
|
||||
uint64_t result = ntohl(((int*)(data + index))[0]);
|
||||
uint64_t result = ntohl(((int *)(data + index))[0]);
|
||||
result <<= 32;
|
||||
result += ntohl(((int*)(data + index))[1]);
|
||||
result += ntohl(((int *)(data + index))[1]);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Sets the NULL-terminated string at the given index.
|
||||
/// Will attempt to resize if the string doesn't fit.
|
||||
/// Fails silently if resizing failed.
|
||||
void Box::setString(std::string newData, size_t index){
|
||||
setString((char*)newData.c_str(), newData.size(), index);
|
||||
void Box::setString(std::string newData, size_t index) {
|
||||
setString((char *)newData.c_str(), newData.size(), index);
|
||||
}
|
||||
|
||||
/// Sets the NULL-terminated string at the given index.
|
||||
/// Will attempt to resize if the string doesn't fit.
|
||||
/// Fails silently if resizing failed.
|
||||
void Box::setString(char* newData, size_t size, size_t index){
|
||||
void Box::setString(char * newData, size_t size, size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index >= boxedSize()){
|
||||
if ( !reserve(index, 0, 1)){
|
||||
if (index >= boxedSize()) {
|
||||
if (!reserve(index, 0, 1)) {
|
||||
return;
|
||||
}
|
||||
data[index] = 0;
|
||||
}
|
||||
if (getStringLen(index) != size){
|
||||
if ( !reserve(index, getStringLen(index) + 1, size + 1)){
|
||||
if (getStringLen(index) != size) {
|
||||
if (!reserve(index, getStringLen(index) + 1, size + 1)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -559,10 +559,10 @@ namespace MP4 {
|
|||
/// Gets the NULL-terminated string at the given index.
|
||||
/// Will attempt to resize if the string is out of range.
|
||||
/// Returns null if resizing failed.
|
||||
char * Box::getString(size_t index){
|
||||
char * Box::getString(size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index >= boxedSize()){
|
||||
if ( !reserve(index, 0, 1)){
|
||||
if (index >= boxedSize()) {
|
||||
if (!reserve(index, 0, 1)) {
|
||||
return 0;
|
||||
}
|
||||
data[index] = 0;
|
||||
|
@ -572,9 +572,9 @@ namespace MP4 {
|
|||
|
||||
/// Returns the length of the NULL-terminated string at the given index.
|
||||
/// Returns 0 if out of range.
|
||||
size_t Box::getStringLen(size_t index){
|
||||
size_t Box::getStringLen(size_t index) {
|
||||
index += payloadOffset;
|
||||
if (index >= boxedSize()){
|
||||
if (index >= boxedSize()) {
|
||||
return 0;
|
||||
}
|
||||
return strlen(data + index);
|
||||
|
@ -584,12 +584,12 @@ namespace MP4 {
|
|||
/// Do not store or copy this reference, for there will be raptors.
|
||||
/// Will attempt to resize if out of range.
|
||||
/// Returns an 8-byte error box if resizing failed.
|
||||
Box & Box::getBox(size_t index){
|
||||
static Box retbox = Box((char*)"\000\000\000\010erro", false);
|
||||
Box & Box::getBox(size_t index) {
|
||||
static Box retbox = Box((char *)"\000\000\000\010erro", false);
|
||||
index += payloadOffset;
|
||||
if (index + 8 > boxedSize()){
|
||||
if ( !reserve(index, 0, 8)){
|
||||
retbox = Box((char*)"\000\000\000\010erro", false);
|
||||
if (index + 8 > boxedSize()) {
|
||||
if (!reserve(index, 0, 8)) {
|
||||
retbox = Box((char *)"\000\000\000\010erro", false);
|
||||
return retbox;
|
||||
}
|
||||
memcpy(data + index, "\000\000\000\010erro", 8);
|
||||
|
@ -601,8 +601,8 @@ namespace MP4 {
|
|||
/// Returns the size of the box at the given position.
|
||||
/// Returns undefined values if there is no box at the given position.
|
||||
/// Returns 0 if out of range.
|
||||
size_t Box::getBoxLen(size_t index){
|
||||
if ((index + payloadOffset + 8) > boxedSize()){
|
||||
size_t Box::getBoxLen(size_t index) {
|
||||
if ((index + payloadOffset + 8) > boxedSize()) {
|
||||
return 0;
|
||||
}
|
||||
return getBox(index).boxedSize();
|
||||
|
@ -610,10 +610,10 @@ namespace MP4 {
|
|||
|
||||
/// Replaces the existing box at the given index by the new box newEntry.
|
||||
/// Will resize if needed, will reserve new space if out of range.
|
||||
void Box::setBox(Box & newEntry, size_t index){
|
||||
void Box::setBox(Box & newEntry, size_t index) {
|
||||
int oldlen = getBoxLen(index);
|
||||
int newlen = newEntry.boxedSize();
|
||||
if (oldlen != newlen && !reserve(index + payloadOffset, oldlen, newlen)){
|
||||
if (oldlen != newlen && !reserve(index + payloadOffset, oldlen, newlen)) {
|
||||
return;
|
||||
}
|
||||
memcpy(data + index + payloadOffset, newEntry.asBox(), newlen);
|
||||
|
@ -622,90 +622,90 @@ namespace MP4 {
|
|||
/// Attempts to reserve enough space for wanted bytes of data at given position, where current bytes of data is now reserved.
|
||||
/// This will move any existing data behind the currently reserved space to the proper location after reserving.
|
||||
/// \returns True on success, false otherwise.
|
||||
bool Box::reserve(size_t position, size_t current, size_t wanted){
|
||||
if (current == wanted){
|
||||
bool Box::reserve(size_t position, size_t current, size_t wanted) {
|
||||
if (current == wanted) {
|
||||
return true;
|
||||
}
|
||||
if (position > boxedSize()){
|
||||
if (position > boxedSize()) {
|
||||
wanted += position - boxedSize();
|
||||
}
|
||||
if (current < wanted){
|
||||
if (current < wanted) {
|
||||
//make bigger
|
||||
if (boxedSize() + (wanted - current) > data_size){
|
||||
if (boxedSize() + (wanted - current) > data_size) {
|
||||
//realloc if managed, otherwise fail
|
||||
if ( !managed){
|
||||
if (!managed) {
|
||||
return false;
|
||||
}
|
||||
void * ret = realloc(data, boxedSize() + (wanted - current));
|
||||
if ( !ret){
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
data = (char*)ret;
|
||||
data = (char *)ret;
|
||||
memset(data + boxedSize(), 0, wanted - current); //initialize to 0
|
||||
data_size = boxedSize() + (wanted - current);
|
||||
}
|
||||
}
|
||||
//move data behind, if any
|
||||
if (boxedSize() > (position + current)){
|
||||
if (boxedSize() > (position + current)) {
|
||||
memmove(data + position + wanted, data + position + current, boxedSize() - (position + current));
|
||||
}
|
||||
//calculate and set new size
|
||||
if (payloadOffset != 16){
|
||||
if (payloadOffset != 16) {
|
||||
int newSize = boxedSize() + (wanted - current);
|
||||
((int*)data)[0] = htonl(newSize);
|
||||
((int *)data)[0] = htonl(newSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fullBox::fullBox(){
|
||||
|
||||
fullBox::fullBox() {
|
||||
setVersion(0);
|
||||
}
|
||||
|
||||
void fullBox::setVersion(char newVersion){
|
||||
|
||||
void fullBox::setVersion(char newVersion) {
|
||||
setInt8(newVersion, 0);
|
||||
}
|
||||
|
||||
char fullBox::getVersion(){
|
||||
char fullBox::getVersion() {
|
||||
return getInt8(0);
|
||||
}
|
||||
|
||||
void fullBox::setFlags(uint32_t newFlags){
|
||||
void fullBox::setFlags(uint32_t newFlags) {
|
||||
setInt24(newFlags, 1);
|
||||
}
|
||||
|
||||
uint32_t fullBox::getFlags(){
|
||||
uint32_t fullBox::getFlags() {
|
||||
return getInt24(1);
|
||||
}
|
||||
|
||||
std::string fullBox::toPrettyString(uint32_t indent){
|
||||
|
||||
std::string fullBox::toPrettyString(uint32_t indent) {
|
||||
std::stringstream r;
|
||||
r << std::string(indent + 1, ' ') << "Version: " << (int)getVersion() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Flags: " << getFlags() << std::endl;
|
||||
return r.str();
|
||||
}
|
||||
|
||||
containerBox::containerBox(){
|
||||
|
||||
containerBox::containerBox() {
|
||||
|
||||
}
|
||||
|
||||
uint32_t containerBox::getContentCount(){
|
||||
|
||||
uint32_t containerBox::getContentCount() {
|
||||
int res = 0;
|
||||
unsigned int tempLoc = 0;
|
||||
while (tempLoc < boxedSize() - 8){
|
||||
while (tempLoc < boxedSize() - 8) {
|
||||
res++;
|
||||
tempLoc += Box(getBox(tempLoc).asBox(), false).boxedSize();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void containerBox::setContent(Box & newContent, uint32_t no){
|
||||
void containerBox::setContent(Box & newContent, uint32_t no) {
|
||||
int tempLoc = 0;
|
||||
unsigned int contentCount = getContentCount();
|
||||
for (unsigned int i = 0; i < no; i++){
|
||||
if (i < contentCount){
|
||||
for (unsigned int i = 0; i < no; i++) {
|
||||
if (i < contentCount) {
|
||||
tempLoc += getBoxLen(tempLoc);
|
||||
}else{
|
||||
if ( !reserve(tempLoc, 0, (no - contentCount) * 8)){
|
||||
} else {
|
||||
if (!reserve(tempLoc, 0, (no - contentCount) * 8)) {
|
||||
return;
|
||||
};
|
||||
memset(data + tempLoc, 0, (no - contentCount) * 8);
|
||||
|
@ -716,27 +716,27 @@ namespace MP4 {
|
|||
setBox(newContent, tempLoc);
|
||||
}
|
||||
|
||||
Box & containerBox::getContent(uint32_t no){
|
||||
static Box ret = Box((char*)"\000\000\000\010erro", false);
|
||||
if (no > getContentCount()){
|
||||
Box & containerBox::getContent(uint32_t no) {
|
||||
static Box ret = Box((char *)"\000\000\000\010erro", false);
|
||||
if (no > getContentCount()) {
|
||||
return ret;
|
||||
}
|
||||
unsigned int i = 0;
|
||||
int tempLoc = 0;
|
||||
while (i < no){
|
||||
while (i < no) {
|
||||
tempLoc += getBoxLen(tempLoc);
|
||||
i++;
|
||||
}
|
||||
return getBox(tempLoc);
|
||||
}
|
||||
|
||||
std::string containerBox::toPrettyString(uint32_t indent){
|
||||
|
||||
std::string containerBox::toPrettyString(uint32_t indent) {
|
||||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << "[" << getType() <<"] Container Box (" << boxedSize() << ")" << std::endl;
|
||||
r << std::string(indent, ' ') << "[" << getType() << "] Container Box (" << boxedSize() << ")" << std::endl;
|
||||
Box curBox;
|
||||
int tempLoc = 0;
|
||||
int contentCount = getContentCount();
|
||||
for (int i = 0; i < contentCount; i++){
|
||||
for (int i = 0; i < contentCount; i++) {
|
||||
curBox = getContent(i);
|
||||
r << curBox.toPrettyString(indent + 1);
|
||||
tempLoc += getBoxLen(tempLoc);
|
||||
|
@ -744,24 +744,24 @@ namespace MP4 {
|
|||
return r.str();
|
||||
}
|
||||
|
||||
uint32_t containerFullBox::getContentCount(){
|
||||
uint32_t containerFullBox::getContentCount() {
|
||||
int res = 0;
|
||||
unsigned int tempLoc = 4;
|
||||
while (tempLoc < boxedSize() - 8){
|
||||
while (tempLoc < boxedSize() - 8) {
|
||||
res++;
|
||||
tempLoc += getBoxLen(tempLoc);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void containerFullBox::setContent(Box & newContent, uint32_t no){
|
||||
|
||||
void containerFullBox::setContent(Box & newContent, uint32_t no) {
|
||||
int tempLoc = 4;
|
||||
unsigned int contentCount = getContentCount();
|
||||
for (unsigned int i = 0; i < no; i++){
|
||||
if (i < contentCount){
|
||||
for (unsigned int i = 0; i < no; i++) {
|
||||
if (i < contentCount) {
|
||||
tempLoc += getBoxLen(tempLoc);
|
||||
}else{
|
||||
if ( !reserve(tempLoc, 0, (no - contentCount) * 8)){
|
||||
} else {
|
||||
if (!reserve(tempLoc, 0, (no - contentCount) * 8)) {
|
||||
return;
|
||||
};
|
||||
memset(data + tempLoc, 0, (no - contentCount) * 8);
|
||||
|
@ -771,29 +771,29 @@ namespace MP4 {
|
|||
}
|
||||
setBox(newContent, tempLoc);
|
||||
}
|
||||
|
||||
Box & containerFullBox::getContent(uint32_t no){
|
||||
static Box ret = Box((char*)"\000\000\000\010erro", false);
|
||||
if (no > getContentCount()){
|
||||
|
||||
Box & containerFullBox::getContent(uint32_t no) {
|
||||
static Box ret = Box((char *)"\000\000\000\010erro", false);
|
||||
if (no > getContentCount()) {
|
||||
return ret;
|
||||
}
|
||||
unsigned int i = 0;
|
||||
int tempLoc = 4;
|
||||
while (i < no){
|
||||
while (i < no) {
|
||||
tempLoc += getBoxLen(tempLoc);
|
||||
i++;
|
||||
}
|
||||
return getBox(tempLoc);
|
||||
}
|
||||
|
||||
std::string containerFullBox::toPrettyCFBString(uint32_t indent, std::string boxName){
|
||||
|
||||
std::string containerFullBox::toPrettyCFBString(uint32_t indent, std::string boxName) {
|
||||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << boxName <<" (" << boxedSize() << ")" << std::endl;
|
||||
r << std::string(indent, ' ') << boxName << " (" << boxedSize() << ")" << std::endl;
|
||||
r << fullBox::toPrettyString(indent);
|
||||
Box curBox;
|
||||
int tempLoc = 4;
|
||||
int contentCount = getContentCount();
|
||||
for (int i = 0; i < contentCount; i++){
|
||||
for (int i = 0; i < contentCount; i++) {
|
||||
curBox = getContent(i);
|
||||
r << curBox.toPrettyString(indent + 1);
|
||||
tempLoc += getBoxLen(tempLoc);
|
||||
|
|
24
lib/mp4.h
24
lib/mp4.h
|
@ -18,16 +18,16 @@ namespace MP4 {
|
|||
std::string readBoxType(FILE * newData);
|
||||
bool skipBox(FILE * newData);
|
||||
|
||||
|
||||
class Box{
|
||||
|
||||
class Box {
|
||||
public:
|
||||
Box(char * datapointer = 0, bool manage = true);
|
||||
Box(const Box & rs);
|
||||
Box& operator = (const Box & rs);
|
||||
Box & operator = (const Box & rs);
|
||||
~Box();
|
||||
std::string getType();
|
||||
bool isType(const char* boxType);
|
||||
bool read(FILE* newData);
|
||||
bool isType(const char * boxType);
|
||||
bool read(FILE * newData);
|
||||
bool read(std::string & newData);
|
||||
uint64_t boxedSize();
|
||||
uint64_t payloadSize();
|
||||
|
@ -49,7 +49,7 @@ namespace MP4 {
|
|||
uint64_t getInt64(size_t index);
|
||||
//string functions
|
||||
void setString(std::string newData, size_t index);
|
||||
void setString(char* newData, size_t size, size_t index);
|
||||
void setString(char * newData, size_t size, size_t index);
|
||||
char * getString(size_t index);
|
||||
size_t getStringLen(size_t index);
|
||||
//box functions
|
||||
|
@ -65,8 +65,8 @@ namespace MP4 {
|
|||
unsigned int payloadOffset; ///<The offset of the payload with regards to the data
|
||||
};
|
||||
//Box Class
|
||||
|
||||
class fullBox: public Box{
|
||||
|
||||
class fullBox: public Box {
|
||||
public:
|
||||
fullBox();
|
||||
void setVersion(char newVersion);
|
||||
|
@ -75,8 +75,8 @@ namespace MP4 {
|
|||
uint32_t getFlags();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class containerBox: public Box{
|
||||
|
||||
class containerBox: public Box {
|
||||
public:
|
||||
containerBox();
|
||||
uint32_t getContentCount();
|
||||
|
@ -84,8 +84,8 @@ namespace MP4 {
|
|||
Box & getContent(uint32_t no);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class containerFullBox: public fullBox{
|
||||
|
||||
class containerFullBox: public fullBox {
|
||||
public:
|
||||
uint32_t getContentCount();
|
||||
void setContent(Box & newContent, uint32_t no);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,17 +4,17 @@
|
|||
|
||||
namespace MP4 {
|
||||
//class Box;
|
||||
|
||||
struct afrt_runtable{
|
||||
uint32_t firstFragment;
|
||||
uint64_t firstTimestamp;
|
||||
uint32_t duration;
|
||||
uint32_t discontinuity;
|
||||
|
||||
struct afrt_runtable {
|
||||
uint32_t firstFragment;
|
||||
uint64_t firstTimestamp;
|
||||
uint32_t duration;
|
||||
uint32_t discontinuity;
|
||||
};
|
||||
//fragmentRun
|
||||
|
||||
/// AFRT Box class
|
||||
class AFRT: public Box{
|
||||
class AFRT: public Box {
|
||||
public:
|
||||
AFRT();
|
||||
void setVersion(char newVersion);
|
||||
|
@ -33,13 +33,13 @@ namespace MP4 {
|
|||
};
|
||||
//AFRT Box
|
||||
|
||||
struct asrt_runtable{
|
||||
uint32_t firstSegment;
|
||||
uint32_t fragmentsPerSegment;
|
||||
struct asrt_runtable {
|
||||
uint32_t firstSegment;
|
||||
uint32_t fragmentsPerSegment;
|
||||
};
|
||||
|
||||
/// ASRT Box class
|
||||
class ASRT: public Box{
|
||||
class ASRT: public Box {
|
||||
public:
|
||||
ASRT();
|
||||
void setVersion(char newVersion);
|
||||
|
@ -48,7 +48,7 @@ namespace MP4 {
|
|||
uint32_t getUpdate();
|
||||
uint32_t getQualityEntryCount();
|
||||
void setQualityEntry(std::string & newQuality, uint32_t no);
|
||||
const char* getQualityEntry(uint32_t no);
|
||||
const char * getQualityEntry(uint32_t no);
|
||||
uint32_t getSegmentRunEntryCount();
|
||||
void setSegmentRun(uint32_t firstSegment, uint32_t fragmentsPerSegment, uint32_t no);
|
||||
asrt_runtable getSegmentRun(uint32_t no);
|
||||
|
@ -57,7 +57,7 @@ namespace MP4 {
|
|||
//ASRT Box
|
||||
|
||||
/// ABST Box class
|
||||
class ABST: public Box{
|
||||
class ABST: public Box {
|
||||
public:
|
||||
ABST();
|
||||
void setVersion(char newVersion);
|
||||
|
@ -100,18 +100,18 @@ namespace MP4 {
|
|||
};
|
||||
//ABST Box
|
||||
|
||||
struct afraentry{
|
||||
uint64_t time;
|
||||
uint64_t offset;
|
||||
struct afraentry {
|
||||
uint64_t time;
|
||||
uint64_t offset;
|
||||
};
|
||||
struct globalafraentry{
|
||||
uint64_t time;
|
||||
uint32_t segment;
|
||||
uint32_t fragment;
|
||||
uint64_t afraoffset;
|
||||
uint64_t offsetfromafra;
|
||||
struct globalafraentry {
|
||||
uint64_t time;
|
||||
uint32_t segment;
|
||||
uint32_t fragment;
|
||||
uint64_t afraoffset;
|
||||
uint64_t offsetfromafra;
|
||||
};
|
||||
class AFRA: public Box{
|
||||
class AFRA: public Box {
|
||||
public:
|
||||
AFRA();
|
||||
void setVersion(uint32_t newVersion);
|
||||
|
|
2230
lib/mp4_generic.cpp
2230
lib/mp4_generic.cpp
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
#include "mp4.h"
|
||||
|
||||
namespace MP4{
|
||||
class MFHD: public Box{
|
||||
namespace MP4 {
|
||||
class MFHD: public Box {
|
||||
public:
|
||||
MFHD();
|
||||
void setSequenceNumber(uint32_t newSequenceNumber);
|
||||
|
@ -10,13 +10,13 @@ namespace MP4{
|
|||
};
|
||||
//MFHD Box
|
||||
|
||||
class MOOF: public containerBox{
|
||||
class MOOF: public containerBox {
|
||||
public:
|
||||
MOOF();
|
||||
};
|
||||
//MOOF Box
|
||||
|
||||
class TRAF: public Box{
|
||||
class TRAF: public Box {
|
||||
public:
|
||||
TRAF();
|
||||
uint32_t getContentCount();
|
||||
|
@ -26,13 +26,13 @@ namespace MP4{
|
|||
};
|
||||
//TRAF Box
|
||||
|
||||
struct trunSampleInformation{
|
||||
uint32_t sampleDuration;
|
||||
uint32_t sampleSize;
|
||||
uint32_t sampleFlags;
|
||||
uint32_t sampleOffset;
|
||||
struct trunSampleInformation {
|
||||
uint32_t sampleDuration;
|
||||
uint32_t sampleSize;
|
||||
uint32_t sampleFlags;
|
||||
uint32_t sampleOffset;
|
||||
};
|
||||
enum trunflags{
|
||||
enum trunflags {
|
||||
trundataOffset = 0x00000001,
|
||||
trunfirstSampleFlags = 0x00000004,
|
||||
trunsampleDuration = 0x00000100,
|
||||
|
@ -40,7 +40,7 @@ namespace MP4{
|
|||
trunsampleFlags = 0x00000400,
|
||||
trunsampleOffsets = 0x00000800
|
||||
};
|
||||
enum sampleflags{
|
||||
enum sampleflags {
|
||||
noIPicture = 0x01000000,
|
||||
isIPicture = 0x02000000,
|
||||
noDisposable = 0x00400000,
|
||||
|
@ -52,7 +52,7 @@ namespace MP4{
|
|||
MUST_BE_PRESENT = 0x1
|
||||
};
|
||||
std::string prettySampleFlags(uint32_t flag);
|
||||
class TRUN: public Box{
|
||||
class TRUN: public Box {
|
||||
public:
|
||||
TRUN();
|
||||
void setFlags(uint32_t newFlags);
|
||||
|
@ -67,7 +67,7 @@ namespace MP4{
|
|||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
enum tfhdflags{
|
||||
enum tfhdflags {
|
||||
tfhdBaseOffset = 0x000001,
|
||||
tfhdSampleDesc = 0x000002,
|
||||
tfhdSampleDura = 0x000008,
|
||||
|
@ -75,7 +75,7 @@ namespace MP4{
|
|||
tfhdSampleFlag = 0x000020,
|
||||
tfhdNoDuration = 0x010000,
|
||||
};
|
||||
class TFHD: public Box{
|
||||
class TFHD: public Box {
|
||||
public:
|
||||
TFHD();
|
||||
void setFlags(uint32_t newFlags);
|
||||
|
@ -96,7 +96,7 @@ namespace MP4{
|
|||
};
|
||||
|
||||
|
||||
class AVCC: public Box{
|
||||
class AVCC: public Box {
|
||||
public:
|
||||
AVCC();
|
||||
void setVersion(uint32_t newVersion);
|
||||
|
@ -111,19 +111,19 @@ namespace MP4{
|
|||
uint32_t getSPSNumber();
|
||||
void setSPS(std::string newSPS);
|
||||
uint32_t getSPSLen();
|
||||
char* getSPS();
|
||||
char * getSPS();
|
||||
void setPPSNumber(uint32_t newPPSNumber);
|
||||
uint32_t getPPSNumber();
|
||||
void setPPS(std::string newPPS);
|
||||
uint32_t getPPSLen();
|
||||
char* getPPS();
|
||||
char * getPPS();
|
||||
std::string asAnnexB();
|
||||
void setPayload(std::string newPayload);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
|
||||
///\todo : ESDS is filthy implemented, clean up when optimising
|
||||
class ESDS: public fullBox{
|
||||
class ESDS: public fullBox {
|
||||
public:
|
||||
ESDS();
|
||||
ESDS(std::string init, uint32_t bps);
|
||||
|
@ -180,8 +180,8 @@ namespace MP4{
|
|||
void setSLValue(char newVal);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class FTYP: public Box{
|
||||
|
||||
class FTYP: public Box {
|
||||
public:
|
||||
FTYP();
|
||||
void setMajorBrand(const char * newMajorBrand);
|
||||
|
@ -193,18 +193,18 @@ namespace MP4{
|
|||
std::string getCompatibleBrands(size_t index);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class MOOV: public containerBox{
|
||||
|
||||
class MOOV: public containerBox {
|
||||
public:
|
||||
MOOV();
|
||||
};
|
||||
|
||||
class MVEX: public containerBox{
|
||||
|
||||
class MVEX: public containerBox {
|
||||
public:
|
||||
MVEX();
|
||||
};
|
||||
|
||||
class TREX: public Box{
|
||||
|
||||
class TREX: public Box {
|
||||
public:
|
||||
TREX();
|
||||
void setTrackID(uint32_t newTrackID);
|
||||
|
@ -219,34 +219,34 @@ namespace MP4{
|
|||
uint32_t getDefaultSampleFlags();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
|
||||
class MFRA: public containerBox{
|
||||
|
||||
|
||||
class MFRA: public containerBox {
|
||||
public:
|
||||
MFRA();
|
||||
};
|
||||
|
||||
class TRAK: public containerBox{
|
||||
class TRAK: public containerBox {
|
||||
public:
|
||||
TRAK();
|
||||
};
|
||||
|
||||
class MDIA: public containerBox{
|
||||
|
||||
class MDIA: public containerBox {
|
||||
public:
|
||||
MDIA();
|
||||
};
|
||||
|
||||
class MINF: public containerBox{
|
||||
class MINF: public containerBox {
|
||||
public:
|
||||
MINF();
|
||||
};
|
||||
|
||||
class DINF: public containerBox{
|
||||
class DINF: public containerBox {
|
||||
public:
|
||||
DINF();
|
||||
};
|
||||
|
||||
class MFRO: public Box{
|
||||
class MFRO: public Box {
|
||||
public:
|
||||
MFRO();
|
||||
void setSize(uint32_t newSize);
|
||||
|
@ -254,7 +254,7 @@ namespace MP4{
|
|||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class HDLR: public Box{
|
||||
class HDLR: public Box {
|
||||
public:
|
||||
HDLR(std::string & type, std::string name);
|
||||
void setHandlerType(const char * newHandlerType);
|
||||
|
@ -264,7 +264,7 @@ namespace MP4{
|
|||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class VMHD: public fullBox{
|
||||
class VMHD: public fullBox {
|
||||
public:
|
||||
VMHD();
|
||||
void setGraphicsMode(uint16_t newGraphicsMode);
|
||||
|
@ -274,16 +274,16 @@ namespace MP4{
|
|||
uint16_t getOpColor(size_t index);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class SMHD: public fullBox{
|
||||
|
||||
class SMHD: public fullBox {
|
||||
public:
|
||||
SMHD();
|
||||
void setBalance(int16_t newBalance);
|
||||
int16_t getBalance();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class HMHD: public fullBox{
|
||||
|
||||
class HMHD: public fullBox {
|
||||
public:
|
||||
HMHD();
|
||||
void setMaxPDUSize(uint16_t newMaxPDUSize);
|
||||
|
@ -296,27 +296,27 @@ namespace MP4{
|
|||
uint32_t getAvgBitRate();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class NMHD: public fullBox{
|
||||
|
||||
class NMHD: public fullBox {
|
||||
public:
|
||||
NMHD();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class MEHD: public fullBox{
|
||||
|
||||
class MEHD: public fullBox {
|
||||
public:
|
||||
MEHD();
|
||||
void setFragmentDuration(uint64_t newFragmentDuration);
|
||||
uint64_t getFragmentDuration();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class STBL: public containerBox{
|
||||
|
||||
class STBL: public containerBox {
|
||||
public:
|
||||
STBL();
|
||||
};
|
||||
|
||||
class URL: public fullBox{
|
||||
|
||||
class URL: public fullBox {
|
||||
public:
|
||||
URL();
|
||||
void setLocation(std::string newLocation);
|
||||
|
@ -324,7 +324,7 @@ namespace MP4{
|
|||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class URN: public fullBox{
|
||||
class URN: public fullBox {
|
||||
public:
|
||||
URN();
|
||||
void setName(std::string newName);
|
||||
|
@ -333,8 +333,8 @@ namespace MP4{
|
|||
std::string getLocation();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class DREF: public fullBox{
|
||||
|
||||
class DREF: public fullBox {
|
||||
public:
|
||||
DREF();
|
||||
uint32_t getEntryCount();
|
||||
|
@ -342,8 +342,8 @@ namespace MP4{
|
|||
Box & getDataEntry(size_t index);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class MVHD: public fullBox{
|
||||
|
||||
class MVHD: public fullBox {
|
||||
public:
|
||||
MVHD(long long unsigned int duration);
|
||||
void setCreationTime(uint64_t newCreationTime);
|
||||
|
@ -365,16 +365,16 @@ namespace MP4{
|
|||
uint32_t getTrackID();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
struct TFRAEntry{
|
||||
|
||||
struct TFRAEntry {
|
||||
uint64_t time;
|
||||
uint64_t moofOffset;
|
||||
uint32_t trafNumber;
|
||||
uint32_t trunNumber;
|
||||
uint32_t sampleNumber;
|
||||
};
|
||||
|
||||
class TFRA: public fullBox{
|
||||
|
||||
class TFRA: public fullBox {
|
||||
public:
|
||||
TFRA();
|
||||
void setTrackID(uint32_t newTrackID);
|
||||
|
@ -392,8 +392,8 @@ namespace MP4{
|
|||
uint32_t getTFRAEntrySize();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class TKHD: public fullBox{
|
||||
|
||||
class TKHD: public fullBox {
|
||||
public:
|
||||
TKHD(uint32_t trackId, uint64_t duration, uint32_t width, uint32_t height);
|
||||
void setCreationTime(uint64_t newCreationTime);
|
||||
|
@ -422,8 +422,8 @@ namespace MP4{
|
|||
uint32_t getHeight();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class MDHD: public fullBox{
|
||||
|
||||
class MDHD: public fullBox {
|
||||
public:
|
||||
MDHD(uint64_t duration);
|
||||
void setCreationTime(uint64_t newCreationTime);
|
||||
|
@ -439,13 +439,13 @@ namespace MP4{
|
|||
uint16_t getLanguage();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
struct STTSEntry{
|
||||
|
||||
struct STTSEntry {
|
||||
uint32_t sampleCount;
|
||||
uint32_t sampleDelta;
|
||||
};
|
||||
|
||||
class STTS: public fullBox{
|
||||
|
||||
class STTS: public fullBox {
|
||||
public:
|
||||
STTS(char v = 1, uint32_t f = 0);
|
||||
void setEntryCount(uint32_t newEntryCount);
|
||||
|
@ -454,13 +454,13 @@ namespace MP4{
|
|||
STTSEntry getSTTSEntry(uint32_t no);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
struct CTTSEntry{
|
||||
|
||||
struct CTTSEntry {
|
||||
uint32_t sampleCount;
|
||||
uint32_t sampleOffset;
|
||||
};
|
||||
|
||||
class CTTS: public fullBox{
|
||||
class CTTS: public fullBox {
|
||||
public:
|
||||
CTTS();
|
||||
void setEntryCount(uint32_t newEntryCount);
|
||||
|
@ -469,14 +469,14 @@ namespace MP4{
|
|||
CTTSEntry getCTTSEntry(uint32_t no);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
struct STSCEntry{
|
||||
|
||||
struct STSCEntry {
|
||||
uint32_t firstChunk;
|
||||
uint32_t samplesPerChunk;
|
||||
uint32_t sampleDescriptionIndex;
|
||||
};
|
||||
|
||||
class STSC: public fullBox{
|
||||
|
||||
class STSC: public fullBox {
|
||||
public:
|
||||
STSC(char v = 1, uint32_t f = 0);
|
||||
void setEntryCount(uint32_t newEntryCount);
|
||||
|
@ -485,8 +485,8 @@ namespace MP4{
|
|||
STSCEntry getSTSCEntry(uint32_t no);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class STCO: public fullBox{
|
||||
|
||||
class STCO: public fullBox {
|
||||
public:
|
||||
STCO(char v = 1, uint32_t f = 0);
|
||||
void setEntryCount(uint32_t newEntryCount);
|
||||
|
@ -495,8 +495,8 @@ namespace MP4{
|
|||
uint32_t getChunkOffset(uint32_t no);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class STSZ: public fullBox{
|
||||
|
||||
class STSZ: public fullBox {
|
||||
public:
|
||||
STSZ(char v = 1, uint32_t f = 0);
|
||||
void setSampleSize(uint32_t newSampleSize);
|
||||
|
@ -507,16 +507,16 @@ namespace MP4{
|
|||
uint32_t getEntrySize(uint32_t no);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class SampleEntry: public Box{
|
||||
|
||||
class SampleEntry: public Box {
|
||||
public:
|
||||
SampleEntry();
|
||||
void setDataReferenceIndex(uint16_t newDataReferenceIndex);
|
||||
uint16_t getDataReferenceIndex();
|
||||
std::string toPrettySampleString(uint32_t index);
|
||||
};
|
||||
|
||||
class CLAP: public Box{//CleanApertureBox
|
||||
|
||||
class CLAP: public Box { //CleanApertureBox
|
||||
public:
|
||||
CLAP();
|
||||
void setCleanApertureWidthN(uint32_t newVal);
|
||||
|
@ -538,7 +538,7 @@ namespace MP4{
|
|||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class PASP: public Box{ //PixelAspectRatioBox
|
||||
class PASP: public Box { //PixelAspectRatioBox
|
||||
public:
|
||||
PASP();
|
||||
void setHSpacing(uint32_t newVal);
|
||||
|
@ -547,19 +547,19 @@ namespace MP4{
|
|||
uint32_t getVSpacing();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class VisualSampleEntry: public SampleEntry{
|
||||
///\todo set default values
|
||||
|
||||
class VisualSampleEntry: public SampleEntry {
|
||||
///\todo set default values
|
||||
public:
|
||||
VisualSampleEntry();
|
||||
void setCodec(const char* newCodec);
|
||||
void setCodec(const char * newCodec);
|
||||
void setWidth(uint16_t newWidth);
|
||||
uint16_t getWidth();
|
||||
void setHeight(uint16_t newHeight);
|
||||
uint16_t getHeight();
|
||||
void setHorizResolution (uint32_t newHorizResolution);
|
||||
void setHorizResolution(uint32_t newHorizResolution);
|
||||
uint32_t getHorizResolution();
|
||||
void setVertResolution (uint32_t newVertResolution);
|
||||
void setVertResolution(uint32_t newVertResolution);
|
||||
uint32_t getVertResolution();
|
||||
void setFrameCount(uint16_t newFrameCount);
|
||||
uint16_t getFrameCount();
|
||||
|
@ -568,16 +568,16 @@ namespace MP4{
|
|||
void setDepth(uint16_t newDepth);
|
||||
uint16_t getDepth();
|
||||
Box & getCLAP();
|
||||
void setCLAP(Box& clap);
|
||||
void setCLAP(Box & clap);
|
||||
Box & getPASP();
|
||||
std::string toPrettyVisualString(uint32_t index = 0, std::string = "");
|
||||
};
|
||||
|
||||
class AudioSampleEntry: public SampleEntry{
|
||||
|
||||
class AudioSampleEntry: public SampleEntry {
|
||||
public:
|
||||
///\todo set default values
|
||||
AudioSampleEntry();
|
||||
void setCodec(const char* newCodec);
|
||||
void setCodec(const char * newCodec);
|
||||
void setChannelCount(uint16_t newChannelCount);
|
||||
uint16_t getChannelCount();
|
||||
void setSampleSize(uint16_t newSampleSize);
|
||||
|
@ -587,56 +587,56 @@ namespace MP4{
|
|||
void setSampleRate(uint32_t newSampleRate);
|
||||
uint16_t toAACInit();
|
||||
uint32_t getSampleRate();
|
||||
void setCodecBox(Box& newBox);
|
||||
void setCodecBox(Box & newBox);
|
||||
Box & getCodecBox();
|
||||
std::string toPrettyAudioString(uint32_t indent = 0, std::string name = "");
|
||||
};
|
||||
|
||||
class MP4A: public AudioSampleEntry{
|
||||
|
||||
class MP4A: public AudioSampleEntry {
|
||||
public:
|
||||
MP4A();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class AAC: public AudioSampleEntry{
|
||||
class AAC: public AudioSampleEntry {
|
||||
public:
|
||||
AAC();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class AVC1: public VisualSampleEntry{
|
||||
class AVC1: public VisualSampleEntry {
|
||||
public:
|
||||
AVC1();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class H264: public VisualSampleEntry{
|
||||
class H264: public VisualSampleEntry {
|
||||
public:
|
||||
H264();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class STSD: public fullBox{
|
||||
|
||||
class STSD: public fullBox {
|
||||
public:
|
||||
STSD(char v = 1, uint32_t f = 0);
|
||||
void setEntryCount (uint32_t newEntryCount);
|
||||
void setEntryCount(uint32_t newEntryCount);
|
||||
uint32_t getEntryCount();
|
||||
void setEntry(Box & newContent, uint32_t no);
|
||||
Box & getEntry(uint32_t no);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class EDTS: public containerBox{
|
||||
|
||||
class EDTS: public containerBox {
|
||||
public:
|
||||
EDTS();
|
||||
};
|
||||
|
||||
class UDTA: public containerBox{
|
||||
class UDTA: public containerBox {
|
||||
public:
|
||||
UDTA();
|
||||
};
|
||||
|
||||
class STSS: public fullBox{
|
||||
|
||||
class STSS: public fullBox {
|
||||
public:
|
||||
STSS(char v = 1, uint32_t f = 0);
|
||||
void setEntryCount(uint32_t newVal);
|
||||
|
@ -645,14 +645,14 @@ namespace MP4{
|
|||
uint32_t getSampleNumber(uint32_t index);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class META: public containerFullBox{
|
||||
|
||||
class META: public containerFullBox {
|
||||
public:
|
||||
META();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class ELST: public fullBox{
|
||||
|
||||
class ELST: public fullBox {
|
||||
public:
|
||||
ELST();
|
||||
void setSegmentDuration(uint64_t newVal);
|
||||
|
|
146
lib/mp4_ms.cpp
146
lib/mp4_ms.cpp
|
@ -1,8 +1,8 @@
|
|||
#include "mp4_ms.h"
|
||||
|
||||
namespace MP4{
|
||||
namespace MP4 {
|
||||
|
||||
static char c2hex(int c){
|
||||
static char c2hex(int c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
|
@ -10,34 +10,34 @@ namespace MP4{
|
|||
}
|
||||
|
||||
|
||||
SDTP::SDTP(){
|
||||
SDTP::SDTP() {
|
||||
memcpy(data + 4, "sdtp", 4);
|
||||
}
|
||||
|
||||
void SDTP::setVersion(uint32_t newVersion){
|
||||
void SDTP::setVersion(uint32_t newVersion) {
|
||||
setInt8(newVersion, 0);
|
||||
}
|
||||
|
||||
uint32_t SDTP::getVersion(){
|
||||
uint32_t SDTP::getVersion() {
|
||||
return getInt8(0);
|
||||
}
|
||||
|
||||
void SDTP::setValue(uint32_t newValue, size_t index){
|
||||
void SDTP::setValue(uint32_t newValue, size_t index) {
|
||||
setInt8(newValue, index);
|
||||
}
|
||||
|
||||
uint32_t SDTP::getValue(size_t index){
|
||||
uint32_t SDTP::getValue(size_t index) {
|
||||
return getInt8(index);
|
||||
}
|
||||
|
||||
std::string SDTP::toPrettyString(uint32_t indent){
|
||||
std::string SDTP::toPrettyString(uint32_t indent) {
|
||||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << "[sdtp] Sample Dependancy Type (" << boxedSize() << ")" << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Samples: " << (boxedSize() - 12) << std::endl;
|
||||
for (size_t i = 1; i <= boxedSize() - 12; ++i){
|
||||
uint32_t val = getValue(i+3);
|
||||
for (size_t i = 1; i <= boxedSize() - 12; ++i) {
|
||||
uint32_t val = getValue(i + 3);
|
||||
r << std::string(indent + 2, ' ') << "[" << i << "] = ";
|
||||
switch (val & 3){
|
||||
switch (val & 3) {
|
||||
case 0:
|
||||
r << " ";
|
||||
break;
|
||||
|
@ -51,7 +51,7 @@ namespace MP4{
|
|||
r << "Error, ";
|
||||
break;
|
||||
}
|
||||
switch (val & 12){
|
||||
switch (val & 12) {
|
||||
case 0:
|
||||
r << " ";
|
||||
break;
|
||||
|
@ -65,7 +65,7 @@ namespace MP4{
|
|||
r << "Error, ";
|
||||
break;
|
||||
}
|
||||
switch (val & 48){
|
||||
switch (val & 48) {
|
||||
case 0:
|
||||
r << " ";
|
||||
break;
|
||||
|
@ -84,48 +84,48 @@ namespace MP4{
|
|||
return r.str();
|
||||
}
|
||||
|
||||
UUID::UUID(){
|
||||
UUID::UUID() {
|
||||
memcpy(data + 4, "uuid", 4);
|
||||
setInt64(0, 0);
|
||||
setInt64(0, 8);
|
||||
}
|
||||
|
||||
std::string UUID::getUUID(){
|
||||
std::string UUID::getUUID() {
|
||||
std::stringstream r;
|
||||
r << std::hex;
|
||||
for (int i = 0; i < 16; ++i){
|
||||
if (i == 4 || i == 6 || i == 8 || i == 10){
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (i == 4 || i == 6 || i == 8 || i == 10) {
|
||||
r << "-";
|
||||
}
|
||||
r << std::setfill('0') << std::setw(2) << std::right << (int)(data[8+i]);
|
||||
r << std::setfill('0') << std::setw(2) << std::right << (int)(data[8 + i]);
|
||||
}
|
||||
return r.str();
|
||||
}
|
||||
|
||||
void UUID::setUUID(const std::string & uuid_string){
|
||||
void UUID::setUUID(const std::string & uuid_string) {
|
||||
//reset UUID to zero
|
||||
for (int i = 0; i < 4; ++i){
|
||||
((uint32_t*)(data+8))[i] = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
((uint32_t *)(data + 8))[i] = 0;
|
||||
}
|
||||
//set the UUID from the string, char by char
|
||||
int i = 0;
|
||||
for (size_t j = 0; j < uuid_string.size(); ++j){
|
||||
if (uuid_string[j] == '-'){
|
||||
for (size_t j = 0; j < uuid_string.size(); ++j) {
|
||||
if (uuid_string[j] == '-') {
|
||||
continue;
|
||||
}
|
||||
data[8+i/2] |= (c2hex(uuid_string[j]) << ((~i & 1) << 2));
|
||||
data[8 + i / 2] |= (c2hex(uuid_string[j]) << ((~i & 1) << 2));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void UUID::setUUID(const char * raw_uuid){
|
||||
memcpy(data+8, raw_uuid, 16);
|
||||
void UUID::setUUID(const char * raw_uuid) {
|
||||
memcpy(data + 8, raw_uuid, 16);
|
||||
}
|
||||
|
||||
std::string UUID::toPrettyString(uint32_t indent){
|
||||
std::string UUID::toPrettyString(uint32_t indent) {
|
||||
std::string UUID = getUUID();
|
||||
if (UUID == "d4807ef2-ca39-4695-8e54-26cb9e46a79f"){
|
||||
return ((UUID_TrackFragmentReference*)this)->toPrettyString(indent);
|
||||
if (UUID == "d4807ef2-ca39-4695-8e54-26cb9e46a79f") {
|
||||
return ((UUID_TrackFragmentReference *)this)->toPrettyString(indent);
|
||||
}
|
||||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << "[uuid] Extension box (" << boxedSize() << ")" << std::endl;
|
||||
|
@ -134,73 +134,73 @@ namespace MP4{
|
|||
return r.str();
|
||||
}
|
||||
|
||||
UUID_TrackFragmentReference::UUID_TrackFragmentReference(){
|
||||
UUID_TrackFragmentReference::UUID_TrackFragmentReference() {
|
||||
setUUID((std::string)"d4807ef2-ca39-4695-8e54-26cb9e46a79f");
|
||||
}
|
||||
|
||||
void UUID_TrackFragmentReference::setVersion(uint32_t newVersion){
|
||||
void UUID_TrackFragmentReference::setVersion(uint32_t newVersion) {
|
||||
setInt8(newVersion, 16);
|
||||
}
|
||||
|
||||
uint32_t UUID_TrackFragmentReference::getVersion(){
|
||||
|
||||
uint32_t UUID_TrackFragmentReference::getVersion() {
|
||||
return getInt8(16);
|
||||
}
|
||||
|
||||
void UUID_TrackFragmentReference::setFlags(uint32_t newFlags){
|
||||
|
||||
void UUID_TrackFragmentReference::setFlags(uint32_t newFlags) {
|
||||
setInt24(newFlags, 17);
|
||||
}
|
||||
|
||||
uint32_t UUID_TrackFragmentReference::getFlags(){
|
||||
|
||||
uint32_t UUID_TrackFragmentReference::getFlags() {
|
||||
return getInt24(17);
|
||||
}
|
||||
|
||||
void UUID_TrackFragmentReference::setFragmentCount(uint32_t newCount){
|
||||
|
||||
void UUID_TrackFragmentReference::setFragmentCount(uint32_t newCount) {
|
||||
setInt8(newCount, 20);
|
||||
}
|
||||
|
||||
uint32_t UUID_TrackFragmentReference::getFragmentCount(){
|
||||
|
||||
uint32_t UUID_TrackFragmentReference::getFragmentCount() {
|
||||
return getInt8(20);
|
||||
}
|
||||
|
||||
void UUID_TrackFragmentReference::setTime(size_t num, uint64_t newTime){
|
||||
if (getVersion() == 0){
|
||||
setInt32(newTime, 21+(num*8));
|
||||
}else{
|
||||
setInt64(newTime, 21+(num*16));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t UUID_TrackFragmentReference::getTime(size_t num){
|
||||
if (getVersion() == 0){
|
||||
return getInt32(21+(num*8));
|
||||
}else{
|
||||
return getInt64(21+(num*16));
|
||||
}
|
||||
}
|
||||
|
||||
void UUID_TrackFragmentReference::setDuration(size_t num, uint64_t newDuration){
|
||||
if (getVersion() == 0){
|
||||
setInt32(newDuration, 21+(num*8)+4);
|
||||
}else{
|
||||
setInt64(newDuration, 21+(num*16)+8);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t UUID_TrackFragmentReference::getDuration(size_t num){
|
||||
if (getVersion() == 0){
|
||||
return getInt32(21+(num*8)+4);
|
||||
}else{
|
||||
return getInt64(21+(num*16)+8);
|
||||
|
||||
void UUID_TrackFragmentReference::setTime(size_t num, uint64_t newTime) {
|
||||
if (getVersion() == 0) {
|
||||
setInt32(newTime, 21 + (num * 8));
|
||||
} else {
|
||||
setInt64(newTime, 21 + (num * 16));
|
||||
}
|
||||
}
|
||||
|
||||
std::string UUID_TrackFragmentReference::toPrettyString(uint32_t indent){
|
||||
uint64_t UUID_TrackFragmentReference::getTime(size_t num) {
|
||||
if (getVersion() == 0) {
|
||||
return getInt32(21 + (num * 8));
|
||||
} else {
|
||||
return getInt64(21 + (num * 16));
|
||||
}
|
||||
}
|
||||
|
||||
void UUID_TrackFragmentReference::setDuration(size_t num, uint64_t newDuration) {
|
||||
if (getVersion() == 0) {
|
||||
setInt32(newDuration, 21 + (num * 8) + 4);
|
||||
} else {
|
||||
setInt64(newDuration, 21 + (num * 16) + 8);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t UUID_TrackFragmentReference::getDuration(size_t num) {
|
||||
if (getVersion() == 0) {
|
||||
return getInt32(21 + (num * 8) + 4);
|
||||
} else {
|
||||
return getInt64(21 + (num * 16) + 8);
|
||||
}
|
||||
}
|
||||
|
||||
std::string UUID_TrackFragmentReference::toPrettyString(uint32_t indent) {
|
||||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << "[d4807ef2-ca39-4695-8e54-26cb9e46a79f] Track Fragment Reference (" << boxedSize() << ")" << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Fragments: " << getFragmentCount() << std::endl;
|
||||
int j = getFragmentCount();
|
||||
for (int i = 0; i < j; ++i){
|
||||
for (int i = 0; i < j; ++i) {
|
||||
r << std::string(indent + 2, ' ') << "[" << i << "] Time = " << getTime(i) << ", Duration = " << getDuration(i) << std::endl;
|
||||
}
|
||||
return r.str();
|
||||
|
|
10
lib/mp4_ms.h
10
lib/mp4_ms.h
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include "mp4.h"
|
||||
|
||||
namespace MP4{
|
||||
class SDTP: public Box{
|
||||
namespace MP4 {
|
||||
class SDTP: public Box {
|
||||
public:
|
||||
SDTP();
|
||||
void setVersion(uint32_t newVersion);
|
||||
|
@ -11,8 +11,8 @@ namespace MP4{
|
|||
uint32_t getValue(size_t index);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class UUID: public Box{
|
||||
|
||||
class UUID: public Box {
|
||||
public:
|
||||
UUID();
|
||||
std::string getUUID();
|
||||
|
@ -21,7 +21,7 @@ namespace MP4{
|
|||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class UUID_TrackFragmentReference: public UUID{
|
||||
class UUID_TrackFragmentReference: public UUID {
|
||||
public:
|
||||
UUID_TrackFragmentReference();
|
||||
void setVersion(uint32_t newVersion);
|
||||
|
|
8
lib/nal.cpp
Executable file → Normal file
8
lib/nal.cpp
Executable file → Normal file
|
@ -134,10 +134,10 @@ namespace h264 {
|
|||
//For calculating width
|
||||
unsigned int widthInMbs = 0;
|
||||
unsigned int cropHorizontal = 0;
|
||||
|
||||
|
||||
//For calculating height
|
||||
bool mbsOnlyFlag = 0;
|
||||
unsigned int heightInMapUnits = 0;
|
||||
unsigned int heightInMapUnits = 0;
|
||||
unsigned int cropVertical = 0;
|
||||
|
||||
Utils::bitstream bs;
|
||||
|
@ -177,7 +177,7 @@ namespace h264 {
|
|||
bs.skip(1);
|
||||
//Stop skipping data and start doing usefull stuff
|
||||
|
||||
|
||||
|
||||
widthInMbs = bs.getUExpGolomb() + 1;
|
||||
heightInMapUnits = bs.getUExpGolomb() + 1;
|
||||
|
||||
|
@ -197,7 +197,7 @@ namespace h264 {
|
|||
//vuiParameters
|
||||
if (bs.get(1)) {
|
||||
//Skipping all the paramters we dont use
|
||||
if (bs.get(1)){
|
||||
if (bs.get(1)) {
|
||||
if (bs.get(8) == 255) {
|
||||
bs.skip(32);
|
||||
}
|
||||
|
|
32
lib/nal.h
Executable file → Normal file
32
lib/nal.h
Executable file → Normal file
|
@ -1,17 +1,17 @@
|
|||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
namespace h264{
|
||||
|
||||
namespace h264 {
|
||||
|
||||
///Struct containing pre-calculated metadata of an SPS nal unit. Width and height in pixels, fps in Hz
|
||||
struct SPSMeta{
|
||||
struct SPSMeta {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
double fps;
|
||||
};
|
||||
|
||||
|
||||
///Class for analyzing generic nal units
|
||||
class NAL{
|
||||
class NAL {
|
||||
public:
|
||||
NAL();
|
||||
NAL(std::string & InputData);
|
||||
|
@ -25,21 +25,21 @@ namespace h264{
|
|||
std::string MyData;///<The h264 nal unit data
|
||||
};
|
||||
//NAL class
|
||||
|
||||
|
||||
///Special instance of NAL class for analyzing SPS nal units
|
||||
class SPS: public NAL{
|
||||
class SPS: public NAL {
|
||||
public:
|
||||
SPS():NAL(){};
|
||||
SPS(std::string & InputData, bool raw = false);
|
||||
SPSMeta getCharacteristics();
|
||||
void analyzeSPS();
|
||||
SPS(): NAL() {};
|
||||
SPS(std::string & InputData, bool raw = false);
|
||||
SPSMeta getCharacteristics();
|
||||
void analyzeSPS();
|
||||
};
|
||||
|
||||
|
||||
///Special instance of NAL class for analyzing PPS nal units
|
||||
class PPS: public NAL{
|
||||
class PPS: public NAL {
|
||||
public:
|
||||
PPS():NAL(){};
|
||||
PPS(std::string & InputData):NAL(InputData){};
|
||||
void analyzePPS();
|
||||
PPS(): NAL() {};
|
||||
PPS(std::string & InputData): NAL(InputData) {};
|
||||
void analyzePPS();
|
||||
};
|
||||
}//ns h264
|
||||
|
|
485
lib/ogg.cpp
485
lib/ogg.cpp
|
@ -5,87 +5,87 @@
|
|||
#include <sstream>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
namespace OGG{
|
||||
inline long long unsigned int get_64(char* data){
|
||||
namespace OGG {
|
||||
inline long long unsigned int get_64(char * data) {
|
||||
long long unsigned int temp = 0;
|
||||
for (int i = 7; i>= 0; --i){
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
temp <<= 8;
|
||||
temp += data[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline long unsigned int get_32(char* data){
|
||||
|
||||
inline long unsigned int get_32(char * data) {
|
||||
long unsigned int temp = 0;
|
||||
for (int i = 3; i>= 0; --i){
|
||||
for (int i = 3; i >= 0; --i) {
|
||||
temp <<= 8;
|
||||
temp += data[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline void set_64(char* data, long unsigned int val){
|
||||
for (int i = 0; i< 8; ++i){
|
||||
inline void set_64(char * data, long unsigned int val) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
data[i] = val & 0xFF;
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void set_32(char* data, long unsigned int val){
|
||||
for (int i = 0; i< 4; ++i){
|
||||
inline void set_32(char * data, long unsigned int val) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
data[i] = val & 0xFF;
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Page::Page(){
|
||||
|
||||
Page::Page() {
|
||||
data = NULL;
|
||||
datasize = 0;
|
||||
dataSum = 0;
|
||||
}
|
||||
|
||||
Page::~Page(){
|
||||
if (data){
|
||||
|
||||
Page::~Page() {
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
bool Page::read(std::string & newData){
|
||||
bool Page::read(std::string & newData) {
|
||||
segmentTableDeque.clear();
|
||||
//datasize = 0;
|
||||
if (newData.size()<27){
|
||||
if (newData.size() < 27) {
|
||||
return false;
|
||||
}
|
||||
if (newData.substr(0, 4) != "OggS"){
|
||||
if (newData.substr(0, 4) != "OggS") {
|
||||
DEBUG_MSG(DLVL_FAIL, "Invalid Ogg page encountered - cannot continue");
|
||||
return false;
|
||||
}
|
||||
dataSum = 0;
|
||||
if (!checkDataSize(27)){
|
||||
if (!checkDataSize(27)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(data, newData.c_str(), 27);//copying the header, always 27 bytes
|
||||
|
||||
if (newData.size() < 27u + getPageSegments()){//check input size
|
||||
|
||||
if (newData.size() < 27u + getPageSegments()) { //check input size
|
||||
return false;
|
||||
}
|
||||
if(!checkDataSize(27 + getPageSegments())){//check if size available in memory
|
||||
if (!checkDataSize(27 + getPageSegments())) { //check if size available in memory
|
||||
return false;
|
||||
}
|
||||
memcpy(data + 27, newData.c_str() + 27, getPageSegments());
|
||||
memcpy(data + 27, newData.c_str() + 27, getPageSegments());
|
||||
//copying the first part of the page into data, which tells the size of the page
|
||||
|
||||
for(unsigned int i = 0; i < getPageSegments(); i++){
|
||||
|
||||
for (unsigned int i = 0; i < getPageSegments(); i++) {
|
||||
dataSum += getSegmentTable()[i];
|
||||
}
|
||||
|
||||
if (newData.size() < 27 + getPageSegments() + dataSum){//check input size
|
||||
|
||||
if (newData.size() < 27 + getPageSegments() + dataSum) { //check input size
|
||||
dataSum = 0;
|
||||
return false;
|
||||
}
|
||||
if(!checkDataSize(27 + getPageSegments()+dataSum)){
|
||||
if (!checkDataSize(27 + getPageSegments() + dataSum)) {
|
||||
dataSum = 0;
|
||||
return false;
|
||||
}
|
||||
|
@ -95,38 +95,38 @@ namespace OGG{
|
|||
}
|
||||
|
||||
|
||||
bool Page::read(FILE * inFile){
|
||||
bool Page::read(FILE * inFile) {
|
||||
segmentTableDeque.clear();
|
||||
int oriPos = ftell(inFile);
|
||||
dataSum = 0;
|
||||
if (!checkDataSize(27)){
|
||||
DEBUG_MSG(DLVL_WARN,"Unable to read a page: memory allocation");
|
||||
if (!checkDataSize(27)) {
|
||||
DEBUG_MSG(DLVL_WARN, "Unable to read a page: memory allocation");
|
||||
return false;
|
||||
}
|
||||
if (!fread(data, 27, 1, inFile)){
|
||||
DEBUG_MSG(DLVL_WARN,"Unable to read a page: fread");
|
||||
if (!fread(data, 27, 1, inFile)) {
|
||||
DEBUG_MSG(DLVL_WARN, "Unable to read a page: fread");
|
||||
fseek(inFile, oriPos, SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
if(!checkDataSize(27 + getPageSegments())){
|
||||
DEBUG_MSG(DLVL_WARN,"Unable to read a page: memory allocation1");
|
||||
if (!checkDataSize(27 + getPageSegments())) {
|
||||
DEBUG_MSG(DLVL_WARN, "Unable to read a page: memory allocation1");
|
||||
return false;
|
||||
}
|
||||
if (!fread(data + 27, getPageSegments(), 1, inFile)){
|
||||
DEBUG_MSG(DLVL_WARN,"Unable to read a page: fread1");
|
||||
if (!fread(data + 27, getPageSegments(), 1, inFile)) {
|
||||
DEBUG_MSG(DLVL_WARN, "Unable to read a page: fread1");
|
||||
fseek(inFile, oriPos, SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
for (unsigned int i = 0; i < getPageSegments(); i++){
|
||||
for (unsigned int i = 0; i < getPageSegments(); i++) {
|
||||
dataSum += data[27 + i];
|
||||
}
|
||||
if (!checkDataSize(27 + getPageSegments() + dataSum)){
|
||||
DEBUG_MSG(DLVL_WARN,"Unable to read a page: memory allocation2");
|
||||
if (!checkDataSize(27 + getPageSegments() + dataSum)) {
|
||||
DEBUG_MSG(DLVL_WARN, "Unable to read a page: memory allocation2");
|
||||
dataSum = 0;
|
||||
return false;
|
||||
}
|
||||
if ( !fread(data + 27 + getPageSegments(), dataSum, 1, inFile)){
|
||||
DEBUG_MSG(DLVL_WARN,"Unable to read a page: fread2");
|
||||
if (!fread(data + 27 + getPageSegments(), dataSum, 1, inFile)) {
|
||||
DEBUG_MSG(DLVL_WARN, "Unable to read a page: fread2");
|
||||
fseek(inFile, oriPos, SEEK_SET);
|
||||
dataSum = 0;
|
||||
return false;
|
||||
|
@ -134,143 +134,143 @@ namespace OGG{
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Page::getSegment(unsigned int index, char * ret, unsigned int & len){
|
||||
if (index > segmentTableDeque.size()){
|
||||
bool Page::getSegment(unsigned int index, char * ret, unsigned int & len) {
|
||||
if (index > segmentTableDeque.size()) {
|
||||
ret = NULL;
|
||||
len = 0;
|
||||
return false;
|
||||
}
|
||||
ret = getFullPayload();
|
||||
for (unsigned int i = 0; i < index; i++){
|
||||
for (unsigned int i = 0; i < index; i++) {
|
||||
ret += segmentTableDeque[i];
|
||||
}
|
||||
len = segmentTableDeque[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
void Page::setMagicNumber(){
|
||||
if(checkDataSize(4)){
|
||||
|
||||
void Page::setMagicNumber() {
|
||||
if (checkDataSize(4)) {
|
||||
memcpy(data, "OggS", 4);
|
||||
}
|
||||
}
|
||||
|
||||
char Page::getVersion(){
|
||||
|
||||
char Page::getVersion() {
|
||||
return data[4];
|
||||
}
|
||||
|
||||
void Page::setVersion(char newVal){
|
||||
if(checkDataSize(5)){
|
||||
void Page::setVersion(char newVal) {
|
||||
if (checkDataSize(5)) {
|
||||
data[4] = newVal;
|
||||
}
|
||||
}
|
||||
|
||||
char Page::getHeaderType(){
|
||||
|
||||
char Page::getHeaderType() {
|
||||
return data[5];
|
||||
}
|
||||
|
||||
void Page::setHeaderType(char newVal){
|
||||
if(checkDataSize(6)){
|
||||
void Page::setHeaderType(char newVal) {
|
||||
if (checkDataSize(6)) {
|
||||
data[5] = newVal;
|
||||
}
|
||||
}
|
||||
|
||||
long long unsigned int Page::getGranulePosition(){
|
||||
if(checkDataSize(14)){
|
||||
|
||||
long long unsigned int Page::getGranulePosition() {
|
||||
if (checkDataSize(14)) {
|
||||
//switching bit order upon return
|
||||
//return ntohl(((long unsigned*)(data+6))[1]) & ((long long unsigned)((long long unsigned)ntohl(((long unsigned*)(data+6))[0]) << 32));
|
||||
//long long unsigned int temp;
|
||||
//temp = ((long unsigned int)(data+6)[0]);
|
||||
//temp = temp << 32 + ((long unsigned int)(data+6)[1]);
|
||||
return get_64(data+6);
|
||||
return get_64(data + 6);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Page::setGranulePosition(long long unsigned int newVal){
|
||||
if(checkDataSize(14)){
|
||||
set_64(data+6, newVal);
|
||||
void Page::setGranulePosition(long long unsigned int newVal) {
|
||||
if (checkDataSize(14)) {
|
||||
set_64(data + 6, newVal);
|
||||
}
|
||||
}
|
||||
|
||||
long unsigned int Page::getBitstreamSerialNumber(){
|
||||
|
||||
long unsigned int Page::getBitstreamSerialNumber() {
|
||||
//return ntohl(((long unsigned int*)(data+14))[0]);
|
||||
return get_32(data+14);
|
||||
return get_32(data + 14);
|
||||
}
|
||||
|
||||
void Page::setBitstreamSerialNumber(long unsigned int newVal){
|
||||
if(checkDataSize(18)){
|
||||
void Page::setBitstreamSerialNumber(long unsigned int newVal) {
|
||||
if (checkDataSize(18)) {
|
||||
//((long unsigned *)(data+14))[0] = htonl(newVal);
|
||||
set_32(data+14, newVal);
|
||||
set_32(data + 14, newVal);
|
||||
}
|
||||
}
|
||||
|
||||
long unsigned int Page::getPageSequenceNumber(){
|
||||
return get_32(data+18);
|
||||
}
|
||||
|
||||
void Page::setPageSequenceNumber(long unsigned int newVal){
|
||||
if(checkDataSize(22)){
|
||||
long unsigned int Page::getPageSequenceNumber() {
|
||||
return get_32(data + 18);
|
||||
}
|
||||
|
||||
void Page::setPageSequenceNumber(long unsigned int newVal) {
|
||||
if (checkDataSize(22)) {
|
||||
//((long unsigned *)(data+18))[0] = htonl(newVal);
|
||||
set_32(data+18, newVal);
|
||||
set_32(data + 18, newVal);
|
||||
}
|
||||
}
|
||||
|
||||
long unsigned int Page::getCRCChecksum(){
|
||||
|
||||
long unsigned int Page::getCRCChecksum() {
|
||||
//return ntohl(((long unsigned int*)(data+22))[0]);
|
||||
return get_32(data+22);
|
||||
return get_32(data + 22);
|
||||
}
|
||||
|
||||
void Page::setCRCChecksum(long unsigned int newVal){
|
||||
if(checkDataSize(26)){
|
||||
set_32(data+22,newVal);
|
||||
|
||||
void Page::setCRCChecksum(long unsigned int newVal) {
|
||||
if (checkDataSize(26)) {
|
||||
set_32(data + 22, newVal);
|
||||
}
|
||||
}
|
||||
|
||||
char Page::getPageSegments(){
|
||||
return data[26];
|
||||
|
||||
char Page::getPageSegments() {
|
||||
return data[26];
|
||||
}
|
||||
|
||||
inline void Page::setPageSegments(char newVal){
|
||||
if(checkDataSize(26)){
|
||||
|
||||
inline void Page::setPageSegments(char newVal) {
|
||||
if (checkDataSize(26)) {
|
||||
data[26] = newVal;
|
||||
}
|
||||
}
|
||||
|
||||
char* Page::getSegmentTable(){
|
||||
return data+27;
|
||||
|
||||
char * Page::getSegmentTable() {
|
||||
return data + 27;
|
||||
}
|
||||
|
||||
std::deque<unsigned int> & Page::getSegmentTableDeque(){
|
||||
if ( !segmentTableDeque.size()){
|
||||
|
||||
std::deque<unsigned int> & Page::getSegmentTableDeque() {
|
||||
if (!segmentTableDeque.size()) {
|
||||
unsigned int temp = 0;
|
||||
for (unsigned int i = 0; i < getPageSegments(); i++){
|
||||
for (unsigned int i = 0; i < getPageSegments(); i++) {
|
||||
temp += getSegmentTable()[i];
|
||||
if (getSegmentTable()[i] < 255){
|
||||
if (getSegmentTable()[i] < 255) {
|
||||
segmentTableDeque.push_back(temp);
|
||||
temp = 0;
|
||||
}
|
||||
}
|
||||
if (temp!=0){
|
||||
if (temp != 0) {
|
||||
segmentTableDeque.push_back(temp);
|
||||
}
|
||||
}
|
||||
return segmentTableDeque;
|
||||
}
|
||||
|
||||
static void STerrMSG(){
|
||||
static void STerrMSG() {
|
||||
DEBUG_MSG(DLVL_ERROR, "Segment too big, create a continue page");
|
||||
}
|
||||
|
||||
bool Page::setSegmentTable(std::vector<unsigned int> layout){
|
||||
dataSum=0;
|
||||
for (unsigned int i = 0; i < layout.size(); i++){
|
||||
bool Page::setSegmentTable(std::vector<unsigned int> layout) {
|
||||
dataSum = 0;
|
||||
for (unsigned int i = 0; i < layout.size(); i++) {
|
||||
dataSum += layout[i];
|
||||
}
|
||||
unsigned int place = 0;
|
||||
char table[256];
|
||||
for (unsigned int i = 0; i < layout.size(); i++){
|
||||
int amount = (layout[i]/255) + 1;
|
||||
if (i == layout.size() - 1 && place + amount > (255 + (layout[i] % 255 == 0))){
|
||||
for (unsigned int i = 0; i < layout.size(); i++) {
|
||||
int amount = (layout[i] / 255) + 1;
|
||||
if (i == layout.size() - 1 && place + amount > (255 + (layout[i] % 255 == 0))) {
|
||||
STerrMSG();
|
||||
return false;
|
||||
}
|
||||
|
@ -279,141 +279,140 @@ namespace OGG{
|
|||
place += amount;
|
||||
}
|
||||
//Don't send element 256, even if it was filled.
|
||||
if (place > 255){
|
||||
if (place > 255) {
|
||||
place = 255;
|
||||
}
|
||||
setPageSegments(place);
|
||||
setSegmentTable(table,place);
|
||||
setSegmentTable(table, place);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Page::setSegmentTable(char* newVal, unsigned int length){
|
||||
if(checkDataSize(27 + length)){
|
||||
|
||||
void Page::setSegmentTable(char * newVal, unsigned int length) {
|
||||
if (checkDataSize(27 + length)) {
|
||||
memcpy(data + 27, newVal, length);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long int Page::getPageSize(){
|
||||
return 27 + getPageSegments()+dataSum;
|
||||
|
||||
unsigned long int Page::getPageSize() {
|
||||
return 27 + getPageSegments() + dataSum;
|
||||
}
|
||||
|
||||
char* Page::getPage(){
|
||||
|
||||
char * Page::getPage() {
|
||||
return data;
|
||||
}
|
||||
|
||||
char* Page::getFullPayload(){
|
||||
|
||||
char * Page::getFullPayload() {
|
||||
return data + 27 + getPageSegments();
|
||||
}
|
||||
|
||||
void Page::setInternalCodec(std::string myCodec){
|
||||
|
||||
void Page::setInternalCodec(std::string myCodec) {
|
||||
codec = myCodec;
|
||||
}
|
||||
|
||||
std::string Page::toPrettyString(size_t indent){
|
||||
|
||||
std::string Page::toPrettyString(size_t indent) {
|
||||
std::stringstream r;
|
||||
r << std::string(indent,' ') << "Ogg page (" << getPageSize() << ")" << std::endl;
|
||||
r << std::string(indent + 2,' ') << "Version: " << (int)getVersion() << std::endl;
|
||||
r << std::string(indent + 2,' ') << "Header type:";
|
||||
if ( !getHeaderType()){
|
||||
r << std::string(indent, ' ') << "Ogg page (" << getPageSize() << ")" << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "Version: " << (int)getVersion() << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "Header type:";
|
||||
if (!getHeaderType()) {
|
||||
r << " Normal";
|
||||
}else{
|
||||
if (getHeaderType() & Continued){
|
||||
} else {
|
||||
if (getHeaderType() & Continued) {
|
||||
r << " Continued";
|
||||
}
|
||||
if (getHeaderType() & BeginOfStream){
|
||||
if (getHeaderType() & BeginOfStream) {
|
||||
r << " BeginOfStream";
|
||||
}
|
||||
if (getHeaderType() & EndOfStream){
|
||||
if (getHeaderType() & EndOfStream) {
|
||||
r << " EndOfStream";
|
||||
}
|
||||
}
|
||||
r << " (" << (int)getHeaderType() << ")" << std::endl;
|
||||
r << std::string(indent + 2,' ') << "Granule position: " << getGranulePosition() << std::endl;
|
||||
r << std::string(indent + 2,' ') << "Bitstream number: " << getBitstreamSerialNumber() << std::endl;
|
||||
r << std::string(indent + 2,' ') << "Sequence number: " << getPageSequenceNumber() << std::endl;
|
||||
r << std::string(indent + 2,' ') << "Checksum: " << std::hex << getCRCChecksum() << std::dec << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "Granule position: " << getGranulePosition() << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "Bitstream number: " << getBitstreamSerialNumber() << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "Sequence number: " << getPageSequenceNumber() << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "Checksum: " << std::hex << getCRCChecksum() << std::dec << std::endl;
|
||||
//r << " Calced Checksum: " << std::hex << calcChecksum() << std::dec << std::endl;
|
||||
r << std::string(indent + 2,' ') << "Payloadsize: " << dataSum << std::endl;
|
||||
r << std::string(indent + 2,' ') << (int)getPageSegments() << " segments:" << std::endl;
|
||||
r << std::string(indent + 3,' ');
|
||||
r << std::string(indent + 2, ' ') << "Payloadsize: " << dataSum << std::endl;
|
||||
r << std::string(indent + 2, ' ') << (int)getPageSegments() << " segments:" << std::endl;
|
||||
r << std::string(indent + 3, ' ');
|
||||
std::deque<unsigned int> temp = getSegmentTableDeque();
|
||||
for (std::deque<unsigned int>::iterator i = temp.begin(); i != temp.end(); i++){
|
||||
for (std::deque<unsigned int>::iterator i = temp.begin(); i != temp.end(); i++) {
|
||||
r << " " << (*i);
|
||||
}
|
||||
r << std::endl;
|
||||
return r.str();
|
||||
}
|
||||
|
||||
inline unsigned int crc32(unsigned int crc, const char *data, size_t len){
|
||||
|
||||
inline unsigned int crc32(unsigned int crc, const char * data, size_t len) {
|
||||
static const unsigned int table[256] = {
|
||||
0x00000000U,0x04C11DB7U,0x09823B6EU,0x0D4326D9U,
|
||||
0x130476DCU,0x17C56B6BU,0x1A864DB2U,0x1E475005U,
|
||||
0x2608EDB8U,0x22C9F00FU,0x2F8AD6D6U,0x2B4BCB61U,
|
||||
0x350C9B64U,0x31CD86D3U,0x3C8EA00AU,0x384FBDBDU,
|
||||
0x4C11DB70U,0x48D0C6C7U,0x4593E01EU,0x4152FDA9U,
|
||||
0x5F15ADACU,0x5BD4B01BU,0x569796C2U,0x52568B75U,
|
||||
0x6A1936C8U,0x6ED82B7FU,0x639B0DA6U,0x675A1011U,
|
||||
0x791D4014U,0x7DDC5DA3U,0x709F7B7AU,0x745E66CDU,
|
||||
0x9823B6E0U,0x9CE2AB57U,0x91A18D8EU,0x95609039U,
|
||||
0x8B27C03CU,0x8FE6DD8BU,0x82A5FB52U,0x8664E6E5U,
|
||||
0xBE2B5B58U,0xBAEA46EFU,0xB7A96036U,0xB3687D81U,
|
||||
0xAD2F2D84U,0xA9EE3033U,0xA4AD16EAU,0xA06C0B5DU,
|
||||
0xD4326D90U,0xD0F37027U,0xDDB056FEU,0xD9714B49U,
|
||||
0xC7361B4CU,0xC3F706FBU,0xCEB42022U,0xCA753D95U,
|
||||
0xF23A8028U,0xF6FB9D9FU,0xFBB8BB46U,0xFF79A6F1U,
|
||||
0xE13EF6F4U,0xE5FFEB43U,0xE8BCCD9AU,0xEC7DD02DU,
|
||||
0x34867077U,0x30476DC0U,0x3D044B19U,0x39C556AEU,
|
||||
0x278206ABU,0x23431B1CU,0x2E003DC5U,0x2AC12072U,
|
||||
0x128E9DCFU,0x164F8078U,0x1B0CA6A1U,0x1FCDBB16U,
|
||||
0x018AEB13U,0x054BF6A4U,0x0808D07DU,0x0CC9CDCAU,
|
||||
0x7897AB07U,0x7C56B6B0U,0x71159069U,0x75D48DDEU,
|
||||
0x6B93DDDBU,0x6F52C06CU,0x6211E6B5U,0x66D0FB02U,
|
||||
0x5E9F46BFU,0x5A5E5B08U,0x571D7DD1U,0x53DC6066U,
|
||||
0x4D9B3063U,0x495A2DD4U,0x44190B0DU,0x40D816BAU,
|
||||
0xACA5C697U,0xA864DB20U,0xA527FDF9U,0xA1E6E04EU,
|
||||
0xBFA1B04BU,0xBB60ADFCU,0xB6238B25U,0xB2E29692U,
|
||||
0x8AAD2B2FU,0x8E6C3698U,0x832F1041U,0x87EE0DF6U,
|
||||
0x99A95DF3U,0x9D684044U,0x902B669DU,0x94EA7B2AU,
|
||||
0xE0B41DE7U,0xE4750050U,0xE9362689U,0xEDF73B3EU,
|
||||
0xF3B06B3BU,0xF771768CU,0xFA325055U,0xFEF34DE2U,
|
||||
0xC6BCF05FU,0xC27DEDE8U,0xCF3ECB31U,0xCBFFD686U,
|
||||
0xD5B88683U,0xD1799B34U,0xDC3ABDEDU,0xD8FBA05AU,
|
||||
0x690CE0EEU,0x6DCDFD59U,0x608EDB80U,0x644FC637U,
|
||||
0x7A089632U,0x7EC98B85U,0x738AAD5CU,0x774BB0EBU,
|
||||
0x4F040D56U,0x4BC510E1U,0x46863638U,0x42472B8FU,
|
||||
0x5C007B8AU,0x58C1663DU,0x558240E4U,0x51435D53U,
|
||||
0x251D3B9EU,0x21DC2629U,0x2C9F00F0U,0x285E1D47U,
|
||||
0x36194D42U,0x32D850F5U,0x3F9B762CU,0x3B5A6B9BU,
|
||||
0x0315D626U,0x07D4CB91U,0x0A97ED48U,0x0E56F0FFU,
|
||||
0x1011A0FAU,0x14D0BD4DU,0x19939B94U,0x1D528623U,
|
||||
0xF12F560EU,0xF5EE4BB9U,0xF8AD6D60U,0xFC6C70D7U,
|
||||
0xE22B20D2U,0xE6EA3D65U,0xEBA91BBCU,0xEF68060BU,
|
||||
0xD727BBB6U,0xD3E6A601U,0xDEA580D8U,0xDA649D6FU,
|
||||
0xC423CD6AU,0xC0E2D0DDU,0xCDA1F604U,0xC960EBB3U,
|
||||
0xBD3E8D7EU,0xB9FF90C9U,0xB4BCB610U,0xB07DABA7U,
|
||||
0xAE3AFBA2U,0xAAFBE615U,0xA7B8C0CCU,0xA379DD7BU,
|
||||
0x9B3660C6U,0x9FF77D71U,0x92B45BA8U,0x9675461FU,
|
||||
0x8832161AU,0x8CF30BADU,0x81B02D74U,0x857130C3U,
|
||||
0x5D8A9099U,0x594B8D2EU,0x5408ABF7U,0x50C9B640U,
|
||||
0x4E8EE645U,0x4A4FFBF2U,0x470CDD2BU,0x43CDC09CU,
|
||||
0x7B827D21U,0x7F436096U,0x7200464FU,0x76C15BF8U,
|
||||
0x68860BFDU,0x6C47164AU,0x61043093U,0x65C52D24U,
|
||||
0x119B4BE9U,0x155A565EU,0x18197087U,0x1CD86D30U,
|
||||
0x029F3D35U,0x065E2082U,0x0B1D065BU,0x0FDC1BECU,
|
||||
0x3793A651U,0x3352BBE6U,0x3E119D3FU,0x3AD08088U,
|
||||
0x2497D08DU,0x2056CD3AU,0x2D15EBE3U,0x29D4F654U,
|
||||
0xC5A92679U,0xC1683BCEU,0xCC2B1D17U,0xC8EA00A0U,
|
||||
0xD6AD50A5U,0xD26C4D12U,0xDF2F6BCBU,0xDBEE767CU,
|
||||
0xE3A1CBC1U,0xE760D676U,0xEA23F0AFU,0xEEE2ED18U,
|
||||
0xF0A5BD1DU,0xF464A0AAU,0xF9278673U,0xFDE69BC4U,
|
||||
0x89B8FD09U,0x8D79E0BEU,0x803AC667U,0x84FBDBD0U,
|
||||
0x9ABC8BD5U,0x9E7D9662U,0x933EB0BBU,0x97FFAD0CU,
|
||||
0xAFB010B1U,0xAB710D06U,0xA6322BDFU,0xA2F33668U,
|
||||
0xBCB4666DU,0xB8757BDAU,0xB5365D03U,0xB1F740B4U,
|
||||
0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U,
|
||||
0x130476DCU, 0x17C56B6BU, 0x1A864DB2U, 0x1E475005U,
|
||||
0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U,
|
||||
0x350C9B64U, 0x31CD86D3U, 0x3C8EA00AU, 0x384FBDBDU,
|
||||
0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U,
|
||||
0x5F15ADACU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U,
|
||||
0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U,
|
||||
0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU,
|
||||
0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU, 0x95609039U,
|
||||
0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U,
|
||||
0xBE2B5B58U, 0xBAEA46EFU, 0xB7A96036U, 0xB3687D81U,
|
||||
0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU,
|
||||
0xD4326D90U, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U,
|
||||
0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U,
|
||||
0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U,
|
||||
0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU, 0xEC7DD02DU,
|
||||
0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU,
|
||||
0x278206ABU, 0x23431B1CU, 0x2E003DC5U, 0x2AC12072U,
|
||||
0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U,
|
||||
0x018AEB13U, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU,
|
||||
0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU,
|
||||
0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U,
|
||||
0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U, 0x53DC6066U,
|
||||
0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU,
|
||||
0xACA5C697U, 0xA864DB20U, 0xA527FDF9U, 0xA1E6E04EU,
|
||||
0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U,
|
||||
0x8AAD2B2FU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U,
|
||||
0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU,
|
||||
0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU,
|
||||
0xF3B06B3BU, 0xF771768CU, 0xFA325055U, 0xFEF34DE2U,
|
||||
0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U,
|
||||
0xD5B88683U, 0xD1799B34U, 0xDC3ABDEDU, 0xD8FBA05AU,
|
||||
0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U,
|
||||
0x7A089632U, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU,
|
||||
0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU,
|
||||
0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U,
|
||||
0x251D3B9EU, 0x21DC2629U, 0x2C9F00F0U, 0x285E1D47U,
|
||||
0x36194D42U, 0x32D850F5U, 0x3F9B762CU, 0x3B5A6B9BU,
|
||||
0x0315D626U, 0x07D4CB91U, 0x0A97ED48U, 0x0E56F0FFU,
|
||||
0x1011A0FAU, 0x14D0BD4DU, 0x19939B94U, 0x1D528623U,
|
||||
0xF12F560EU, 0xF5EE4BB9U, 0xF8AD6D60U, 0xFC6C70D7U,
|
||||
0xE22B20D2U, 0xE6EA3D65U, 0xEBA91BBCU, 0xEF68060BU,
|
||||
0xD727BBB6U, 0xD3E6A601U, 0xDEA580D8U, 0xDA649D6FU,
|
||||
0xC423CD6AU, 0xC0E2D0DDU, 0xCDA1F604U, 0xC960EBB3U,
|
||||
0xBD3E8D7EU, 0xB9FF90C9U, 0xB4BCB610U, 0xB07DABA7U,
|
||||
0xAE3AFBA2U, 0xAAFBE615U, 0xA7B8C0CCU, 0xA379DD7BU,
|
||||
0x9B3660C6U, 0x9FF77D71U, 0x92B45BA8U, 0x9675461FU,
|
||||
0x8832161AU, 0x8CF30BADU, 0x81B02D74U, 0x857130C3U,
|
||||
0x5D8A9099U, 0x594B8D2EU, 0x5408ABF7U, 0x50C9B640U,
|
||||
0x4E8EE645U, 0x4A4FFBF2U, 0x470CDD2BU, 0x43CDC09CU,
|
||||
0x7B827D21U, 0x7F436096U, 0x7200464FU, 0x76C15BF8U,
|
||||
0x68860BFDU, 0x6C47164AU, 0x61043093U, 0x65C52D24U,
|
||||
0x119B4BE9U, 0x155A565EU, 0x18197087U, 0x1CD86D30U,
|
||||
0x029F3D35U, 0x065E2082U, 0x0B1D065BU, 0x0FDC1BECU,
|
||||
0x3793A651U, 0x3352BBE6U, 0x3E119D3FU, 0x3AD08088U,
|
||||
0x2497D08DU, 0x2056CD3AU, 0x2D15EBE3U, 0x29D4F654U,
|
||||
0xC5A92679U, 0xC1683BCEU, 0xCC2B1D17U, 0xC8EA00A0U,
|
||||
0xD6AD50A5U, 0xD26C4D12U, 0xDF2F6BCBU, 0xDBEE767CU,
|
||||
0xE3A1CBC1U, 0xE760D676U, 0xEA23F0AFU, 0xEEE2ED18U,
|
||||
0xF0A5BD1DU, 0xF464A0AAU, 0xF9278673U, 0xFDE69BC4U,
|
||||
0x89B8FD09U, 0x8D79E0BEU, 0x803AC667U, 0x84FBDBD0U,
|
||||
0x9ABC8BD5U, 0x9E7D9662U, 0x933EB0BBU, 0x97FFAD0CU,
|
||||
0xAFB010B1U, 0xAB710D06U, 0xA6322BDFU, 0xA2F33668U,
|
||||
0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U, 0xB1F740B4U,
|
||||
};
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
|
||||
while (len > 0) {
|
||||
crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8);
|
||||
data++;
|
||||
len--;
|
||||
|
@ -421,39 +420,39 @@ namespace OGG{
|
|||
return crc;
|
||||
}
|
||||
|
||||
long unsigned int Page::calcChecksum(){
|
||||
long unsigned int Page::calcChecksum() {
|
||||
long unsigned int retVal = 0;
|
||||
long unsigned int oldChecksum = getCRCChecksum();
|
||||
setCRCChecksum (0);
|
||||
setCRCChecksum(0);
|
||||
retVal = crc32(0, data, getPageSize());
|
||||
setCRCChecksum (oldChecksum);
|
||||
setCRCChecksum(oldChecksum);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
inline bool Page::checkDataSize(unsigned int size){
|
||||
if (size > datasize){
|
||||
void* tmp = realloc(data,size);
|
||||
if (tmp){
|
||||
data = (char*)tmp;
|
||||
|
||||
inline bool Page::checkDataSize(unsigned int size) {
|
||||
if (size > datasize) {
|
||||
void * tmp = realloc(data, size);
|
||||
if (tmp) {
|
||||
data = (char *)tmp;
|
||||
datasize = size;
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int Page::getPayloadSize(){
|
||||
int Page::getPayloadSize() {
|
||||
return dataSum;
|
||||
}
|
||||
|
||||
bool Page::clear(){
|
||||
if(!checkDataSize(27)){//check if size available in memory
|
||||
|
||||
bool Page::clear() {
|
||||
if (!checkDataSize(27)) { //check if size available in memory
|
||||
return false;
|
||||
}
|
||||
memset(data,0,27);
|
||||
memset(data, 0, 27);
|
||||
dataSum = 0;
|
||||
codec = "";
|
||||
setMagicNumber();
|
||||
|
@ -461,70 +460,70 @@ namespace OGG{
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Page::setPayload(char* newData, unsigned int length){
|
||||
if(!checkDataSize(27 + getPageSegments() + length)){//check if size available in memory
|
||||
bool Page::setPayload(char * newData, unsigned int length) {
|
||||
if (!checkDataSize(27 + getPageSegments() + length)) { //check if size available in memory
|
||||
return false;
|
||||
}
|
||||
memcpy(data + 27 + getPageSegments(), newData, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Page::readDTSCVector(std::vector <JSON::Value> DTSCVec, unsigned int serial, unsigned int sequence){
|
||||
|
||||
void Page::readDTSCVector(std::vector <JSON::Value> DTSCVec, unsigned int serial, unsigned int sequence) {
|
||||
clear();
|
||||
setVersion();
|
||||
if (DTSCVec[0]["OggCont"] ){//if it is a continue page, also for granule=0xFFFFFFFF
|
||||
if (DTSCVec[0]["OggCont"]) {//if it is a continue page, also for granule=0xFFFFFFFF
|
||||
setHeaderType(1);//headertype 1 = Continue Page
|
||||
}else if (DTSCVec[0]["OggEOS"]){
|
||||
} else if (DTSCVec[0]["OggEOS"]) {
|
||||
setHeaderType(4);//headertype 4 = end of stream
|
||||
}else{
|
||||
} else {
|
||||
setHeaderType(0);//headertype 0 = normal
|
||||
}
|
||||
setGranulePosition(DTSCVec[0]["granule"].asInt());
|
||||
for (unsigned int i = 1; i < DTSCVec.size(); i++){
|
||||
if (DTSCVec[0]["granule"].asInt() != DTSCVec[i]["granule"].asInt()){
|
||||
for (unsigned int i = 1; i < DTSCVec.size(); i++) {
|
||||
if (DTSCVec[0]["granule"].asInt() != DTSCVec[i]["granule"].asInt()) {
|
||||
DEBUG_MSG(DLVL_WARN, "Granule inconcistency!! %u != %u", (unsigned int)DTSCVec[0]["granule"].asInt(), (unsigned int)DTSCVec[i]["granule"].asInt());
|
||||
}
|
||||
if (DTSCVec[0]["trackid"].asInt() != DTSCVec[i]["trackid"].asInt()){
|
||||
if (DTSCVec[0]["trackid"].asInt() != DTSCVec[i]["trackid"].asInt()) {
|
||||
DEBUG_MSG(DLVL_WARN, "Track ID inconcistency!! %u != %u", (unsigned int)DTSCVec[0]["trackid"].asInt(), (unsigned int)DTSCVec[i]["trackid"].asInt());
|
||||
}
|
||||
}
|
||||
setBitstreamSerialNumber(serial);
|
||||
setPageSequenceNumber(sequence);
|
||||
|
||||
|
||||
std::vector<unsigned int> curSegTable;
|
||||
std::string pageBuffer;
|
||||
|
||||
for (unsigned int i = 0; i < DTSCVec.size(); i++){
|
||||
for (unsigned int i = 0; i < DTSCVec.size(); i++) {
|
||||
curSegTable.push_back(DTSCVec[i]["data"].asString().size());
|
||||
pageBuffer += DTSCVec[i]["data"].asString();
|
||||
}
|
||||
setSegmentTable(curSegTable);
|
||||
setPayload((char*)pageBuffer.c_str(), pageBuffer.size());
|
||||
setPayload((char *)pageBuffer.c_str(), pageBuffer.size());
|
||||
setCRCChecksum(calcChecksum());
|
||||
}
|
||||
|
||||
void headerPages::readDTSCHeader(DTSC::Meta & meta){
|
||||
|
||||
void headerPages::readDTSCHeader(DTSC::Meta & meta) {
|
||||
//pages.clear();
|
||||
parsedPages = "";
|
||||
Page curOggPage;
|
||||
srand (Util::getMS());//randomising with milliseconds from boot
|
||||
srand(Util::getMS()); //randomising with milliseconds from boot
|
||||
std::vector<unsigned int> curSegTable;
|
||||
DTSCID2OGGSerial.clear();
|
||||
DTSCID2seqNum.clear();
|
||||
//Creating ID headers for theora and vorbis
|
||||
for ( std::map<int,DTSC::Track>::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it ++) {
|
||||
for (std::map<int, DTSC::Track>::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it ++) {
|
||||
curOggPage.clear();
|
||||
curOggPage.setVersion();
|
||||
curOggPage.setHeaderType(2);//headertype 2 = Begin of Stream
|
||||
curOggPage.setGranulePosition(0);
|
||||
DTSCID2OGGSerial[it->second.trackID] = rand() % 0xFFFFFFFE +1; //initialising on a random not 0 number
|
||||
DTSCID2OGGSerial[it->second.trackID] = rand() % 0xFFFFFFFE + 1; //initialising on a random not 0 number
|
||||
curOggPage.setBitstreamSerialNumber(DTSCID2OGGSerial[it->second.trackID]);
|
||||
DTSCID2seqNum[it->second.trackID] = 0;
|
||||
curOggPage.setPageSequenceNumber(DTSCID2seqNum[it->second.trackID]++);
|
||||
curSegTable.clear();
|
||||
curSegTable.push_back(it->second.idHeader.size());
|
||||
curOggPage.setSegmentTable(curSegTable);
|
||||
curOggPage.setPayload((char*)it->second.idHeader.c_str(), it->second.idHeader.size());
|
||||
curOggPage.setPayload((char *)it->second.idHeader.c_str(), it->second.idHeader.size());
|
||||
curOggPage.setCRCChecksum(curOggPage.calcChecksum());
|
||||
//std::cout << std::string(curOggPage.getPage(), curOggPage.getPageSize());
|
||||
//pages.push_back(curOggPage);
|
||||
|
@ -533,7 +532,7 @@ namespace OGG{
|
|||
//Creating remaining headers for theora and vorbis
|
||||
//for tracks in header
|
||||
//create standard page with comment (empty) en setup header(init)
|
||||
for ( std::map<int,DTSC::Track>::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it ++) {
|
||||
for (std::map<int, DTSC::Track>::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it ++) {
|
||||
curOggPage.clear();
|
||||
curOggPage.setVersion();
|
||||
curOggPage.setHeaderType(0);//headertype 0 = normal
|
||||
|
@ -545,7 +544,7 @@ namespace OGG{
|
|||
curSegTable.push_back(it->second.init.size());
|
||||
curOggPage.setSegmentTable(curSegTable);
|
||||
std::string fullHeader = it->second.commentHeader + it->second.init;
|
||||
curOggPage.setPayload((char*)fullHeader.c_str(),fullHeader.size());
|
||||
curOggPage.setPayload((char *)fullHeader.c_str(), fullHeader.size());
|
||||
curOggPage.setCRCChecksum(curOggPage.calcChecksum());
|
||||
//std::cout << std::string(curOggPage.getPage(), curOggPage.getPageSize());
|
||||
//pages.push_back(curOggPage);
|
||||
|
|
26
lib/ogg.h
26
lib/ogg.h
|
@ -8,15 +8,15 @@
|
|||
#include "vorbis.h"
|
||||
#include "json.h"
|
||||
|
||||
namespace OGG{
|
||||
|
||||
enum HeaderType{
|
||||
namespace OGG {
|
||||
|
||||
enum HeaderType {
|
||||
Continued = 1,
|
||||
BeginOfStream = 2,
|
||||
EndOfStream = 4
|
||||
};
|
||||
|
||||
class Page{
|
||||
|
||||
class Page {
|
||||
public:
|
||||
Page();
|
||||
~Page();
|
||||
|
@ -38,30 +38,30 @@ namespace OGG{
|
|||
void setCRCChecksum(long unsigned int newVal);
|
||||
char getPageSegments();
|
||||
inline void setPageSegments(char newVal);
|
||||
char* getSegmentTable();
|
||||
char * getSegmentTable();
|
||||
std::deque<unsigned int> & getSegmentTableDeque();
|
||||
bool setSegmentTable(std::vector<unsigned int> layout);
|
||||
void setSegmentTable(char* newVal, unsigned int length);
|
||||
char* getPage();//returns complete page with header
|
||||
void setSegmentTable(char * newVal, unsigned int length);
|
||||
char * getPage(); //returns complete page with header
|
||||
unsigned long int getPageSize();
|
||||
char* getFullPayload();//returns all segments in the page
|
||||
char * getFullPayload(); //returns all segments in the page
|
||||
int getPayloadSize();
|
||||
std::string toPrettyString(size_t indent = 0);
|
||||
void setInternalCodec(std::string myCodec);
|
||||
long unsigned int calcChecksum();
|
||||
bool clear();
|
||||
bool setPayload(char* newData, unsigned int length);
|
||||
bool setPayload(char * newData, unsigned int length);
|
||||
void readDTSCVector(std::vector <JSON::Value> DTSCVec, unsigned int serial, unsigned int sequence);
|
||||
private:
|
||||
std::deque<unsigned int> segmentTableDeque;
|
||||
char* data;//pointer to the beginning of the Page data
|
||||
char * data; //pointer to the beginning of the Page data
|
||||
unsigned int datasize;//size of the allocated memory
|
||||
unsigned int dataSum;//size of the total segments
|
||||
bool checkDataSize(unsigned int size);
|
||||
std::string codec;//codec in the page
|
||||
};
|
||||
|
||||
class headerPages{
|
||||
|
||||
class headerPages {
|
||||
public:
|
||||
void readDTSCHeader(DTSC::Meta & meta);
|
||||
std::map <long long unsigned int, unsigned int> DTSCID2OGGSerial;
|
||||
|
|
366
lib/procs.cpp
366
lib/procs.cpp
|
@ -25,13 +25,17 @@ std::map<pid_t, std::string> Util::Procs::plist;
|
|||
std::map<pid_t, Util::TerminationNotifier> Util::Procs::exitHandlers;
|
||||
bool Util::Procs::handler_set = false;
|
||||
|
||||
static bool childRunning(pid_t p){
|
||||
static bool childRunning(pid_t p) {
|
||||
pid_t ret = waitpid(p, 0, WNOHANG);
|
||||
if (ret == p){return false;}
|
||||
if (ret < 0 && errno == EINTR){
|
||||
if (ret == p) {
|
||||
return false;
|
||||
}
|
||||
if (ret < 0 && errno == EINTR) {
|
||||
return childRunning(p);
|
||||
}
|
||||
if (kill(p, 0) == 0){return true;}
|
||||
if (kill(p, 0) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -39,121 +43,129 @@ static bool childRunning(pid_t p){
|
|||
/// Waits up to 1 second, then sends SIGINT signal to all managed processes.
|
||||
/// After that waits up to 5 seconds for children to exit, then sends SIGKILL to
|
||||
/// all remaining children. Waits one more second for cleanup to finish, then exits.
|
||||
void Util::Procs::exit_handler(){
|
||||
void Util::Procs::exit_handler() {
|
||||
int waiting = 0;
|
||||
std::map<pid_t, std::string> listcopy = plist;
|
||||
std::map<pid_t, std::string>::iterator it;
|
||||
if (listcopy.empty()){return;}
|
||||
if (listcopy.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//wait up to 0.5 second for applications to shut down
|
||||
while ( !listcopy.empty() && waiting <= 25){
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++){
|
||||
if ( !childRunning((*it).first)){
|
||||
//wait up to 0.5 second for applications to shut down
|
||||
while (!listcopy.empty() && waiting <= 25) {
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||
if (!childRunning((*it).first)) {
|
||||
listcopy.erase(it);
|
||||
break;
|
||||
}
|
||||
if ( !listcopy.empty()){
|
||||
if (!listcopy.empty()) {
|
||||
Util::sleep(20);
|
||||
++waiting;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (listcopy.empty()){return;}
|
||||
|
||||
if (listcopy.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_MSG(DLVL_DEVEL, "Sending SIGINT to remaining %d children", (int)listcopy.size());
|
||||
//send sigint to all remaining
|
||||
if ( !listcopy.empty()){
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++){
|
||||
DEBUG_MSG(DLVL_DEVEL, "SIGINT %d: %s", ( *it).first, ( *it).second.c_str());
|
||||
kill(( *it).first, SIGINT);
|
||||
if (!listcopy.empty()) {
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "SIGINT %d: %s", (*it).first, (*it).second.c_str());
|
||||
kill((*it).first, SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEBUG_MSG(DLVL_DEVEL, "Waiting up to 5 seconds for %d children to terminate.", (int)listcopy.size());
|
||||
waiting = 0;
|
||||
//wait up to 5 seconds for applications to shut down
|
||||
while ( !listcopy.empty() && waiting <= 250){
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++){
|
||||
if ( !childRunning((*it).first)){
|
||||
//wait up to 5 seconds for applications to shut down
|
||||
while (!listcopy.empty() && waiting <= 250) {
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||
if (!childRunning((*it).first)) {
|
||||
listcopy.erase(it);
|
||||
break;
|
||||
}
|
||||
if ( !listcopy.empty()){
|
||||
if (!listcopy.empty()) {
|
||||
Util::sleep(20);
|
||||
++waiting;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (listcopy.empty()){return;}
|
||||
|
||||
if (listcopy.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_MSG(DLVL_DEVEL, "Sending SIGKILL to remaining %d children", (int)listcopy.size());
|
||||
//send sigkill to all remaining
|
||||
if ( !listcopy.empty()){
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++){
|
||||
DEBUG_MSG(DLVL_DEVEL, "SIGKILL %d: %s", ( *it).first, ( *it).second.c_str());
|
||||
kill(( *it).first, SIGKILL);
|
||||
if (!listcopy.empty()) {
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "SIGKILL %d: %s", (*it).first, (*it).second.c_str());
|
||||
kill((*it).first, SIGKILL);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG(DLVL_DEVEL, "Waiting up to a second for %d children to terminate.", (int)listcopy.size());
|
||||
waiting = 0;
|
||||
//wait up to 1 second for applications to shut down
|
||||
while ( !listcopy.empty() && waiting <= 50){
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++){
|
||||
if ( !childRunning((*it).first)){
|
||||
//wait up to 1 second for applications to shut down
|
||||
while (!listcopy.empty() && waiting <= 50) {
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||
if (!childRunning((*it).first)) {
|
||||
listcopy.erase(it);
|
||||
break;
|
||||
}
|
||||
if ( !listcopy.empty()){
|
||||
if (!listcopy.empty()) {
|
||||
Util::sleep(20);
|
||||
++waiting;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (listcopy.empty()){return;}
|
||||
if (listcopy.empty()) {
|
||||
return;
|
||||
}
|
||||
DEBUG_MSG(DLVL_DEVEL, "Giving up with %d children left.", (int)listcopy.size());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Sets up exit and childsig handlers.
|
||||
/// Called by every Start* function.
|
||||
void Util::Procs::setHandler(){
|
||||
if ( !handler_set){
|
||||
void Util::Procs::setHandler() {
|
||||
if (!handler_set) {
|
||||
struct sigaction new_action;
|
||||
new_action.sa_handler = childsig_handler;
|
||||
sigemptyset( &new_action.sa_mask);
|
||||
sigemptyset(&new_action.sa_mask);
|
||||
new_action.sa_flags = 0;
|
||||
sigaction(SIGCHLD, &new_action, NULL);
|
||||
atexit(exit_handler);
|
||||
handler_set = true;
|
||||
}// else {
|
||||
// DEBUG_MSG(DLVL_DEVEL, "not setting handler");
|
||||
// }
|
||||
// DEBUG_MSG(DLVL_DEVEL, "not setting handler");
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
/// Used internally to capture child signals and update plist.
|
||||
void Util::Procs::childsig_handler(int signum){
|
||||
if (signum != SIGCHLD){
|
||||
void Util::Procs::childsig_handler(int signum) {
|
||||
if (signum != SIGCHLD) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "signum != SIGCHLD");
|
||||
return;
|
||||
}
|
||||
int status;
|
||||
pid_t ret = -1;
|
||||
while (ret != 0){
|
||||
ret = waitpid( -1, &status, WNOHANG);
|
||||
if (ret <= 0){ //ignore, would block otherwise
|
||||
if (ret == 0 || errno != EINTR){
|
||||
while (ret != 0) {
|
||||
ret = waitpid(-1, &status, WNOHANG);
|
||||
if (ret <= 0) { //ignore, would block otherwise
|
||||
if (ret == 0 || errno != EINTR) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int exitcode;
|
||||
if (WIFEXITED(status)){
|
||||
if (WIFEXITED(status)) {
|
||||
exitcode = WEXITSTATUS(status);
|
||||
}else if (WIFSIGNALED(status)){
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
exitcode = -WTERMSIG(status);
|
||||
}else{// not possible
|
||||
} else { // not possible
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -162,14 +174,14 @@ void Util::Procs::childsig_handler(int signum){
|
|||
#endif
|
||||
plist.erase(ret);
|
||||
#if DEBUG >= DLVL_HIGH
|
||||
if (!isActive(pname)){
|
||||
if (!isActive(pname)) {
|
||||
DEBUG_MSG(DLVL_HIGH, "Process %s fully terminated", pname.c_str());
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_HIGH, "Child process %d exited", ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (exitHandlers.count(ret) > 0){
|
||||
if (exitHandlers.count(ret) > 0) {
|
||||
TerminationNotifier tn = exitHandlers[ret];
|
||||
exitHandlers.erase(ret);
|
||||
tn(ret, exitcode);
|
||||
|
@ -179,15 +191,17 @@ void Util::Procs::childsig_handler(int signum){
|
|||
|
||||
|
||||
/// Runs the given command and returns the stdout output as a string.
|
||||
std::string Util::Procs::getOutputOf(char* const* argv){
|
||||
std::string Util::Procs::getOutputOf(char * const * argv) {
|
||||
std::string ret;
|
||||
int fin = 0, fout = -1, ferr = 0;
|
||||
StartPiped("output_getter", argv, &fin, &fout, &ferr);
|
||||
while (isActive("output_getter")){Util::sleep(100);}
|
||||
while (isActive("output_getter")) {
|
||||
Util::sleep(100);
|
||||
}
|
||||
FILE * outFile = fdopen(fout, "r");
|
||||
char * fileBuf = 0;
|
||||
size_t fileBufLen = 0;
|
||||
while ( !(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){
|
||||
while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)) {
|
||||
ret += fileBuf;
|
||||
}
|
||||
fclose(outFile);
|
||||
|
@ -196,15 +210,17 @@ std::string Util::Procs::getOutputOf(char* const* argv){
|
|||
}
|
||||
|
||||
/// Runs the given command and returns the stdout output as a string.
|
||||
std::string Util::Procs::getOutputOf(std::string cmd){
|
||||
std::string Util::Procs::getOutputOf(std::string cmd) {
|
||||
std::string ret;
|
||||
int fin = 0, fout = -1, ferr = 0;
|
||||
StartPiped("output_getter", cmd, &fin, &fout, &ferr);
|
||||
while (isActive("output_getter")){Util::sleep(100);}
|
||||
while (isActive("output_getter")) {
|
||||
Util::sleep(100);
|
||||
}
|
||||
FILE * outFile = fdopen(fout, "r");
|
||||
char * fileBuf = 0;
|
||||
size_t fileBufLen = 0;
|
||||
while ( !(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){
|
||||
while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)) {
|
||||
ret += fileBuf;
|
||||
}
|
||||
free(fileBuf);
|
||||
|
@ -217,21 +233,21 @@ std::string Util::Procs::getOutputOf(std::string cmd){
|
|||
/// Replaces the current process - use after forking first!
|
||||
/// This function will never return - it will either run the given
|
||||
/// command or kill itself with return code 42.
|
||||
void Util::Procs::runCmd(std::string & cmd){
|
||||
void Util::Procs::runCmd(std::string & cmd) {
|
||||
//split cmd into arguments
|
||||
//supports a maximum of 20 arguments
|
||||
char * tmp = (char*)cmd.c_str();
|
||||
char * tmp = (char *)cmd.c_str();
|
||||
char * tmp2 = 0;
|
||||
char * args[21];
|
||||
int i = 0;
|
||||
tmp2 = strtok(tmp, " ");
|
||||
args[0] = tmp2;
|
||||
while (tmp2 != 0 && (i < 20)){
|
||||
while (tmp2 != 0 && (i < 20)) {
|
||||
tmp2 = strtok(0, " ");
|
||||
++i;
|
||||
args[i] = tmp2;
|
||||
}
|
||||
if (i == 20){
|
||||
if (i == 20) {
|
||||
args[20] = 0;
|
||||
}
|
||||
//execute the command
|
||||
|
@ -244,19 +260,19 @@ void Util::Procs::runCmd(std::string & cmd){
|
|||
/// \return 0 if process was not started, process PID otherwise.
|
||||
/// \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)){
|
||||
pid_t Util::Procs::Start(std::string name, std::string cmd) {
|
||||
if (isActive(name)) {
|
||||
return getPid(name);
|
||||
}
|
||||
setHandler();
|
||||
pid_t ret = fork();
|
||||
if (ret == 0){
|
||||
if (ret == 0) {
|
||||
runCmd(cmd);
|
||||
}else{
|
||||
if (ret > 0){
|
||||
} else {
|
||||
if (ret > 0) {
|
||||
DEBUG_MSG(DLVL_HIGH, "Process %s started, PID %d: %s", name.c_str(), ret, cmd.c_str());
|
||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started: fork() failed", name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
@ -269,30 +285,30 @@ pid_t Util::Procs::Start(std::string name, std::string cmd){
|
|||
/// \arg name Name for this process - only used internally.
|
||||
/// \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)){
|
||||
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2) {
|
||||
if (isActive(name)) {
|
||||
return getPid(name);
|
||||
}
|
||||
setHandler();
|
||||
int pfildes[2];
|
||||
if (pipe(pfildes) == -1){
|
||||
if (pipe(pfildes) == -1) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int devnull = open("/dev/null", O_RDWR);
|
||||
pid_t ret = fork();
|
||||
if (ret == 0){
|
||||
if (ret == 0) {
|
||||
close(pfildes[0]);
|
||||
dup2(pfildes[1], STDOUT_FILENO);
|
||||
close(pfildes[1]);
|
||||
dup2(devnull, STDIN_FILENO);
|
||||
dup2(devnull, STDERR_FILENO);
|
||||
runCmd(cmd);
|
||||
}else{
|
||||
if (ret > 0){
|
||||
} else {
|
||||
if (ret > 0) {
|
||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||
close(pfildes[1]);
|
||||
close(pfildes[0]);
|
||||
|
@ -301,18 +317,18 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
|
|||
}
|
||||
|
||||
pid_t ret2 = fork();
|
||||
if (ret2 == 0){
|
||||
if (ret2 == 0) {
|
||||
close(pfildes[1]);
|
||||
dup2(pfildes[0], STDIN_FILENO);
|
||||
close(pfildes[0]);
|
||||
dup2(devnull, STDOUT_FILENO);
|
||||
dup2(devnull, STDERR_FILENO);
|
||||
runCmd(cmd2);
|
||||
}else{
|
||||
if (ret2 > 0){
|
||||
} else {
|
||||
if (ret2 > 0) {
|
||||
DEBUG_MSG(DLVL_HIGH, "Process %s started, PIDs (%d, %d): %s | %s", name.c_str(), ret, ret2, cmd.c_str(), cmd2.c_str());
|
||||
plist.insert(std::pair<pid_t, std::string>(ret2, name));
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||
Stop(name);
|
||||
close(pfildes[1]);
|
||||
|
@ -331,25 +347,25 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
|
|||
/// \arg cmd Commandline for sub (sending) process.
|
||||
/// \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)){
|
||||
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, std::string cmd3) {
|
||||
if (isActive(name)) {
|
||||
return getPid(name);
|
||||
}
|
||||
setHandler();
|
||||
int pfildes[2];
|
||||
int pfildes2[2];
|
||||
if (pipe(pfildes) == -1){
|
||||
if (pipe(pfildes) == -1) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
||||
return 0;
|
||||
}
|
||||
if (pipe(pfildes2) == -1){
|
||||
if (pipe(pfildes2) == -1) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. Pipe creation failed.", name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int devnull = open("/dev/null", O_RDWR);
|
||||
pid_t ret = fork();
|
||||
if (ret == 0){
|
||||
if (ret == 0) {
|
||||
close(pfildes[0]);
|
||||
dup2(pfildes[1], STDOUT_FILENO);
|
||||
close(pfildes[1]);
|
||||
|
@ -358,10 +374,10 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
|||
close(pfildes2[1]);
|
||||
close(pfildes2[0]);
|
||||
runCmd(cmd);
|
||||
}else{
|
||||
if (ret > 0){
|
||||
} else {
|
||||
if (ret > 0) {
|
||||
plist.insert(std::pair<pid_t, std::string>(ret, name));
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||
close(pfildes[1]);
|
||||
close(pfildes[0]);
|
||||
|
@ -372,7 +388,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
|||
}
|
||||
|
||||
pid_t ret2 = fork();
|
||||
if (ret2 == 0){
|
||||
if (ret2 == 0) {
|
||||
close(pfildes[1]);
|
||||
close(pfildes2[0]);
|
||||
dup2(pfildes[0], STDIN_FILENO);
|
||||
|
@ -381,11 +397,11 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
|||
close(pfildes2[1]);
|
||||
dup2(devnull, STDERR_FILENO);
|
||||
runCmd(cmd2);
|
||||
}else{
|
||||
if (ret2 > 0){
|
||||
} else {
|
||||
if (ret2 > 0) {
|
||||
DEBUG_MSG(DLVL_HIGH, "Process %s started, PIDs (%d, %d): %s | %s", name.c_str(), ret, ret2, cmd.c_str(), cmd2.c_str());
|
||||
plist.insert(std::pair<pid_t, std::string>(ret2, name));
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||
Stop(name);
|
||||
close(pfildes[1]);
|
||||
|
@ -399,7 +415,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
|||
close(pfildes[0]);
|
||||
|
||||
pid_t ret3 = fork();
|
||||
if (ret3 == 0){
|
||||
if (ret3 == 0) {
|
||||
close(pfildes[1]);
|
||||
close(pfildes[0]);
|
||||
close(pfildes2[1]);
|
||||
|
@ -408,11 +424,11 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
|||
dup2(devnull, STDOUT_FILENO);
|
||||
dup2(devnull, STDERR_FILENO);
|
||||
runCmd(cmd3);
|
||||
}else{
|
||||
if (ret3 > 0){
|
||||
} else {
|
||||
if (ret3 > 0) {
|
||||
DEBUG_MSG(DLVL_HIGH, "Process %s started, PIDs (%d, %d, %d): %s | %s | %s", name.c_str(), ret, ret2, ret3, cmd.c_str(), cmd2.c_str(), cmd3.c_str());
|
||||
plist.insert(std::pair<pid_t, std::string>(ret3, name));
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_ERROR, "Process %s could not be started. fork() failed.", name.c_str());
|
||||
Stop(name);
|
||||
close(pfildes[1]);
|
||||
|
@ -433,61 +449,61 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st
|
|||
/// \arg fdin Standard input file descriptor. If null, /dev/null is assumed. Otherwise, if arg contains -1, a new fd is automatically allocated and written into this arg. Then the arg will be used as fd.
|
||||
/// \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* const* argv, int * fdin, int * fdout, int * fderr){
|
||||
if (isActive(name)){
|
||||
pid_t Util::Procs::StartPiped(std::string name, char * const * argv, int * fdin, int * fdout, int * fderr) {
|
||||
if (isActive(name)) {
|
||||
DEBUG_MSG(DLVL_WARN, "Process %s already active - skipping start", name.c_str());
|
||||
return getPid(name);
|
||||
}
|
||||
int pidtemp = StartPiped(argv, fdin, fdout, fderr);
|
||||
if (pidtemp > 0 ) {
|
||||
if (pidtemp > 0) {
|
||||
plist.insert(std::pair<pid_t, std::string>(pidtemp, name));
|
||||
}
|
||||
return pidtemp;
|
||||
}
|
||||
|
||||
pid_t Util::Procs::StartPiped(char* const* argv, int * fdin, int * fdout, int * fderr){
|
||||
pid_t Util::Procs::StartPiped(char * const * argv, int * fdin, int * fdout, int * fderr) {
|
||||
pid_t pid;
|
||||
int pipein[2], pipeout[2], pipeerr[2];
|
||||
//DEBUG_MSG(DLVL_DEVEL, "setHandler");
|
||||
setHandler();
|
||||
if (fdin && *fdin == -1 && pipe(pipein) < 0){
|
||||
if (fdin && *fdin == -1 && pipe(pipein) < 0) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Pipe in creation failed for process %s", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
if (fdout && *fdout == -1 && pipe(pipeout) < 0){
|
||||
if (fdout && *fdout == -1 && pipe(pipeout) < 0) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Pipe out creation failed for process %s", argv[0]);
|
||||
if ( *fdin == -1){
|
||||
if (*fdin == -1) {
|
||||
close(pipein[0]);
|
||||
close(pipein[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (fderr && *fderr == -1 && pipe(pipeerr) < 0){
|
||||
if (fderr && *fderr == -1 && pipe(pipeerr) < 0) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Pipe err creation failed for process %s", argv[0]);
|
||||
if ( *fdin == -1){
|
||||
if (*fdin == -1) {
|
||||
close(pipein[0]);
|
||||
close(pipein[1]);
|
||||
}
|
||||
if ( *fdout == -1){
|
||||
if (*fdout == -1) {
|
||||
close(pipeout[0]);
|
||||
close(pipeout[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int devnull = -1;
|
||||
if ( !fdin || !fdout || !fderr){
|
||||
if (!fdin || !fdout || !fderr) {
|
||||
devnull = open("/dev/null", O_RDWR);
|
||||
if (devnull == -1){
|
||||
if (devnull == -1) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Could not open /dev/null for process %s: %s", argv[0], strerror(errno));
|
||||
if ( *fdin == -1){
|
||||
if (*fdin == -1) {
|
||||
close(pipein[0]);
|
||||
close(pipein[1]);
|
||||
}
|
||||
if ( *fdout == -1){
|
||||
if (*fdout == -1) {
|
||||
close(pipeout[0]);
|
||||
close(pipeout[1]);
|
||||
}
|
||||
if ( *fderr == -1){
|
||||
if (*fderr == -1) {
|
||||
close(pipeerr[0]);
|
||||
close(pipeerr[1]);
|
||||
}
|
||||
|
@ -495,81 +511,81 @@ pid_t Util::Procs::StartPiped(char* const* argv, int * fdin, int * fdout, int *
|
|||
}
|
||||
}
|
||||
pid = fork();
|
||||
if (pid == 0){ //child
|
||||
if ( !fdin){
|
||||
if (pid == 0) { //child
|
||||
if (!fdin) {
|
||||
dup2(devnull, STDIN_FILENO);
|
||||
}else if ( *fdin == -1){
|
||||
} else if (*fdin == -1) {
|
||||
close(pipein[1]); // close unused write end
|
||||
dup2(pipein[0], STDIN_FILENO);
|
||||
close(pipein[0]);
|
||||
}else if ( *fdin != STDIN_FILENO){
|
||||
dup2( *fdin, STDIN_FILENO);
|
||||
} else if (*fdin != STDIN_FILENO) {
|
||||
dup2(*fdin, STDIN_FILENO);
|
||||
}
|
||||
if ( !fdout){
|
||||
if (!fdout) {
|
||||
dup2(devnull, STDOUT_FILENO);
|
||||
}else if ( *fdout == -1){
|
||||
} else if (*fdout == -1) {
|
||||
close(pipeout[0]); // close unused read end
|
||||
dup2(pipeout[1], STDOUT_FILENO);
|
||||
close(pipeout[1]);
|
||||
}else if ( *fdout != STDOUT_FILENO){
|
||||
dup2( *fdout, STDOUT_FILENO);
|
||||
} else if (*fdout != STDOUT_FILENO) {
|
||||
dup2(*fdout, STDOUT_FILENO);
|
||||
}
|
||||
if ( !fderr){
|
||||
if (!fderr) {
|
||||
dup2(devnull, STDERR_FILENO);
|
||||
}else if ( *fderr == -1){
|
||||
} else if (*fderr == -1) {
|
||||
close(pipeerr[0]); // close unused read end
|
||||
dup2(pipeerr[1], STDERR_FILENO);
|
||||
close(pipeerr[1]);
|
||||
}else if ( *fderr != STDERR_FILENO){
|
||||
dup2( *fderr, STDERR_FILENO);
|
||||
} else if (*fderr != STDERR_FILENO) {
|
||||
dup2(*fderr, STDERR_FILENO);
|
||||
}
|
||||
if( fdin && *fdin !=-1 && *fdin != STDIN_FILENO){
|
||||
close( *fdin);
|
||||
if (fdin && *fdin != -1 && *fdin != STDIN_FILENO) {
|
||||
close(*fdin);
|
||||
}
|
||||
if( fdout && *fdout !=-1 && *fdout != STDOUT_FILENO){
|
||||
close( *fdout);
|
||||
if (fdout && *fdout != -1 && *fdout != STDOUT_FILENO) {
|
||||
close(*fdout);
|
||||
}
|
||||
if( fderr && *fderr !=-1 && *fderr != STDERR_FILENO){
|
||||
close( *fderr);
|
||||
if (fderr && *fderr != -1 && *fderr != STDERR_FILENO) {
|
||||
close(*fderr);
|
||||
}
|
||||
if (devnull != -1){
|
||||
if (devnull != -1) {
|
||||
close(devnull);
|
||||
}
|
||||
execvp(argv[0], argv);
|
||||
DEBUG_MSG(DLVL_ERROR, "execvp() failed for process %s", argv[0]);
|
||||
exit(42);
|
||||
}else if (pid == -1){
|
||||
} else if (pid == -1) {
|
||||
DEBUG_MSG(DLVL_ERROR, "fork() for pipe failed for process %s", argv[0]);
|
||||
if (fdin && *fdin == -1){
|
||||
if (fdin && *fdin == -1) {
|
||||
close(pipein[0]);
|
||||
close(pipein[1]);
|
||||
}
|
||||
if (fdout && *fdout == -1){
|
||||
if (fdout && *fdout == -1) {
|
||||
close(pipeout[0]);
|
||||
close(pipeout[1]);
|
||||
}
|
||||
if (fderr && *fderr == -1){
|
||||
if (fderr && *fderr == -1) {
|
||||
close(pipeerr[0]);
|
||||
close(pipeerr[1]);
|
||||
}
|
||||
if (devnull != -1){
|
||||
if (devnull != -1) {
|
||||
close(devnull);
|
||||
}
|
||||
return 0;
|
||||
}else{ //parent
|
||||
} else { //parent
|
||||
DEBUG_MSG(DLVL_HIGH, "Piped process %s started, PID %d", argv[0], pid);
|
||||
if (devnull != -1){
|
||||
if (devnull != -1) {
|
||||
close(devnull);
|
||||
}
|
||||
if (fdin && *fdin == -1){
|
||||
if (fdin && *fdin == -1) {
|
||||
close(pipein[0]); // close unused end end
|
||||
*fdin = pipein[1];
|
||||
}
|
||||
if (fdout && *fdout == -1){
|
||||
if (fdout && *fdout == -1) {
|
||||
close(pipeout[1]); // close unused write end
|
||||
*fdout = pipeout[0];
|
||||
}
|
||||
if (fderr && *fderr == -1){
|
||||
if (fderr && *fderr == -1) {
|
||||
close(pipeerr[1]); // close unused write end
|
||||
*fderr = pipeerr[0];
|
||||
}
|
||||
|
@ -584,40 +600,40 @@ pid_t Util::Procs::StartPiped(char* const* argv, int * fdin, int * fdout, int *
|
|||
/// \arg fdin Standard input file descriptor. If null, /dev/null is assumed. Otherwise, if arg contains -1, a new fd is automatically allocated and written into this arg. Then the arg will be used as fd.
|
||||
/// \arg fdout Same as fdin, but for stdout.
|
||||
/// \arg fdout Same as fdin, but for stderr.
|
||||
pid_t Util::Procs::StartPiped(std::string name, std::string cmd, int * fdin, int * fdout, int * fderr){
|
||||
pid_t Util::Procs::StartPiped(std::string name, std::string cmd, int * fdin, int * fdout, int * fderr) {
|
||||
//Convert the given command to a char * []
|
||||
char * tmp = (char*)cmd.c_str();
|
||||
char * tmp = (char *)cmd.c_str();
|
||||
char * tmp2 = 0;
|
||||
char * args[21];
|
||||
int i = 0;
|
||||
tmp2 = strtok(tmp, " ");
|
||||
args[0] = tmp2;
|
||||
while (tmp2 != 0 && (i < 20)){
|
||||
while (tmp2 != 0 && (i < 20)) {
|
||||
tmp2 = strtok(0, " ");
|
||||
++i;
|
||||
args[i] = tmp2;
|
||||
}
|
||||
if (i == 20){
|
||||
if (i == 20) {
|
||||
args[20] = 0;
|
||||
}
|
||||
return StartPiped(name,args,fdin,fdout,fderr);
|
||||
return StartPiped(name, args, fdin, fdout, fderr);
|
||||
}
|
||||
|
||||
|
||||
pid_t Util::Procs::StartPiped2(std::string name, std::string cmd1, std::string cmd2, int * fdin, int * fdout, int * fderr1, int * fderr2){
|
||||
pid_t Util::Procs::StartPiped2(std::string name, std::string cmd1, std::string cmd2, int * fdin, int * fdout, int * fderr1, int * fderr2) {
|
||||
int pfildes[2];
|
||||
if (pipe(pfildes) == -1){
|
||||
if (pipe(pfildes) == -1) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Pipe creation failed for process %s", name.c_str());
|
||||
return 0;
|
||||
}
|
||||
pid_t res1 = StartPiped(name, cmd1, fdin, &pfildes[1], fderr1);
|
||||
if ( !res1){
|
||||
if (!res1) {
|
||||
close(pfildes[1]);
|
||||
close(pfildes[0]);
|
||||
return 0;
|
||||
}
|
||||
pid_t res2 = StartPiped(name+"receiving", cmd2, &pfildes[0], fdout, fderr2);
|
||||
if ( !res2){
|
||||
pid_t res2 = StartPiped(name + "receiving", cmd2, &pfildes[0], fdout, fderr2);
|
||||
if (!res2) {
|
||||
Stop(res1);
|
||||
close(pfildes[1]);
|
||||
close(pfildes[0]);
|
||||
|
@ -630,12 +646,12 @@ pid_t Util::Procs::StartPiped2(std::string name, std::string cmd1, std::string c
|
|||
}
|
||||
/// Stops the named process, if running.
|
||||
/// \arg name (Internal) name of process to stop
|
||||
void Util::Procs::Stop(std::string name){
|
||||
void Util::Procs::Stop(std::string name) {
|
||||
int max = 5;
|
||||
while (isActive(name)){
|
||||
while (isActive(name)) {
|
||||
Stop(getPid(name));
|
||||
max--;
|
||||
if (max <= 0){
|
||||
if (max <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -643,36 +659,36 @@ void Util::Procs::Stop(std::string name){
|
|||
|
||||
/// Stops the process with this pid, if running.
|
||||
/// \arg name The PID of the process to stop.
|
||||
void Util::Procs::Stop(pid_t name){
|
||||
if (isActive(name)){
|
||||
void Util::Procs::Stop(pid_t name) {
|
||||
if (isActive(name)) {
|
||||
kill(name, SIGTERM);
|
||||
}
|
||||
}
|
||||
|
||||
/// (Attempts to) stop all running child processes.
|
||||
void Util::Procs::StopAll(){
|
||||
void Util::Procs::StopAll() {
|
||||
std::map<pid_t, std::string> listcopy = plist;
|
||||
std::map<pid_t, std::string>::iterator it;
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++){
|
||||
Stop(( *it).first);
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||
Stop((*it).first);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of active child processes.
|
||||
int Util::Procs::Count(){
|
||||
int Util::Procs::Count() {
|
||||
return plist.size();
|
||||
}
|
||||
|
||||
/// Returns true if a process by this name is currently active.
|
||||
bool Util::Procs::isActive(std::string name){
|
||||
bool Util::Procs::isActive(std::string name) {
|
||||
std::map<pid_t, std::string> listcopy = plist;
|
||||
std::map<pid_t, std::string>::iterator it;
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++){
|
||||
if (( *it).second == name){
|
||||
if (childRunning(( *it).first)){
|
||||
for (it = listcopy.begin(); it != listcopy.end(); it++) {
|
||||
if ((*it).second == name) {
|
||||
if (childRunning((*it).first)) {
|
||||
return true;
|
||||
}else{
|
||||
plist.erase(( *it).first);
|
||||
} else {
|
||||
plist.erase((*it).first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -680,17 +696,17 @@ bool Util::Procs::isActive(std::string name){
|
|||
}
|
||||
|
||||
/// Returns true if a process with this PID is currently active.
|
||||
bool Util::Procs::isActive(pid_t name){
|
||||
bool Util::Procs::isActive(pid_t name) {
|
||||
return (plist.count(name) == 1) && (kill(name, 0) == 0);
|
||||
}
|
||||
|
||||
/// Gets PID for this named process, if active.
|
||||
/// \return NULL if not active, process PID otherwise.
|
||||
pid_t Util::Procs::getPid(std::string 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;
|
||||
for (it = plist.begin(); it != plist.end(); it++) {
|
||||
if ((*it).second == name) {
|
||||
return (*it).first;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -698,8 +714,8 @@ pid_t Util::Procs::getPid(std::string name){
|
|||
|
||||
/// Gets name for this process PID, if active.
|
||||
/// \return Empty string if not active, name otherwise.
|
||||
std::string Util::Procs::getName(pid_t name){
|
||||
if (plist.count(name) == 1){
|
||||
std::string Util::Procs::getName(pid_t name) {
|
||||
if (plist.count(name) == 1) {
|
||||
return plist[name];
|
||||
}
|
||||
return "";
|
||||
|
@ -707,8 +723,8 @@ std::string Util::Procs::getName(pid_t name){
|
|||
|
||||
/// Registers one notifier function for when a process indentified by PID terminates.
|
||||
/// \return true if the notifier could be registered, false otherwise.
|
||||
bool Util::Procs::SetTerminationNotifier(pid_t pid, TerminationNotifier notifier){
|
||||
if (plist.find(pid) != plist.end()){
|
||||
bool Util::Procs::SetTerminationNotifier(pid_t pid, TerminationNotifier notifier) {
|
||||
if (plist.find(pid) != plist.end()) {
|
||||
exitHandlers[pid] = notifier;
|
||||
return true;
|
||||
}
|
||||
|
|
14
lib/procs.h
14
lib/procs.h
|
@ -13,7 +13,7 @@ namespace Util {
|
|||
typedef void (*TerminationNotifier)(pid_t pid, int exitCode);
|
||||
|
||||
/// Deals with spawning, monitoring and stopping child processes
|
||||
class Procs{
|
||||
class Procs {
|
||||
private:
|
||||
static std::map<pid_t, std::string> plist; ///< Holds active processes
|
||||
static std::map<pid_t, TerminationNotifier> exitHandlers; ///< termination function, if any
|
||||
|
@ -22,16 +22,16 @@ namespace Util {
|
|||
static void exit_handler();
|
||||
static void runCmd(std::string & cmd);
|
||||
static void setHandler();
|
||||
public:
|
||||
static std::string getOutputOf(char* const* argv);
|
||||
public:
|
||||
static std::string getOutputOf(char * const * argv);
|
||||
static std::string getOutputOf(std::string cmd);
|
||||
static pid_t Start(std::string name, std::string cmd);
|
||||
static pid_t Start(std::string name, std::string cmd, std::string cmd2);
|
||||
static pid_t Start(std::string name, std::string cmd, std::string cmd2, std::string cmd3);
|
||||
|
||||
static pid_t StartPiped(char* const* argv, int * fdin, int * fdout, int * fderr);
|
||||
static pid_t StartPiped(std::string name, char* const* argv, int * fdin, int * fdout, int * fderr);
|
||||
|
||||
|
||||
static pid_t StartPiped(char * const * argv, int * fdin, int * fdout, int * fderr);
|
||||
static pid_t StartPiped(std::string name, char * const * argv, int * fdin, int * fdout, int * fderr);
|
||||
|
||||
static pid_t StartPiped(std::string name, std::string cmd, int * fdin, int * fdout, int * fderr);
|
||||
static pid_t StartPiped2(std::string name, std::string cmd1, std::string cmd2, int * fdin, int * fdout, int * fderr1, int * fderr2);
|
||||
static void Stop(std::string name);
|
||||
|
|
|
@ -39,59 +39,61 @@ std::map<unsigned int, RTMPStream::Chunk> RTMPStream::lastrecv;
|
|||
#include <openssl/hmac.h>
|
||||
|
||||
#define P1024 \
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"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
|
||||
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
|
||||
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){
|
||||
inline uint32_t GetDigestOffset(uint8_t * pBuffer, uint8_t scheme) {
|
||||
if (scheme == 0) {
|
||||
return ((pBuffer[8] + pBuffer[9] + pBuffer[10] + pBuffer[11]) % 728) + 12;
|
||||
}else{
|
||||
} else {
|
||||
return ((pBuffer[772] + pBuffer[773] + pBuffer[774] + pBuffer[775]) % 728) + 776;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t GetDHOffset(uint8_t *pBuffer, uint8_t scheme){
|
||||
if (scheme == 0){
|
||||
inline uint32_t GetDHOffset(uint8_t * pBuffer, uint8_t scheme) {
|
||||
if (scheme == 0) {
|
||||
return ((pBuffer[1532] + pBuffer[1533] + pBuffer[1534] + pBuffer[1535]) % 632) + 772;
|
||||
}else{
|
||||
} else {
|
||||
return ((pBuffer[768] + pBuffer[769] + pBuffer[770] + pBuffer[771]) % 632) + 8;
|
||||
}
|
||||
}
|
||||
|
||||
class DHWrapper{
|
||||
class DHWrapper {
|
||||
private:
|
||||
int32_t _bitsCount;
|
||||
DH *_pDH;
|
||||
uint8_t *_pSharedKey;
|
||||
DH * _pDH;
|
||||
uint8_t * _pSharedKey;
|
||||
int32_t _sharedKeyLength;
|
||||
BIGNUM *_peerPublickey;
|
||||
BIGNUM * _peerPublickey;
|
||||
public:
|
||||
DHWrapper(int32_t bitsCount);
|
||||
virtual ~DHWrapper();
|
||||
bool Initialize();
|
||||
bool CopyPublicKey(uint8_t *pDst, int32_t dstLength);
|
||||
bool CopyPrivateKey(uint8_t *pDst, int32_t dstLength);
|
||||
bool CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length);
|
||||
bool CopySharedKey(uint8_t *pDst, int32_t dstLength);
|
||||
bool CopyPublicKey(uint8_t * pDst, int32_t dstLength);
|
||||
bool CopyPrivateKey(uint8_t * pDst, int32_t dstLength);
|
||||
bool CreateSharedKey(uint8_t * pPeerPublicKey, int32_t length);
|
||||
bool CopySharedKey(uint8_t * pDst, int32_t dstLength);
|
||||
private:
|
||||
void Cleanup();
|
||||
bool CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength);
|
||||
bool CopyKey(BIGNUM * pNum, uint8_t * pDst, int32_t dstLength);
|
||||
};
|
||||
|
||||
DHWrapper::DHWrapper(int32_t bitsCount){
|
||||
DHWrapper::DHWrapper(int32_t bitsCount) {
|
||||
_bitsCount = bitsCount;
|
||||
_pDH = 0;
|
||||
_pSharedKey = 0;
|
||||
|
@ -99,73 +101,73 @@ DHWrapper::DHWrapper(int32_t bitsCount){
|
|||
_peerPublickey = 0;
|
||||
}
|
||||
|
||||
DHWrapper::~DHWrapper(){
|
||||
DHWrapper::~DHWrapper() {
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
bool DHWrapper::Initialize(){
|
||||
bool DHWrapper::Initialize() {
|
||||
Cleanup();
|
||||
_pDH = DH_new();
|
||||
if ( !_pDH){
|
||||
if (!_pDH) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
_pDH->p = BN_new();
|
||||
if ( !_pDH->p){
|
||||
if (!_pDH->p) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
_pDH->g = BN_new();
|
||||
if ( !_pDH->g){
|
||||
if (!_pDH->g) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
if (BN_hex2bn( &_pDH->p, P1024) == 0){
|
||||
if (BN_hex2bn(&_pDH->p, P1024) == 0) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
if (BN_set_word(_pDH->g, 2) != 1){
|
||||
if (BN_set_word(_pDH->g, 2) != 1) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
_pDH->length = _bitsCount;
|
||||
if (DH_generate_key(_pDH) != 1){
|
||||
if (DH_generate_key(_pDH) != 1) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength){
|
||||
if ( !_pDH){
|
||||
bool DHWrapper::CopyPublicKey(uint8_t * pDst, int32_t dstLength) {
|
||||
if (!_pDH) {
|
||||
return false;
|
||||
}
|
||||
return CopyKey(_pDH->pub_key, pDst, dstLength);
|
||||
}
|
||||
|
||||
bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength){
|
||||
if ( !_pDH){
|
||||
bool DHWrapper::CopyPrivateKey(uint8_t * pDst, int32_t dstLength) {
|
||||
if (!_pDH) {
|
||||
return false;
|
||||
}
|
||||
return CopyKey(_pDH->priv_key, pDst, dstLength);
|
||||
}
|
||||
|
||||
bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length){
|
||||
if ( !_pDH){
|
||||
bool DHWrapper::CreateSharedKey(uint8_t * pPeerPublicKey, int32_t length) {
|
||||
if (!_pDH) {
|
||||
return false;
|
||||
}
|
||||
if (_sharedKeyLength != 0 || _pSharedKey){
|
||||
if (_sharedKeyLength != 0 || _pSharedKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_sharedKeyLength = DH_size(_pDH);
|
||||
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024){
|
||||
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_pSharedKey = new uint8_t[_sharedKeyLength];
|
||||
_peerPublickey = BN_bin2bn(pPeerPublicKey, length, 0);
|
||||
if ( !_peerPublickey){
|
||||
if (!_peerPublickey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -173,93 +175,93 @@ bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length){
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength){
|
||||
if ( !_pDH){
|
||||
bool DHWrapper::CopySharedKey(uint8_t * pDst, int32_t dstLength) {
|
||||
if (!_pDH) {
|
||||
return false;
|
||||
}
|
||||
if (dstLength != _sharedKeyLength){
|
||||
if (dstLength != _sharedKeyLength) {
|
||||
return false;
|
||||
}
|
||||
memcpy(pDst, _pSharedKey, _sharedKeyLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DHWrapper::Cleanup(){
|
||||
if (_pDH){
|
||||
if (_pDH->p){
|
||||
void DHWrapper::Cleanup() {
|
||||
if (_pDH) {
|
||||
if (_pDH->p) {
|
||||
BN_free(_pDH->p);
|
||||
_pDH->p = 0;
|
||||
}
|
||||
if (_pDH->g){
|
||||
if (_pDH->g) {
|
||||
BN_free(_pDH->g);
|
||||
_pDH->g = 0;
|
||||
}
|
||||
DH_free(_pDH);
|
||||
_pDH = 0;
|
||||
}
|
||||
if (_pSharedKey){
|
||||
if (_pSharedKey) {
|
||||
delete[] _pSharedKey;
|
||||
_pSharedKey = 0;
|
||||
}
|
||||
_sharedKeyLength = 0;
|
||||
if (_peerPublickey){
|
||||
if (_peerPublickey) {
|
||||
BN_free(_peerPublickey);
|
||||
_peerPublickey = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool DHWrapper::CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength){
|
||||
bool DHWrapper::CopyKey(BIGNUM * pNum, uint8_t * pDst, int32_t dstLength) {
|
||||
int32_t keySize = BN_num_bytes(pNum);
|
||||
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)){
|
||||
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)) {
|
||||
return false;
|
||||
}
|
||||
if (BN_bn2bin(pNum, pDst) != keySize){
|
||||
if (BN_bn2bin(pNum, pDst) != keySize) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut){
|
||||
void InitRC4Encryption(uint8_t * secretKey, uint8_t * pubKeyIn, uint8_t * pubKeyOut, RC4_KEY * rc4keyIn, RC4_KEY * rc4keyOut) {
|
||||
uint8_t digest[SHA256_DIGEST_LENGTH];
|
||||
unsigned int digestLen = 0;
|
||||
|
||||
HMAC_CTX ctx;
|
||||
HMAC_CTX_init( &ctx);
|
||||
HMAC_Init_ex( &ctx, secretKey, 128, EVP_sha256(), 0);
|
||||
HMAC_Update( &ctx, pubKeyIn, 128);
|
||||
HMAC_Final( &ctx, digest, &digestLen);
|
||||
HMAC_CTX_cleanup( &ctx);
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
|
||||
HMAC_Update(&ctx, pubKeyIn, 128);
|
||||
HMAC_Final(&ctx, digest, &digestLen);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
|
||||
RC4_set_key(rc4keyOut, 16, digest);
|
||||
|
||||
HMAC_CTX_init( &ctx);
|
||||
HMAC_Init_ex( &ctx, secretKey, 128, EVP_sha256(), 0);
|
||||
HMAC_Update( &ctx, pubKeyOut, 128);
|
||||
HMAC_Final( &ctx, digest, &digestLen);
|
||||
HMAC_CTX_cleanup( &ctx);
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
|
||||
HMAC_Update(&ctx, pubKeyOut, 128);
|
||||
HMAC_Final(&ctx, digest, &digestLen);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
|
||||
RC4_set_key(rc4keyIn, 16, digest);
|
||||
}
|
||||
|
||||
void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult){
|
||||
void HMACsha256(const void * pData, uint32_t dataLength, const void * pKey, uint32_t keyLength, void * pResult) {
|
||||
unsigned int digestLen;
|
||||
HMAC_CTX ctx;
|
||||
HMAC_CTX_init( &ctx);
|
||||
HMAC_Init_ex( &ctx, (unsigned char*)pKey, keyLength, EVP_sha256(), 0);
|
||||
HMAC_Update( &ctx, (unsigned char *)pData, dataLength);
|
||||
HMAC_Final( &ctx, (unsigned char *)pResult, &digestLen);
|
||||
HMAC_CTX_cleanup( &ctx);
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init_ex(&ctx, (unsigned char *)pKey, keyLength, EVP_sha256(), 0);
|
||||
HMAC_Update(&ctx, (unsigned char *)pData, dataLength);
|
||||
HMAC_Final(&ctx, (unsigned char *)pResult, &digestLen);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
}
|
||||
|
||||
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme){
|
||||
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme) {
|
||||
uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme);
|
||||
uint8_t *pTempBuffer = new uint8_t[1536 - 32];
|
||||
uint8_t * pTempBuffer = new uint8_t[1536 - 32];
|
||||
memcpy(pTempBuffer, pBuffer, clientDigestOffset);
|
||||
memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32);
|
||||
uint8_t *pTempHash = new uint8_t[512];
|
||||
uint8_t * pTempHash = new uint8_t[512];
|
||||
HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
|
||||
bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0);
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Client scheme validation %hhi %s", scheme, result?"success":"failed");
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Client scheme validation %hhi %s", scheme, result ? "success" : "failed");
|
||||
delete[] pTempBuffer;
|
||||
delete[] pTempHash;
|
||||
return result;
|
||||
|
@ -268,58 +270,58 @@ bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme){
|
|||
/// Packs up the chunk for sending over the network.
|
||||
/// \warning Do not call if you are not actually sending the resulting data!
|
||||
/// \returns A std::string ready to be sent.
|
||||
std::string & RTMPStream::Chunk::Pack(){
|
||||
std::string & RTMPStream::Chunk::Pack() {
|
||||
static std::string output;
|
||||
output.clear();
|
||||
bool allow_short = lastsend.count(cs_id);
|
||||
RTMPStream::Chunk prev = lastsend[cs_id];
|
||||
unsigned int tmpi;
|
||||
unsigned char chtype = 0x00;
|
||||
if (allow_short && (prev.cs_id == cs_id)){
|
||||
if (msg_stream_id == prev.msg_stream_id){
|
||||
if (allow_short && (prev.cs_id == cs_id)) {
|
||||
if (msg_stream_id == prev.msg_stream_id) {
|
||||
chtype = 0x40; //do not send msg_stream_id
|
||||
if (len == prev.len){
|
||||
if (msg_type_id == prev.msg_type_id){
|
||||
if (len == prev.len) {
|
||||
if (msg_type_id == prev.msg_type_id) {
|
||||
chtype = 0x80; //do not send len and msg_type_id
|
||||
if (timestamp == prev.timestamp){
|
||||
if (timestamp == prev.timestamp) {
|
||||
chtype = 0xC0; //do not send timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//override - we always sent type 0x00 if the timestamp has decreased since last chunk in this channel
|
||||
if (timestamp < prev.timestamp){
|
||||
if (timestamp < prev.timestamp) {
|
||||
chtype = 0x00;
|
||||
}
|
||||
}
|
||||
if (cs_id <= 63){
|
||||
if (cs_id <= 63) {
|
||||
output += (unsigned char)(chtype | cs_id);
|
||||
}else{
|
||||
if (cs_id <= 255 + 64){
|
||||
} else {
|
||||
if (cs_id <= 255 + 64) {
|
||||
output += (unsigned char)(chtype | 0);
|
||||
output += (unsigned char)(cs_id - 64);
|
||||
}else{
|
||||
} else {
|
||||
output += (unsigned char)(chtype | 1);
|
||||
output += (unsigned char)((cs_id - 64) % 256);
|
||||
output += (unsigned char)((cs_id - 64) / 256);
|
||||
}
|
||||
}
|
||||
unsigned int ntime = 0;
|
||||
if (chtype != 0xC0){
|
||||
if (chtype != 0xC0) {
|
||||
//timestamp or timestamp diff
|
||||
if (chtype == 0x00){
|
||||
if (chtype == 0x00) {
|
||||
tmpi = timestamp;
|
||||
}else{
|
||||
} else {
|
||||
tmpi = timestamp - prev.timestamp;
|
||||
}
|
||||
if (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);
|
||||
if (chtype != 0x80){
|
||||
if (chtype != 0x80) {
|
||||
//len
|
||||
tmpi = len;
|
||||
output += (unsigned char)((tmpi >> 16) & 0xff);
|
||||
|
@ -327,7 +329,7 @@ std::string & RTMPStream::Chunk::Pack(){
|
|||
output += (unsigned char)(tmpi & 0xff);
|
||||
//msg type id
|
||||
output += (unsigned char)msg_type_id;
|
||||
if (chtype != 0x40){
|
||||
if (chtype != 0x40) {
|
||||
//msg stream id
|
||||
output += (unsigned char)(msg_stream_id % 256);
|
||||
output += (unsigned char)(msg_stream_id / 256);
|
||||
|
@ -337,28 +339,28 @@ std::string & RTMPStream::Chunk::Pack(){
|
|||
}
|
||||
}
|
||||
//support for 0x00ffffff timestamps
|
||||
if (ntime){
|
||||
if (ntime) {
|
||||
output += (unsigned char)(ntime & 0xff);
|
||||
output += (unsigned char)((ntime >> 8) & 0xff);
|
||||
output += (unsigned char)((ntime >> 16) & 0xff);
|
||||
output += (unsigned char)((ntime >> 24) & 0xff);
|
||||
}
|
||||
len_left = 0;
|
||||
while (len_left < len){
|
||||
while (len_left < len) {
|
||||
tmpi = len - len_left;
|
||||
if (tmpi > RTMPStream::chunk_snd_max){
|
||||
if (tmpi > RTMPStream::chunk_snd_max) {
|
||||
tmpi = RTMPStream::chunk_snd_max;
|
||||
}
|
||||
output.append(data, len_left, tmpi);
|
||||
len_left += tmpi;
|
||||
if (len_left < len){
|
||||
if (cs_id <= 63){
|
||||
if (len_left < len) {
|
||||
if (cs_id <= 63) {
|
||||
output += (unsigned char)(0xC0 + cs_id);
|
||||
}else{
|
||||
if (cs_id <= 255 + 64){
|
||||
} else {
|
||||
if (cs_id <= 255 + 64) {
|
||||
output += (unsigned char)(0xC0);
|
||||
output += (unsigned char)(cs_id - 64);
|
||||
}else{
|
||||
} else {
|
||||
output += (unsigned char)(0xC1);
|
||||
output += (unsigned char)((cs_id - 64) % 256);
|
||||
output += (unsigned char)((cs_id - 64) / 256);
|
||||
|
@ -372,7 +374,7 @@ std::string & RTMPStream::Chunk::Pack(){
|
|||
} //SendChunk
|
||||
|
||||
/// Default constructor, creates an empty chunk with all values initialized to zero.
|
||||
RTMPStream::Chunk::Chunk(){
|
||||
RTMPStream::Chunk::Chunk() {
|
||||
headertype = 0;
|
||||
cs_id = 0;
|
||||
timestamp = 0;
|
||||
|
@ -385,7 +387,7 @@ RTMPStream::Chunk::Chunk(){
|
|||
} //constructor
|
||||
|
||||
/// Packs up a chunk with the given arguments as properties.
|
||||
std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data){
|
||||
std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = cs_id;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -403,7 +405,7 @@ std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_i
|
|||
/// \param data Contents of the media data.
|
||||
/// \param len Length of the media data, in bytes.
|
||||
/// \param ts Timestamp of the media data, relative to current system time.
|
||||
std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts){
|
||||
std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = msg_type_id + 42;
|
||||
ch.timestamp = ts;
|
||||
|
@ -412,13 +414,13 @@ std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * d
|
|||
ch.len_left = 0;
|
||||
ch.msg_type_id = msg_type_id;
|
||||
ch.msg_stream_id = 1;
|
||||
ch.data = std::string((char*)data, (size_t)len);
|
||||
ch.data = std::string((char *)data, (size_t)len);
|
||||
return ch.Pack();
|
||||
} //SendMedia
|
||||
|
||||
/// Packs up a chunk with media contents.
|
||||
/// \param tag FLV::Tag with media to send.
|
||||
std::string & RTMPStream::SendMedia(FLV::Tag & tag){
|
||||
std::string & RTMPStream::SendMedia(FLV::Tag & tag) {
|
||||
static RTMPStream::Chunk ch;
|
||||
//Commented bit is more efficient and correct according to RTMP spec.
|
||||
//Simply passing "4" is the only thing that actually plays correctly, though.
|
||||
|
@ -435,7 +437,7 @@ std::string & RTMPStream::SendMedia(FLV::Tag & tag){
|
|||
} //SendMedia
|
||||
|
||||
/// Packs up a chunk for a control message with 1 argument.
|
||||
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data){
|
||||
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = 2;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -445,12 +447,12 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data){
|
|||
ch.msg_type_id = type;
|
||||
ch.msg_stream_id = 0;
|
||||
ch.data.resize(4);
|
||||
*(int*)((char*)ch.data.c_str()) = htonl(data);
|
||||
*(int *)((char *)ch.data.c_str()) = htonl(data);
|
||||
return ch.Pack();
|
||||
} //SendCTL
|
||||
|
||||
/// Packs up a chunk for a control message with 2 arguments.
|
||||
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned char data2){
|
||||
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned char data2) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = 2;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -460,13 +462,13 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigne
|
|||
ch.msg_type_id = type;
|
||||
ch.msg_stream_id = 0;
|
||||
ch.data.resize(5);
|
||||
*(unsigned int*)((char*)ch.data.c_str()) = htonl(data);
|
||||
*(unsigned int *)((char *)ch.data.c_str()) = htonl(data);
|
||||
ch.data[4] = data2;
|
||||
return ch.Pack();
|
||||
} //SendCTL
|
||||
|
||||
/// Packs up a chunk for a user control message with 1 argument.
|
||||
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data){
|
||||
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = 2;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -476,14 +478,14 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data){
|
|||
ch.msg_type_id = 4;
|
||||
ch.msg_stream_id = 0;
|
||||
ch.data.resize(6);
|
||||
*(unsigned int*)(((char*)ch.data.c_str()) + 2) = htonl(data);
|
||||
*(unsigned int *)(((char *)ch.data.c_str()) + 2) = htonl(data);
|
||||
ch.data[0] = 0;
|
||||
ch.data[1] = type;
|
||||
return ch.Pack();
|
||||
} //SendUSR
|
||||
|
||||
/// Packs up a chunk for a user control message with 2 arguments.
|
||||
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned int data2){
|
||||
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned int data2) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = 2;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -493,8 +495,8 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
|
|||
ch.msg_type_id = 4;
|
||||
ch.msg_stream_id = 0;
|
||||
ch.data.resize(10);
|
||||
*(unsigned int*)(((char*)ch.data.c_str()) + 2) = htonl(data);
|
||||
*(unsigned int*)(((char*)ch.data.c_str()) + 6) = htonl(data2);
|
||||
*(unsigned int *)(((char *)ch.data.c_str()) + 2) = htonl(data);
|
||||
*(unsigned int *)(((char *)ch.data.c_str()) + 6) = htonl(data2);
|
||||
ch.data[0] = 0;
|
||||
ch.data[1] = type;
|
||||
return ch.Pack();
|
||||
|
@ -508,14 +510,14 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
|
|||
/// \param indata The input string to parse and update.
|
||||
/// \warning This function will destroy the current data in this chunk!
|
||||
/// \returns True if a whole chunk could be read, false otherwise.
|
||||
bool RTMPStream::Chunk::Parse(std::string & indata){
|
||||
gettimeofday( &RTMPStream::lastrec, 0);
|
||||
bool RTMPStream::Chunk::Parse(std::string & indata) {
|
||||
gettimeofday(&RTMPStream::lastrec, 0);
|
||||
unsigned int i = 0;
|
||||
if (indata.size() < 1) return false; //need at least a byte
|
||||
|
||||
unsigned char chunktype = indata[i++ ];
|
||||
//read the chunkstream ID properly
|
||||
switch (chunktype & 0x3F){
|
||||
switch (chunktype & 0x3F) {
|
||||
case 0:
|
||||
if (indata.size() < 2) return false; //need at least 2 bytes to continue
|
||||
cs_id = indata[i++ ] + 64;
|
||||
|
@ -535,7 +537,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
|
||||
//process the rest of the header, for each chunk type
|
||||
headertype = chunktype & 0xC0;
|
||||
switch (headertype){
|
||||
switch (headertype) {
|
||||
case 0x00:
|
||||
if (indata.size() < i + 11) return false; //can't read whole header
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
|
@ -553,13 +555,13 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
break;
|
||||
case 0x40:
|
||||
if (indata.size() < i + 7) return false; //can't read whole header
|
||||
if (!allow_short){
|
||||
if (!allow_short) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x40 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256;
|
||||
timestamp += indata[i++ ];
|
||||
if (timestamp != 0x00ffffff){
|
||||
if (timestamp != 0x00ffffff) {
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = indata[i++ ] * 256 * 256;
|
||||
|
@ -571,13 +573,13 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
break;
|
||||
case 0x80:
|
||||
if (indata.size() < i + 3) return false; //can't read whole header
|
||||
if (!allow_short){
|
||||
if (!allow_short) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x80 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256;
|
||||
timestamp += indata[i++ ];
|
||||
if (timestamp != 0x00ffffff){
|
||||
if (timestamp != 0x00ffffff) {
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = prev.len;
|
||||
|
@ -586,7 +588,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
msg_stream_id = prev.msg_stream_id;
|
||||
break;
|
||||
case 0xC0:
|
||||
if (!allow_short){
|
||||
if (!allow_short) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0xC0 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = prev.timestamp;
|
||||
|
@ -597,18 +599,18 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
break;
|
||||
}
|
||||
//calculate chunk length, real length, and length left till complete
|
||||
if (len_left > 0){
|
||||
if (len_left > 0) {
|
||||
real_len = len_left;
|
||||
len_left -= real_len;
|
||||
}else{
|
||||
} else {
|
||||
real_len = len;
|
||||
}
|
||||
if (real_len > RTMPStream::chunk_rec_max){
|
||||
if (real_len > RTMPStream::chunk_rec_max) {
|
||||
len_left += real_len - RTMPStream::chunk_rec_max;
|
||||
real_len = RTMPStream::chunk_rec_max;
|
||||
}
|
||||
//read extended timestamp, if neccesary
|
||||
if (timestamp == 0x00ffffff){
|
||||
if (timestamp == 0x00ffffff) {
|
||||
if (indata.size() < i + 4) return false; //can't read whole header
|
||||
timestamp = indata[i++ ] * 256 * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256 * 256;
|
||||
|
@ -617,10 +619,10 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
}
|
||||
|
||||
//read data if length > 0, and allocate it
|
||||
if (real_len > 0){
|
||||
if (prev.len_left > 0){
|
||||
if (real_len > 0) {
|
||||
if (prev.len_left > 0) {
|
||||
data = prev.data;
|
||||
}else{
|
||||
} else {
|
||||
data = "";
|
||||
}
|
||||
if (indata.size() < i + real_len) return false; //can't read all data (yet)
|
||||
|
@ -628,12 +630,12 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
indata = indata.substr(i + real_len);
|
||||
lastrecv[cs_id] = *this;
|
||||
RTMPStream::rec_cnt += i + real_len;
|
||||
if (len_left == 0){
|
||||
if (len_left == 0) {
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return Parse(indata);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
data = "";
|
||||
indata = indata.substr(i + real_len);
|
||||
lastrecv[cs_id] = *this;
|
||||
|
@ -650,17 +652,17 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
/// \param buffer The input to parse and update.
|
||||
/// \warning This function will destroy the current data in this chunk!
|
||||
/// \returns True if a whole chunk could be read, false otherwise.
|
||||
bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
||||
gettimeofday( &RTMPStream::lastrec, 0);
|
||||
bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer) {
|
||||
gettimeofday(&RTMPStream::lastrec, 0);
|
||||
unsigned int i = 0;
|
||||
if ( !buffer.available(3)){
|
||||
if (!buffer.available(3)) {
|
||||
return false;
|
||||
} //we want at least 3 bytes
|
||||
std::string indata = buffer.copy(3);
|
||||
|
||||
unsigned char chunktype = indata[i++ ];
|
||||
//read the chunkstream ID properly
|
||||
switch (chunktype & 0x3F){
|
||||
switch (chunktype & 0x3F) {
|
||||
case 0:
|
||||
cs_id = indata[i++ ] + 64;
|
||||
break;
|
||||
|
@ -677,9 +679,9 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
|
||||
//process the rest of the header, for each chunk type
|
||||
headertype = chunktype & 0xC0;
|
||||
switch (headertype){
|
||||
switch (headertype) {
|
||||
case 0x00:
|
||||
if ( !buffer.available(i + 11)){
|
||||
if (!buffer.available(i + 11)) {
|
||||
return false;
|
||||
} //can't read whole header
|
||||
indata = buffer.copy(i + 11);
|
||||
|
@ -697,17 +699,17 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
msg_stream_id += indata[i++ ] * 256 * 256 * 256;
|
||||
break;
|
||||
case 0x40:
|
||||
if ( !buffer.available(i + 7)){
|
||||
if (!buffer.available(i + 7)) {
|
||||
return false;
|
||||
} //can't read whole header
|
||||
indata = buffer.copy(i + 7);
|
||||
if (prev.msg_type_id == 0){
|
||||
if (prev.msg_type_id == 0) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x40 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256;
|
||||
timestamp += indata[i++ ];
|
||||
if (timestamp != 0x00ffffff){
|
||||
if (timestamp != 0x00ffffff) {
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = indata[i++ ] * 256 * 256;
|
||||
|
@ -718,17 +720,17 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
msg_stream_id = prev.msg_stream_id;
|
||||
break;
|
||||
case 0x80:
|
||||
if ( !buffer.available(i + 3)){
|
||||
if (!buffer.available(i + 3)) {
|
||||
return false;
|
||||
} //can't read whole header
|
||||
indata = buffer.copy(i + 3);
|
||||
if (prev.msg_type_id == 0){
|
||||
if (prev.msg_type_id == 0) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x80 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256;
|
||||
timestamp += indata[i++ ];
|
||||
if (timestamp != 0x00ffffff){
|
||||
if (timestamp != 0x00ffffff) {
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = prev.len;
|
||||
|
@ -737,7 +739,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
msg_stream_id = prev.msg_stream_id;
|
||||
break;
|
||||
case 0xC0:
|
||||
if (prev.msg_type_id == 0){
|
||||
if (prev.msg_type_id == 0) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0xC0 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = prev.timestamp;
|
||||
|
@ -748,19 +750,19 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
break;
|
||||
}
|
||||
//calculate chunk length, real length, and length left till complete
|
||||
if (len_left > 0){
|
||||
if (len_left > 0) {
|
||||
real_len = len_left;
|
||||
len_left -= real_len;
|
||||
}else{
|
||||
} else {
|
||||
real_len = len;
|
||||
}
|
||||
if (real_len > RTMPStream::chunk_rec_max){
|
||||
if (real_len > RTMPStream::chunk_rec_max) {
|
||||
len_left += real_len - RTMPStream::chunk_rec_max;
|
||||
real_len = RTMPStream::chunk_rec_max;
|
||||
}
|
||||
//read extended timestamp, if neccesary
|
||||
if (timestamp == 0x00ffffff){
|
||||
if ( !buffer.available(i + 4)){
|
||||
if (timestamp == 0x00ffffff) {
|
||||
if (!buffer.available(i + 4)) {
|
||||
return false;
|
||||
} //can't read timestamp
|
||||
indata = buffer.copy(i + 4);
|
||||
|
@ -771,24 +773,24 @@ 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)){
|
||||
if (real_len > 0) {
|
||||
if (!buffer.available(i + real_len)) {
|
||||
return false;
|
||||
} //can't read all data (yet)
|
||||
buffer.remove(i); //remove the header
|
||||
if (prev.len_left > 0){
|
||||
if (prev.len_left > 0) {
|
||||
data = prev.data + buffer.remove(real_len); //append the data and remove from buffer
|
||||
}else{
|
||||
} else {
|
||||
data = buffer.remove(real_len); //append the data and remove from buffer
|
||||
}
|
||||
lastrecv[cs_id] = *this;
|
||||
RTMPStream::rec_cnt += i + real_len;
|
||||
if (len_left == 0){
|
||||
if (len_left == 0) {
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return Parse(buffer);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
buffer.remove(i); //remove the header
|
||||
data = "";
|
||||
indata = indata.substr(i + real_len);
|
||||
|
@ -802,10 +804,10 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
/// After calling this function, don't forget to read and ignore 1536 extra bytes,
|
||||
/// these are the handshake response and not interesting for us because we don't do client
|
||||
/// verification.
|
||||
bool RTMPStream::doHandshake(){
|
||||
bool RTMPStream::doHandshake() {
|
||||
char Version;
|
||||
//Read C0
|
||||
if (handshake_in.size() < 1537){
|
||||
if (handshake_in.size() < 1537) {
|
||||
DEBUG_MSG(DLVL_FAIL, "Handshake wasn't filled properly (%lu/1537) - aborting!", handshake_in.size());
|
||||
return false;
|
||||
}
|
||||
|
@ -816,9 +818,9 @@ bool RTMPStream::doHandshake(){
|
|||
RTMPStream::rec_cnt += 1537;
|
||||
|
||||
//Build S1 Packet
|
||||
*((uint32_t*)Server) = 0; //time zero
|
||||
*(((uint32_t*)(Server + 4))) = htonl(0x01020304); //version 1 2 3 4
|
||||
for (int i = 8; i < 3072; ++i){
|
||||
*((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] = FILLER_DATA[i % sizeof(FILLER_DATA)];
|
||||
} //"random" data
|
||||
|
||||
|
@ -828,7 +830,7 @@ bool RTMPStream::doHandshake(){
|
|||
if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
|
||||
if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
|
||||
|
||||
DEBUG_MSG(DLVL_HIGH, "Handshake type is %hhi, encryption is %s", _validationScheme, encrypted?"on":"off");
|
||||
DEBUG_MSG(DLVL_HIGH, "Handshake type is %hhi, encryption is %s", _validationScheme, encrypted ? "on" : "off");
|
||||
|
||||
//FIRST 1536 bytes from server response
|
||||
//compute DH key position
|
||||
|
@ -837,34 +839,34 @@ bool RTMPStream::doHandshake(){
|
|||
|
||||
//generate DH key
|
||||
DHWrapper dhWrapper(1024);
|
||||
if ( !dhWrapper.Initialize()){
|
||||
if (!dhWrapper.Initialize()) {
|
||||
return false;
|
||||
}
|
||||
if ( !dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)){
|
||||
if (!dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)) {
|
||||
return false;
|
||||
}
|
||||
if ( !dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)){
|
||||
if (!dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (encrypted){
|
||||
if (encrypted) {
|
||||
uint8_t secretKey[128];
|
||||
if ( !dhWrapper.CopySharedKey(secretKey, sizeof(secretKey))){
|
||||
if (!dhWrapper.CopySharedKey(secretKey, sizeof(secretKey))) {
|
||||
return false;
|
||||
}
|
||||
RC4_KEY _pKeyIn;
|
||||
RC4_KEY _pKeyOut;
|
||||
InitRC4Encryption(secretKey, (uint8_t*) &Client[clientDHOffset], (uint8_t*) &Server[serverDHOffset], &_pKeyIn, &_pKeyOut);
|
||||
InitRC4Encryption(secretKey, (uint8_t *) &Client[clientDHOffset], (uint8_t *) &Server[serverDHOffset], &_pKeyIn, &_pKeyOut);
|
||||
uint8_t data[1536];
|
||||
RC4( &_pKeyIn, 1536, data, data);
|
||||
RC4( &_pKeyOut, 1536, data, data);
|
||||
RC4(&_pKeyIn, 1536, data, data);
|
||||
RC4(&_pKeyOut, 1536, data, data);
|
||||
}
|
||||
//generate the digest
|
||||
uint32_t serverDigestOffset = GetDigestOffset(Server, _validationScheme);
|
||||
uint8_t *pTempBuffer = new uint8_t[1536 - 32];
|
||||
uint8_t * pTempBuffer = new uint8_t[1536 - 32];
|
||||
memcpy(pTempBuffer, Server, serverDigestOffset);
|
||||
memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32, 1536 - serverDigestOffset - 32);
|
||||
uint8_t *pTempHash = new uint8_t[512];
|
||||
uint8_t * pTempHash = new uint8_t[512];
|
||||
HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash);
|
||||
memcpy(Server + serverDigestOffset, pTempHash, 32);
|
||||
delete[] pTempBuffer;
|
||||
|
@ -874,7 +876,7 @@ bool RTMPStream::doHandshake(){
|
|||
uint32_t keyChallengeIndex = GetDigestOffset(Client, _validationScheme);
|
||||
pTempHash = new uint8_t[512];
|
||||
HMACsha256(Client + keyChallengeIndex, 32, genuineFMSKey, 68, pTempHash);
|
||||
uint8_t *pLastHash = new uint8_t[512];
|
||||
uint8_t * pLastHash = new uint8_t[512];
|
||||
HMACsha256(Server + 1536, 1536 - 32, pTempHash, 32, pLastHash);
|
||||
memcpy(Server + 1536 * 2 - 32, pLastHash, 32);
|
||||
delete[] pTempHash;
|
||||
|
|
|
@ -28,9 +28,9 @@ namespace RTMPStream {
|
|||
extern unsigned int snd_cnt; ///< Counter for total data sent, in bytes.
|
||||
|
||||
extern timeval lastrec; ///< Timestamp of last time data was received.
|
||||
|
||||
|
||||
/// Holds a single RTMP chunk, either send or receive direction.
|
||||
class Chunk{
|
||||
class Chunk {
|
||||
public:
|
||||
unsigned char headertype; ///< For input chunks, the type of header. This is calculated automatically for output chunks.
|
||||
unsigned int cs_id; ///< ContentStream ID
|
||||
|
@ -51,7 +51,7 @@ namespace RTMPStream {
|
|||
|
||||
extern std::map<unsigned int, Chunk> lastsend;
|
||||
extern std::map<unsigned int, Chunk> lastrecv;
|
||||
|
||||
|
||||
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);
|
||||
std::string & SendMedia(FLV::Tag & tag);
|
||||
|
|
|
@ -177,11 +177,11 @@ namespace IPC {
|
|||
///\brief Unmaps a shared page if allowed
|
||||
void sharedPage::unmap() {
|
||||
if (mapped && len) {
|
||||
#ifdef __CYGWIN__
|
||||
#ifdef __CYGWIN__
|
||||
UnmapViewOfFile(mapped);
|
||||
#else
|
||||
#else
|
||||
munmap(mapped, len);
|
||||
#endif
|
||||
#endif
|
||||
mapped = 0;
|
||||
len = 0;
|
||||
}
|
||||
|
@ -191,14 +191,14 @@ namespace IPC {
|
|||
void sharedPage::close() {
|
||||
unmap();
|
||||
if (handle > 0) {
|
||||
#ifdef __CYGWIN__
|
||||
#ifdef __CYGWIN__
|
||||
CloseHandle(handle);
|
||||
#else
|
||||
#else
|
||||
::close(handle);
|
||||
if (master && name != "") {
|
||||
shm_unlink(name.c_str());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
|
@ -247,69 +247,69 @@ namespace IPC {
|
|||
master = master_;
|
||||
mapped = 0;
|
||||
if (name.size()) {
|
||||
#ifdef __CYGWIN__
|
||||
if (master){
|
||||
handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, len, name.c_str());
|
||||
}else{
|
||||
int i = 0;
|
||||
do {
|
||||
if (i != 0){
|
||||
Util::sleep(1000);
|
||||
}
|
||||
handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name.c_str());
|
||||
i++;
|
||||
} while(i < 10 && !handle && autoBackoff);
|
||||
}
|
||||
if (!handle) {
|
||||
DEBUG_MSG(DLVL_FAIL, "%s for page %s failed: %s", (master ? "CreateFileMapping" : "OpenFileMapping"), name.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
mapped = (char *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
if (!mapped) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
handle = shm_open(name.c_str(), (master ? O_CREAT | O_EXCL : 0) | O_RDWR, ACCESSPERMS);
|
||||
if (handle == -1) {
|
||||
if (master) {
|
||||
DEBUG_MSG(DLVL_HIGH, "Overwriting old page for %s", name.c_str());
|
||||
handle = shm_open(name.c_str(), O_CREAT | O_RDWR, ACCESSPERMS);
|
||||
} else {
|
||||
int i = 0;
|
||||
while (i < 10 && handle == -1 && autoBackoff) {
|
||||
i++;
|
||||
Util::sleep(1000);
|
||||
handle = shm_open(name.c_str(), O_RDWR, ACCESSPERMS);
|
||||
}
|
||||
#ifdef __CYGWIN__
|
||||
if (master) {
|
||||
handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, len, name.c_str());
|
||||
} else {
|
||||
int i = 0;
|
||||
do {
|
||||
if (i != 0) {
|
||||
Util::sleep(1000);
|
||||
}
|
||||
}
|
||||
if (handle == -1) {
|
||||
DEBUG_MSG(DLVL_FAIL, "shm_open for page %s failed: %s", name.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name.c_str());
|
||||
i++;
|
||||
} while (i < 10 && !handle && autoBackoff);
|
||||
}
|
||||
if (!handle) {
|
||||
DEBUG_MSG(DLVL_FAIL, "%s for page %s failed: %s", (master ? "CreateFileMapping" : "OpenFileMapping"), name.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
mapped = (char *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
if (!mapped) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
handle = shm_open(name.c_str(), (master ? O_CREAT | O_EXCL : 0) | O_RDWR, ACCESSPERMS);
|
||||
if (handle == -1) {
|
||||
if (master) {
|
||||
if (ftruncate(handle, 0) < 0) {
|
||||
DEBUG_MSG(DLVL_FAIL, "truncate to zero for page %s failed: %s", name.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ftruncate(handle, len) < 0) {
|
||||
DEBUG_MSG(DLVL_FAIL, "truncate to %lld for page %s failed: %s", len, name.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
DEBUG_MSG(DLVL_HIGH, "Overwriting old page for %s", name.c_str());
|
||||
handle = shm_open(name.c_str(), O_CREAT | O_RDWR, ACCESSPERMS);
|
||||
} else {
|
||||
struct stat buffStats;
|
||||
int xRes = fstat(handle, &buffStats);
|
||||
if (xRes < 0) {
|
||||
return;
|
||||
int i = 0;
|
||||
while (i < 10 && handle == -1 && autoBackoff) {
|
||||
i++;
|
||||
Util::sleep(1000);
|
||||
handle = shm_open(name.c_str(), O_RDWR, ACCESSPERMS);
|
||||
}
|
||||
len = buffStats.st_size;
|
||||
}
|
||||
mapped = (char *)mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0);
|
||||
if (mapped == MAP_FAILED) {
|
||||
mapped = 0;
|
||||
}
|
||||
if (handle == -1) {
|
||||
DEBUG_MSG(DLVL_FAIL, "shm_open for page %s failed: %s", name.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (master) {
|
||||
if (ftruncate(handle, 0) < 0) {
|
||||
DEBUG_MSG(DLVL_FAIL, "truncate to zero for page %s failed: %s", name.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (ftruncate(handle, len) < 0) {
|
||||
DEBUG_MSG(DLVL_FAIL, "truncate to %lld for page %s failed: %s", len, name.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
struct stat buffStats;
|
||||
int xRes = fstat(handle, &buffStats);
|
||||
if (xRes < 0) {
|
||||
return;
|
||||
}
|
||||
len = buffStats.st_size;
|
||||
}
|
||||
mapped = (char *)mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0);
|
||||
if (mapped == MAP_FAILED) {
|
||||
mapped = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#endif
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
||||
///\brief A class used for the exchange of statistics over shared memory.
|
||||
class statExchange {
|
||||
public:
|
||||
|
@ -35,13 +35,13 @@ namespace IPC {
|
|||
private:
|
||||
///\brief The payload for the stat exchange
|
||||
/// - 8 byte - now (timestamp of last statistics)
|
||||
/// - 4 byte - time (duration of the current connection)
|
||||
/// - 4 byte - time (duration of the current connection)
|
||||
/// - 4 byte - lastSecond (last second of content viewed)
|
||||
/// - 8 byte - down (Number of bytes received from peer)
|
||||
/// - 8 byte - up (Number of bytes sent to peer)
|
||||
/// - 16 byte - host (ip address of the peer)
|
||||
/// - 20 byte - streamName (name of the stream peer is viewing)
|
||||
/// - 20 byte - connector (name of the connector the peer is using)
|
||||
/// - 20 byte - connector (name of the connector the peer is using)
|
||||
char * data;
|
||||
};
|
||||
|
||||
|
@ -80,7 +80,7 @@ namespace IPC {
|
|||
|
||||
#if !defined __APPLE__
|
||||
///\brief A class for managing shared memory pages.
|
||||
class sharedPage{
|
||||
class sharedPage {
|
||||
public:
|
||||
sharedPage(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true);
|
||||
sharedPage(const sharedPage & rhs);
|
||||
|
@ -93,13 +93,13 @@ namespace IPC {
|
|||
}
|
||||
void unmap();
|
||||
void close();
|
||||
#ifdef __CYGWIN__
|
||||
#ifdef __CYGWIN__
|
||||
///\brief The handle of the opened shared memory page
|
||||
HANDLE handle;
|
||||
#else
|
||||
#else
|
||||
///\brief The fd handle of the opened shared memory page
|
||||
int handle;
|
||||
#endif
|
||||
#endif
|
||||
///\brief The name of the opened shared memory page
|
||||
std::string name;
|
||||
///\brief The size in bytes of the opened shared memory page
|
||||
|
@ -118,7 +118,7 @@ namespace IPC {
|
|||
#else
|
||||
///\brief A class for managing shared files.
|
||||
#endif
|
||||
class sharedFile{
|
||||
class sharedFile {
|
||||
public:
|
||||
sharedFile(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true);
|
||||
sharedFile(const sharedFile & rhs);
|
||||
|
@ -146,7 +146,7 @@ namespace IPC {
|
|||
///\brief A class for handling shared memory pages.
|
||||
///
|
||||
///Uses shared files at its backbone, defined for portability
|
||||
class sharedPage: public sharedFile{
|
||||
class sharedPage: public sharedFile {
|
||||
public:
|
||||
sharedPage(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true);
|
||||
sharedPage(const sharedPage & rhs);
|
||||
|
@ -163,7 +163,7 @@ namespace IPC {
|
|||
///
|
||||
///Clients should allocate payLen bytes at a time, possibly with the addition of a counter.
|
||||
///If no such length can be allocated, the next page should be tried, and so on.
|
||||
class sharedServer{
|
||||
class sharedServer {
|
||||
public:
|
||||
sharedServer();
|
||||
sharedServer(std::string name, int len, bool withCounter = false);
|
||||
|
@ -198,7 +198,7 @@ namespace IPC {
|
|||
///
|
||||
///Clients should allocate payLen bytes at a time, possibly with the addition of a counter.
|
||||
///If no such length can be allocated, the next page should be tried, and so on.
|
||||
class sharedClient{
|
||||
class sharedClient {
|
||||
public:
|
||||
sharedClient();
|
||||
sharedClient(const sharedClient & rhs);
|
||||
|
|
566
lib/socket.cpp
566
lib/socket.cpp
File diff suppressed because it is too large
Load diff
14
lib/socket.h
14
lib/socket.h
|
@ -25,7 +25,7 @@ namespace Buffer {
|
|||
namespace Socket {
|
||||
|
||||
/// A buffer made out of std::string objects that can be efficiently read from and written to.
|
||||
class Buffer{
|
||||
class Buffer {
|
||||
private:
|
||||
std::deque<std::string> data;
|
||||
public:
|
||||
|
@ -44,7 +44,7 @@ namespace Socket {
|
|||
//Buffer
|
||||
|
||||
/// This class is for easy communicating through sockets, either TCP or Unix.
|
||||
class Connection{
|
||||
class Connection {
|
||||
private:
|
||||
int sock; ///< Internally saved socket number.
|
||||
int pipes[2]; ///< Internally saved file descriptors for pipe socket simulation.
|
||||
|
@ -98,13 +98,13 @@ namespace Socket {
|
|||
bool Error; ///< Set to true if a socket error happened.
|
||||
bool Blocking; ///< Set to true if a socket is currently or wants to be blocking.
|
||||
//overloaded operators
|
||||
bool operator==(const Connection &B) const;
|
||||
bool operator!=(const Connection &B) const;
|
||||
bool operator==(const Connection & B) const;
|
||||
bool operator!=(const Connection & B) const;
|
||||
operator bool() const;
|
||||
};
|
||||
|
||||
/// This class is for easily setting up listening socket, either TCP or Unix.
|
||||
class Server{
|
||||
class Server {
|
||||
private:
|
||||
std::string errors; ///< Stores errors that may have occured.
|
||||
int sock; ///< Internally saved socket number.
|
||||
|
@ -122,8 +122,8 @@ namespace Socket {
|
|||
void drop(); ///< Close connection without shutdown.
|
||||
int getSocket(); ///< Returns internal socket number.
|
||||
};
|
||||
|
||||
class UDPConnection{
|
||||
|
||||
class UDPConnection {
|
||||
private:
|
||||
int sock; ///< Internally saved socket number.
|
||||
std::string remotehost;///< Stores remote host address
|
||||
|
|
|
@ -14,29 +14,29 @@
|
|||
#include "defines.h"
|
||||
#include "shared_memory.h"
|
||||
|
||||
std::string Util::getTmpFolder(){
|
||||
std::string Util::getTmpFolder() {
|
||||
std::string dir;
|
||||
char * tmp_char = 0;
|
||||
if ( !tmp_char){
|
||||
if (!tmp_char) {
|
||||
tmp_char = getenv("TMP");
|
||||
}
|
||||
if ( !tmp_char){
|
||||
if (!tmp_char) {
|
||||
tmp_char = getenv("TEMP");
|
||||
}
|
||||
if ( !tmp_char){
|
||||
if (!tmp_char) {
|
||||
tmp_char = getenv("TMPDIR");
|
||||
}
|
||||
if (tmp_char){
|
||||
if (tmp_char) {
|
||||
dir = tmp_char;
|
||||
dir += "/mist";
|
||||
}else{
|
||||
} else {
|
||||
#if defined(_WIN32) || defined(_CYGWIN_)
|
||||
dir = "C:/tmp/mist";
|
||||
#else
|
||||
dir = "/tmp/mist";
|
||||
#endif
|
||||
}
|
||||
if (access(dir.c_str(), 0) != 0){
|
||||
if (access(dir.c_str(), 0) != 0) {
|
||||
mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO); //attempt to create mist folder - ignore failures
|
||||
}
|
||||
return dir + "/";
|
||||
|
@ -46,92 +46,92 @@ std::string Util::getTmpFolder(){
|
|||
/// Filters the streamname, removing invalid characters and converting all
|
||||
/// letters to lowercase. If a '?' character is found, everything following
|
||||
/// that character is deleted. The original string is modified.
|
||||
void Util::Stream::sanitizeName(std::string & streamname){
|
||||
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 == '?'){
|
||||
for (std::string::iterator i = streamname.end() - 1; i >= streamname.begin(); --i) {
|
||||
if (*i == '?') {
|
||||
streamname.erase(i, streamname.end());
|
||||
break;
|
||||
}
|
||||
if ( !isalpha( *i) && !isdigit( *i) && *i != '_'){
|
||||
if (!isalpha(*i) && !isdigit(*i) && *i != '_') {
|
||||
streamname.erase(i);
|
||||
}else{
|
||||
*i = tolower( *i);
|
||||
} else {
|
||||
*i = tolower(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Util::Stream::getLive(std::string streamname){
|
||||
bool Util::Stream::getLive(std::string streamname) {
|
||||
JSON::Value ServConf = JSON::fromFile(getTmpFolder() + "streamlist");
|
||||
static unsigned long long counter = 0;
|
||||
std::stringstream name;
|
||||
name << "MistInBuffer " << (counter++);
|
||||
std::string player_bin = Util::getMyPath() + "MistInBuffer";
|
||||
DEBUG_MSG(DLVL_WARN, "Starting %s -p -s %s", player_bin.c_str(), streamname.c_str());
|
||||
char* argv[15] = {(char*)player_bin.c_str(), (char*)"-p", (char*)"-s", (char*)streamname.c_str(), (char*)0};
|
||||
char * argv[15] = {(char *)player_bin.c_str(), (char *)"-p", (char *)"-s", (char *)streamname.c_str(), (char *)0};
|
||||
int argNum = 4;
|
||||
if (ServConf["streams"][streamname].isMember("DVR")){
|
||||
if (ServConf["streams"][streamname].isMember("DVR")) {
|
||||
std::string bufferTime = ServConf["streams"][streamname]["DVR"].asString();
|
||||
argv[argNum++] = (char*)"-b";
|
||||
argv[argNum++] = (char*)bufferTime.c_str();
|
||||
argv[argNum++] = (char*)0;
|
||||
argv[argNum++] = (char *)"-b";
|
||||
argv[argNum++] = (char *)bufferTime.c_str();
|
||||
argv[argNum++] = (char *)0;
|
||||
}
|
||||
|
||||
int pid = fork();
|
||||
if (pid){
|
||||
if (pid) {
|
||||
execvp(argv[0], argv);
|
||||
_exit(42);
|
||||
}else if(pid == -1){
|
||||
} else if (pid == -1) {
|
||||
perror("Could not start vod");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Starts a process for a VoD stream.
|
||||
bool Util::Stream::getVod(std::string filename, std::string streamname){
|
||||
bool Util::Stream::getVod(std::string filename, std::string streamname) {
|
||||
static unsigned long long counter = 0;
|
||||
std::stringstream name;
|
||||
name << "MistInDTSC " << (counter++);
|
||||
std::string player_bin = Util::getMyPath() + "MistInDTSC";
|
||||
if (filename.substr(filename.size()-5) == ".ismv"){
|
||||
if (filename.substr(filename.size() - 5) == ".ismv") {
|
||||
name.str("MistInISMV " + filename);
|
||||
player_bin = Util::getMyPath() + "MistInISMV";
|
||||
}
|
||||
if (filename.substr(filename.size()-4) == ".flv"){
|
||||
if (filename.substr(filename.size() - 4) == ".flv") {
|
||||
name.str("MistInFLV " + filename);
|
||||
player_bin = Util::getMyPath() + "MistInFLV";
|
||||
}
|
||||
INFO_MSG("Starting %s -p -s %s %s", player_bin.c_str(), streamname.c_str(), filename.c_str());
|
||||
char* const argv[] = {(char*)player_bin.c_str(), (char*)"-p", (char*)"-s", (char*)streamname.c_str(), (char*)filename.c_str(), (char*)0};
|
||||
char * const argv[] = {(char *)player_bin.c_str(), (char *)"-p", (char *)"-s", (char *)streamname.c_str(), (char *)filename.c_str(), (char *)0};
|
||||
|
||||
int pid = fork();
|
||||
if (pid){
|
||||
if (pid) {
|
||||
execvp(argv[0], argv);
|
||||
_exit(42);
|
||||
}else if(pid == -1){
|
||||
} else if (pid == -1) {
|
||||
perror("Could not start vod");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Probe for available streams. Currently first VoD, then Live.
|
||||
bool Util::Stream::getStream(std::string streamname){
|
||||
bool Util::Stream::getStream(std::string streamname) {
|
||||
sanitizeName(streamname);
|
||||
JSON::Value ServConf = JSON::fromFile(getTmpFolder() + "streamlist");
|
||||
if (ServConf["streams"].isMember(streamname)){
|
||||
if (ServConf["streams"].isMember(streamname)) {
|
||||
//check if the stream is already active, if yes, don't re-activate
|
||||
IPC::semaphore playerLock(std::string("/lock_" + streamname).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||
if (!playerLock.tryWait()){
|
||||
if (!playerLock.tryWait()) {
|
||||
playerLock.close();
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Playerlock for %s already active - not re-activating stream", streamname.c_str());
|
||||
return true;
|
||||
}
|
||||
playerLock.post();
|
||||
playerLock.close();
|
||||
if (ServConf["streams"][streamname]["source"].asString()[0] == '/'){
|
||||
if (ServConf["streams"][streamname]["source"].asString()[0] == '/') {
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Activating VoD stream %s", streamname.c_str());
|
||||
return getVod(ServConf["streams"][streamname]["source"].asString(), streamname);
|
||||
}else{
|
||||
} else {
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Activating live stream %s", streamname.c_str());
|
||||
return getLive(streamname);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ bool Util::Stream::getStream(std::string streamname){
|
|||
/// Filters the streamname, removing invalid characters and
|
||||
/// converting all letters to lowercase.
|
||||
/// If a '?' character is found, everything following that character is deleted.
|
||||
Socket::Server Util::Stream::makeLive(std::string streamname){
|
||||
Socket::Server Util::Stream::makeLive(std::string streamname) {
|
||||
sanitizeName(streamname);
|
||||
std::string loc = getTmpFolder() + "stream_" + streamname;
|
||||
//create and return the Socket::Server
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Util {
|
||||
std::string getTmpFolder();
|
||||
class Stream{
|
||||
class Stream {
|
||||
public:
|
||||
static void sanitizeName(std::string & streamname);
|
||||
static bool getLive(std::string streamname);
|
||||
|
|
378
lib/theora.cpp
378
lib/theora.cpp
|
@ -4,93 +4,117 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace theora{
|
||||
bool header::checkDataSize(unsigned int size){
|
||||
if (size > datasize){
|
||||
void* tmp = realloc(data,size);
|
||||
if (tmp){
|
||||
data = (char*)tmp;
|
||||
namespace theora {
|
||||
bool header::checkDataSize(unsigned int size) {
|
||||
if (size > datasize) {
|
||||
void * tmp = realloc(data, size);
|
||||
if (tmp) {
|
||||
data = (char *)tmp;
|
||||
datasize = size;
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t header::getInt32(size_t index){
|
||||
if (datasize >= (index + 3)){
|
||||
|
||||
uint32_t header::getInt32(size_t index) {
|
||||
if (datasize >= (index + 3)) {
|
||||
return (data[index] << 24) + (data[index + 1] << 16) + (data[index + 2] << 8) + data[index + 3];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t header::getInt24(size_t index){
|
||||
if (datasize >= (index + 2)){
|
||||
uint32_t header::getInt24(size_t index) {
|
||||
if (datasize >= (index + 2)) {
|
||||
return 0 + (data[index] << 16) + (data[index + 1] << 8) + data[index + 2];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t header::getInt16(size_t index){
|
||||
if (datasize >= (index + 1)){
|
||||
uint16_t header::getInt16(size_t index) {
|
||||
if (datasize >= (index + 1)) {
|
||||
return 0 + (data[index] << 8) + data[index + 1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t header::commentLen(size_t index){
|
||||
if (datasize >= index + 3){
|
||||
uint32_t header::commentLen(size_t index) {
|
||||
if (datasize >= index + 3) {
|
||||
return data[index] + (data[index + 1] << 8) + (data[index + 2] << 16) + (data[index + 3] << 24);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
header::header(){
|
||||
|
||||
header::header() {
|
||||
data = NULL;
|
||||
datasize = 0;
|
||||
}
|
||||
|
||||
header::header(char * newData, unsigned int length){
|
||||
header::header(char * newData, unsigned int length) {
|
||||
data = NULL;
|
||||
datasize = 0;
|
||||
read(newData, length);
|
||||
}
|
||||
|
||||
bool header::validateIdentificationHeader(){
|
||||
if (datasize != 42){return false;}
|
||||
if (getHeaderType() != 0){return false;}
|
||||
if (getVMAJ() != 3){return false;}
|
||||
if (getVMIN() != 2){return false;}
|
||||
if (getFMBW() == 0){return false;}
|
||||
if (getFMBH() == 0){return false;}
|
||||
if ((short)getPICW() > getFMBW() * 16){return false;}
|
||||
if ((short)getPICH() > getFMBH() * 16){return false;}
|
||||
if ((short)getPICX() > (getFMBW() * 16) - (short)getPICW()){return false;}
|
||||
if ((short)getPICY() > (getFMBH() * 16) - (short)getPICH()){return false;}
|
||||
if (getFRN() == 0){return false;}
|
||||
if (getFRD() == 0){return false;}
|
||||
bool header::validateIdentificationHeader() {
|
||||
if (datasize != 42) {
|
||||
return false;
|
||||
}
|
||||
if (getHeaderType() != 0) {
|
||||
return false;
|
||||
}
|
||||
if (getVMAJ() != 3) {
|
||||
return false;
|
||||
}
|
||||
if (getVMIN() != 2) {
|
||||
return false;
|
||||
}
|
||||
if (getFMBW() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (getFMBH() == 0) {
|
||||
return false;
|
||||
}
|
||||
if ((short)getPICW() > getFMBW() * 16) {
|
||||
return false;
|
||||
}
|
||||
if ((short)getPICH() > getFMBH() * 16) {
|
||||
return false;
|
||||
}
|
||||
if ((short)getPICX() > (getFMBW() * 16) - (short)getPICW()) {
|
||||
return false;
|
||||
}
|
||||
if ((short)getPICY() > (getFMBH() * 16) - (short)getPICH()) {
|
||||
return false;
|
||||
}
|
||||
if (getFRN() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (getFRD() == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool header::read(char* newData, unsigned int length){
|
||||
if (length < 7){
|
||||
|
||||
bool header::read(char * newData, unsigned int length) {
|
||||
if (length < 7) {
|
||||
return false;
|
||||
}
|
||||
if (! (newData[0] & 0x80)){
|
||||
if (!(newData[0] & 0x80)) {
|
||||
return false;
|
||||
}
|
||||
if(memcmp(newData+1, "theora", 6)!=0){
|
||||
if (memcmp(newData + 1, "theora", 6) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (checkDataSize(length)){
|
||||
if (checkDataSize(length)) {
|
||||
memcpy(data, newData, length);
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
switch(getHeaderType()){
|
||||
switch (getHeaderType()) {
|
||||
case 0:
|
||||
return validateIdentificationHeader();
|
||||
break;
|
||||
|
@ -103,225 +127,273 @@ namespace theora{
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int header::getHeaderType(){
|
||||
|
||||
int header::getHeaderType() {
|
||||
return (data[0] & 0x7F);
|
||||
}
|
||||
|
||||
char header::getVMAJ(){
|
||||
if (getHeaderType() == 0){return data[7];}
|
||||
char header::getVMAJ() {
|
||||
if (getHeaderType() == 0) {
|
||||
return data[7];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getVMIN(){
|
||||
if (getHeaderType() == 0){return data[8];}
|
||||
char header::getVMIN() {
|
||||
if (getHeaderType() == 0) {
|
||||
return data[8];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getVREV(){
|
||||
if (getHeaderType() == 0){return data[9];}
|
||||
char header::getVREV() {
|
||||
if (getHeaderType() == 0) {
|
||||
return data[9];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
short header::getFMBW(){
|
||||
if (getHeaderType() == 0){return getInt16(10);}
|
||||
short header::getFMBW() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt16(10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
short header::getFMBH(){
|
||||
if (getHeaderType() == 0){return getInt16(12);}
|
||||
short header::getFMBH() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt16(12);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getPICX(){
|
||||
if (getHeaderType() == 0){return data[20];}
|
||||
char header::getPICX() {
|
||||
if (getHeaderType() == 0) {
|
||||
return data[20];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getPICY(){
|
||||
if (getHeaderType() == 0){return data[21];}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getKFGShift(){
|
||||
if (getHeaderType() == 0){return (getInt16(40) >> 5) & 0x1F;}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long unsigned int header::getFRN(){
|
||||
if (getHeaderType() == 0){return getInt32(22);}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long unsigned int header::getPICH(){
|
||||
if (getHeaderType() == 0){return getInt24(17);}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long unsigned int header::getPICW(){
|
||||
if (getHeaderType() == 0){return getInt24(14);}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long unsigned int header::getFRD(){
|
||||
if (getHeaderType() == 0){return getInt32(26);}
|
||||
char header::getPICY() {
|
||||
if (getHeaderType() == 0) {
|
||||
return data[21];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long unsigned int header::getPARN(){
|
||||
if (getHeaderType() == 0){return getInt24(30);}
|
||||
char header::getKFGShift() {
|
||||
if (getHeaderType() == 0) {
|
||||
return (getInt16(40) >> 5) & 0x1F;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long unsigned int header::getPARD(){
|
||||
if (getHeaderType() == 0){return getInt24(33);}
|
||||
long unsigned int header::getFRN() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt32(22);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getCS(){
|
||||
if (getHeaderType() == 0){return data[36];}
|
||||
long unsigned int header::getPICH() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt24(17);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long unsigned int header::getNOMBR(){
|
||||
if (getHeaderType() == 0){return getInt24(37);}
|
||||
long unsigned int header::getPICW() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt24(14);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getQUAL(){
|
||||
if (getHeaderType() == 0){return (data[40] >> 3) & 0x1F;}
|
||||
long unsigned int header::getFRD() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt32(26);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getPF(){
|
||||
if (getHeaderType() == 0){return (data[41] >> 3) & 0x03;}
|
||||
long unsigned int header::getPARN() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt24(30);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string header::getVendor(){
|
||||
if (getHeaderType() != 1){return "";}
|
||||
long unsigned int header::getPARD() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt24(33);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getCS() {
|
||||
if (getHeaderType() == 0) {
|
||||
return data[36];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long unsigned int header::getNOMBR() {
|
||||
if (getHeaderType() == 0) {
|
||||
return getInt24(37);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getQUAL() {
|
||||
if (getHeaderType() == 0) {
|
||||
return (data[40] >> 3) & 0x1F;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char header::getPF() {
|
||||
if (getHeaderType() == 0) {
|
||||
return (data[41] >> 3) & 0x03;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string header::getVendor() {
|
||||
if (getHeaderType() != 1) {
|
||||
return "";
|
||||
}
|
||||
return std::string(data + 11, commentLen(7));
|
||||
}
|
||||
|
||||
long unsigned int header::getNComments(){
|
||||
if (getHeaderType() != 1){return 0;}
|
||||
long unsigned int header::getNComments() {
|
||||
if (getHeaderType() != 1) {
|
||||
return 0;
|
||||
}
|
||||
int offset = 11 + commentLen(7);
|
||||
return commentLen(offset);
|
||||
}
|
||||
|
||||
char header::getLFLIMS(size_t index){
|
||||
if (getHeaderType() != 2){return 0;}
|
||||
if (index >= 64){return 0;}
|
||||
char header::getLFLIMS(size_t index) {
|
||||
if (getHeaderType() != 2) {
|
||||
return 0;
|
||||
}
|
||||
if (index >= 64) {
|
||||
return 0;
|
||||
}
|
||||
char NBITS = (data[0] >> 5) & 0x07;
|
||||
return NBITS;
|
||||
}
|
||||
|
||||
std::string header::getUserComment(size_t index){
|
||||
if (index >= getNComments()){return "";}
|
||||
std::string header::getUserComment(size_t index) {
|
||||
if (index >= getNComments()) {
|
||||
return "";
|
||||
}
|
||||
int offset = 11 + commentLen(7) + 4;
|
||||
for (size_t i = 0; i < index; i++){
|
||||
for (size_t i = 0; i < index; i++) {
|
||||
offset += 4 + commentLen(offset);
|
||||
}
|
||||
return std::string(data + offset + 4,commentLen(offset));
|
||||
return std::string(data + offset + 4, commentLen(offset));
|
||||
}
|
||||
|
||||
std::string header::toPrettyString(size_t indent){
|
||||
std::string header::toPrettyString(size_t indent) {
|
||||
std::stringstream result;
|
||||
result << std::string(indent,' ') << "Theora header" << std::endl;
|
||||
result << std::string(indent+2,' ') << "HeaderType: " << getHeaderType() << std::endl;
|
||||
switch (getHeaderType()){
|
||||
result << std::string(indent, ' ') << "Theora header" << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "HeaderType: " << getHeaderType() << std::endl;
|
||||
switch (getHeaderType()) {
|
||||
case 0:
|
||||
result << std::string(indent+2,' ') << "VMAJ: " << (int)getVMAJ() << std::endl;
|
||||
result << std::string(indent+2,' ') << "VMIN: " << (int)getVMIN() << std::endl;
|
||||
result << std::string(indent+2,' ') << "VREV: " << (int)getVREV() << std::endl;
|
||||
result << std::string(indent+2,' ') << "FMBW: " << getFMBW() << std::endl;
|
||||
result << std::string(indent+2,' ') << "FMBH: " << getFMBH() << std::endl;
|
||||
result << std::string(indent+2,' ') << "PICH: " << getPICH() << std::endl;
|
||||
result << std::string(indent+2,' ') << "PICW: " << getPICW() << std::endl;
|
||||
result << std::string(indent+2,' ') << "PICX: " << (int)getPICX() << std::endl;
|
||||
result << std::string(indent+2,' ') << "PICY: " << (int)getPICY() << std::endl;
|
||||
result << std::string(indent+2,' ') << "FRN: " << getFRN() << std::endl;
|
||||
result << std::string(indent+2,' ') << "FRD: " << getFRD() << std::endl;
|
||||
result << std::string(indent+2,' ') << "PARN: " << getPARN() << std::endl;
|
||||
result << std::string(indent+2,' ') << "PARD: " << getPARD() << std::endl;
|
||||
result << std::string(indent+2,' ') << "CS: " << (int)getCS() << std::endl;
|
||||
result << std::string(indent+2,' ') << "NOMBR: " << getNOMBR() << std::endl;
|
||||
result << std::string(indent+2,' ') << "QUAL: " << (int)getQUAL() << std::endl;
|
||||
result << std::string(indent+2,' ') << "KFGShift: " << (int)getKFGShift() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "VMAJ: " << (int)getVMAJ() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "VMIN: " << (int)getVMIN() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "VREV: " << (int)getVREV() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "FMBW: " << getFMBW() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "FMBH: " << getFMBH() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "PICH: " << getPICH() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "PICW: " << getPICW() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "PICX: " << (int)getPICX() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "PICY: " << (int)getPICY() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "FRN: " << getFRN() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "FRD: " << getFRD() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "PARN: " << getPARN() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "PARD: " << getPARD() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "CS: " << (int)getCS() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "NOMBR: " << getNOMBR() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "QUAL: " << (int)getQUAL() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "KFGShift: " << (int)getKFGShift() << std::endl;
|
||||
break;
|
||||
case 1:
|
||||
result << std::string(indent+2,' ') << "Vendor: " << getVendor() << std::endl;
|
||||
result << std::string(indent+2,' ') << "User Comments (" << getNComments() << "):" << std::endl;
|
||||
for (long unsigned int i = 0; i < getNComments(); i++){
|
||||
result << std::string(indent+4,' ') << "[" << i << "] " << getUserComment(i) << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "Vendor: " << getVendor() << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "User Comments (" << getNComments() << "):" << std::endl;
|
||||
for (long unsigned int i = 0; i < getNComments(); i++) {
|
||||
result << std::string(indent + 4, ' ') << "[" << i << "] " << getUserComment(i) << std::endl;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
result << std::string(indent+2,' ') << "NBITS: " << (int)getLFLIMS(0) << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "NBITS: " << (int)getLFLIMS(0) << std::endl;
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
frame::frame(){
|
||||
frame::frame() {
|
||||
data = NULL;
|
||||
datasize = 0;
|
||||
}
|
||||
|
||||
bool frame::checkDataSize(unsigned int size){
|
||||
if (size > datasize){
|
||||
void* tmp = realloc(data,size);
|
||||
if (tmp){
|
||||
data = (char*)tmp;
|
||||
bool frame::checkDataSize(unsigned int size) {
|
||||
if (size > datasize) {
|
||||
void * tmp = realloc(data, size);
|
||||
if (tmp) {
|
||||
data = (char *)tmp;
|
||||
datasize = size;
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool frame::read(char* newData, unsigned int length){
|
||||
if (length < 7){
|
||||
bool frame::read(char * newData, unsigned int length) {
|
||||
if (length < 7) {
|
||||
return false;
|
||||
}
|
||||
if ((newData[0] & 0x80)){
|
||||
if ((newData[0] & 0x80)) {
|
||||
return false;
|
||||
}
|
||||
if (checkDataSize(length)){
|
||||
if (checkDataSize(length)) {
|
||||
memcpy(data, newData, length);
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char frame::getFTYPE(){
|
||||
char frame::getFTYPE() {
|
||||
return (data[0] >> 6) & 0x01;
|
||||
}
|
||||
|
||||
char frame::getNQIS(){
|
||||
char frame::getNQIS() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char frame::getQIS(size_t index){
|
||||
if (index >= 3){return 0;}
|
||||
char frame::getQIS(size_t index) {
|
||||
if (index >= 3) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long long unsigned int header::parseGranuleUpper(long long unsigned int granPos){
|
||||
long long unsigned int header::parseGranuleUpper(long long unsigned int granPos) {
|
||||
return granPos >> getKFGShift();
|
||||
}
|
||||
|
||||
long long unsigned int header::parseGranuleLower(long long unsigned int granPos){
|
||||
long long unsigned int header::parseGranuleLower(long long unsigned int granPos) {
|
||||
return (granPos & ((1 << getKFGShift()) - 1));
|
||||
}
|
||||
|
||||
std::string frame::toPrettyString(size_t indent){
|
||||
std::string frame::toPrettyString(size_t indent) {
|
||||
std::stringstream result;
|
||||
result << std::string(indent,' ') << "Theora Frame" << std::endl;
|
||||
result << std::string(indent+2,' ') << "FType: " << (int)getFTYPE() << std::endl;
|
||||
result << std::string(indent, ' ') << "Theora Frame" << std::endl;
|
||||
result << std::string(indent + 2, ' ') << "FType: " << (int)getFTYPE() << std::endl;
|
||||
return result.str();
|
||||
}
|
||||
}
|
||||
|
|
14
lib/theora.h
14
lib/theora.h
|
@ -3,12 +3,12 @@
|
|||
#include<stdint.h>
|
||||
#include<string>
|
||||
|
||||
namespace theora{
|
||||
class header{
|
||||
namespace theora {
|
||||
class header {
|
||||
public:
|
||||
header();
|
||||
header(char* newData, unsigned int length);
|
||||
bool read(char* newData, unsigned int length);
|
||||
header(char * newData, unsigned int length);
|
||||
bool read(char * newData, unsigned int length);
|
||||
int getHeaderType();
|
||||
char getVMAJ();
|
||||
char getVMIN();
|
||||
|
@ -41,16 +41,16 @@ namespace theora{
|
|||
uint16_t getInt16(size_t index);
|
||||
uint32_t commentLen(size_t index);
|
||||
private:
|
||||
char* data;
|
||||
char * data;
|
||||
unsigned int datasize;
|
||||
bool checkDataSize(unsigned int size);
|
||||
bool validateIdentificationHeader();
|
||||
};
|
||||
|
||||
class frame{
|
||||
class frame {
|
||||
public:
|
||||
frame();
|
||||
bool read(char* newData, unsigned int length);
|
||||
bool read(char * newData, unsigned int length);
|
||||
char getFTYPE();
|
||||
char getNQIS();
|
||||
char getQIS(size_t index);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <mach/mach.h>
|
||||
#define CLOCK_REALTIME CALENDAR_CLOCK
|
||||
#define CLOCK_MONOTONIC SYSTEM_CLOCK
|
||||
void clock_gettime(int ign, struct timespec * ts){
|
||||
void clock_gettime(int ign, struct timespec * ts) {
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
host_get_clock_service(mach_host_self(), ign, &cclock);
|
||||
|
@ -23,53 +23,53 @@ void clock_gettime(int ign, struct timespec * ts){
|
|||
#endif
|
||||
|
||||
/// Sleeps for the indicated amount of milliseconds or longer.
|
||||
void Util::sleep(int ms){
|
||||
if (ms < 0){
|
||||
void Util::sleep(int ms) {
|
||||
if (ms < 0) {
|
||||
return;
|
||||
}
|
||||
if (ms > 100000){
|
||||
if (ms > 100000) {
|
||||
ms = 100000;
|
||||
}
|
||||
struct timespec T;
|
||||
T.tv_sec = ms / 1000;
|
||||
T.tv_nsec = 1000000 * (ms % 1000);
|
||||
nanosleep( &T, 0);
|
||||
nanosleep(&T, 0);
|
||||
}
|
||||
|
||||
long long Util::getNTP(){
|
||||
long long Util::getNTP() {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
return ((((long long int)t.tv_sec) + 2208988800) << 32) + (t.tv_nsec*4.2949);
|
||||
return ((((long long int)t.tv_sec) + 2208988800) << 32) + (t.tv_nsec * 4.2949);
|
||||
}
|
||||
|
||||
/// Gets the current time in milliseconds.
|
||||
long long int Util::getMS(){
|
||||
long long int Util::getMS() {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
return ((long long int)t.tv_sec) * 1000 + t.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
long long int Util::bootSecs(){
|
||||
long long int Util::bootSecs() {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
return t.tv_sec;
|
||||
}
|
||||
|
||||
/// Gets the current time in microseconds.
|
||||
long long unsigned int Util::getMicros(){
|
||||
long long unsigned int Util::getMicros() {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
return ((long long unsigned int)t.tv_sec) * 1000000 + t.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
/// Gets the time difference in microseconds.
|
||||
long long unsigned int Util::getMicros(long long unsigned int previous){
|
||||
long long unsigned int Util::getMicros(long long unsigned int previous) {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
return ((long long unsigned int)t.tv_sec) * 1000000 + t.tv_nsec / 1000 - previous;
|
||||
}
|
||||
|
||||
/// Gets the amount of seconds since 01/01/1970.
|
||||
long long int Util::epoch(){
|
||||
long long int Util::epoch() {
|
||||
return time(0);
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ freely, subject to the following restrictions:
|
|||
#include "tinythread.h"
|
||||
|
||||
#if defined(_TTHREAD_POSIX_)
|
||||
#include <unistd.h>
|
||||
#include <map>
|
||||
#include <unistd.h>
|
||||
#include <map>
|
||||
#elif defined(_TTHREAD_WIN32_)
|
||||
#include <process.h>
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -49,74 +49,69 @@ namespace tthread {
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
#define _CONDITION_EVENT_ONE 0
|
||||
#define _CONDITION_EVENT_ALL 1
|
||||
#define _CONDITION_EVENT_ONE 0
|
||||
#define _CONDITION_EVENT_ALL 1
|
||||
#endif
|
||||
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
condition_variable::condition_variable() : mWaitersCount(0)
|
||||
{
|
||||
mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
InitializeCriticalSection(&mWaitersCountLock);
|
||||
}
|
||||
condition_variable::condition_variable() : mWaitersCount(0) {
|
||||
mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
InitializeCriticalSection(&mWaitersCountLock);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
condition_variable::~condition_variable()
|
||||
{
|
||||
CloseHandle(mEvents[_CONDITION_EVENT_ONE]);
|
||||
CloseHandle(mEvents[_CONDITION_EVENT_ALL]);
|
||||
DeleteCriticalSection(&mWaitersCountLock);
|
||||
}
|
||||
condition_variable::~condition_variable() {
|
||||
CloseHandle(mEvents[_CONDITION_EVENT_ONE]);
|
||||
CloseHandle(mEvents[_CONDITION_EVENT_ALL]);
|
||||
DeleteCriticalSection(&mWaitersCountLock);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
void condition_variable::_wait()
|
||||
{
|
||||
// Wait for either event to become signaled due to notify_one() or
|
||||
// notify_all() being called
|
||||
int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE);
|
||||
void condition_variable::_wait() {
|
||||
// Wait for either event to become signaled due to notify_one() or
|
||||
// notify_all() being called
|
||||
int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE);
|
||||
|
||||
// Check if we are the last waiter
|
||||
EnterCriticalSection(&mWaitersCountLock);
|
||||
-- mWaitersCount;
|
||||
bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
|
||||
(mWaitersCount == 0);
|
||||
LeaveCriticalSection(&mWaitersCountLock);
|
||||
// Check if we are the last waiter
|
||||
EnterCriticalSection(&mWaitersCountLock);
|
||||
-- mWaitersCount;
|
||||
bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
|
||||
(mWaitersCount == 0);
|
||||
LeaveCriticalSection(&mWaitersCountLock);
|
||||
|
||||
// If we are the last waiter to be notified to stop waiting, reset the event
|
||||
if(lastWaiter)
|
||||
ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
|
||||
}
|
||||
// If we are the last waiter to be notified to stop waiting, reset the event
|
||||
if (lastWaiter)
|
||||
ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
void condition_variable::notify_one()
|
||||
{
|
||||
// Are there any waiters?
|
||||
EnterCriticalSection(&mWaitersCountLock);
|
||||
bool haveWaiters = (mWaitersCount > 0);
|
||||
LeaveCriticalSection(&mWaitersCountLock);
|
||||
void condition_variable::notify_one() {
|
||||
// Are there any waiters?
|
||||
EnterCriticalSection(&mWaitersCountLock);
|
||||
bool haveWaiters = (mWaitersCount > 0);
|
||||
LeaveCriticalSection(&mWaitersCountLock);
|
||||
|
||||
// If we have any waiting threads, send them a signal
|
||||
if(haveWaiters)
|
||||
SetEvent(mEvents[_CONDITION_EVENT_ONE]);
|
||||
}
|
||||
// If we have any waiting threads, send them a signal
|
||||
if (haveWaiters)
|
||||
SetEvent(mEvents[_CONDITION_EVENT_ONE]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
void condition_variable::notify_all()
|
||||
{
|
||||
// Are there any waiters?
|
||||
EnterCriticalSection(&mWaitersCountLock);
|
||||
bool haveWaiters = (mWaitersCount > 0);
|
||||
LeaveCriticalSection(&mWaitersCountLock);
|
||||
void condition_variable::notify_all() {
|
||||
// Are there any waiters?
|
||||
EnterCriticalSection(&mWaitersCountLock);
|
||||
bool haveWaiters = (mWaitersCount > 0);
|
||||
LeaveCriticalSection(&mWaitersCountLock);
|
||||
|
||||
// If we have any waiting threads, send them a signal
|
||||
if(haveWaiters)
|
||||
SetEvent(mEvents[_CONDITION_EVENT_ALL]);
|
||||
}
|
||||
// If we have any waiting threads, send them a signal
|
||||
if (haveWaiters)
|
||||
SetEvent(mEvents[_CONDITION_EVENT_ALL]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -128,17 +123,16 @@ void condition_variable::notify_all()
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(_TTHREAD_POSIX_)
|
||||
static thread::id _pthread_t_to_ID(const pthread_t &aHandle)
|
||||
{
|
||||
static mutex idMapLock;
|
||||
static std::map<pthread_t, unsigned long int> idMap;
|
||||
static unsigned long int idCount(1);
|
||||
static thread::id _pthread_t_to_ID(const pthread_t & aHandle) {
|
||||
static mutex idMapLock;
|
||||
static std::map<pthread_t, unsigned long int> idMap;
|
||||
static unsigned long int idCount(1);
|
||||
|
||||
lock_guard<mutex> guard(idMapLock);
|
||||
if(idMap.find(aHandle) == idMap.end())
|
||||
idMap[aHandle] = idCount ++;
|
||||
return thread::id(idMap[aHandle]);
|
||||
}
|
||||
lock_guard<mutex> guard(idMapLock);
|
||||
if (idMap.find(aHandle) == idMap.end())
|
||||
idMap[aHandle] = idCount ++;
|
||||
return thread::id(idMap[aHandle]);
|
||||
}
|
||||
#endif // _TTHREAD_POSIX_
|
||||
|
||||
|
||||
|
@ -147,165 +141,151 @@ static thread::id _pthread_t_to_ID(const pthread_t &aHandle)
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Information to pass to the new thread (what to run).
|
||||
struct _thread_start_info {
|
||||
void (*mFunction)(void *); ///< Pointer to the function to be executed.
|
||||
void * mArg; ///< Function argument for the thread function.
|
||||
thread * mThread; ///< Pointer to the thread object.
|
||||
};
|
||||
struct _thread_start_info {
|
||||
void (*mFunction)(void *); ///< Pointer to the function to be executed.
|
||||
void * mArg; ///< Function argument for the thread function.
|
||||
thread * mThread; ///< Pointer to the thread object.
|
||||
};
|
||||
|
||||
// Thread wrapper function.
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
unsigned WINAPI thread::wrapper_function(void * aArg)
|
||||
unsigned WINAPI thread::wrapper_function(void * aArg)
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
void * thread::wrapper_function(void * aArg)
|
||||
void * thread::wrapper_function(void * aArg)
|
||||
#endif
|
||||
{
|
||||
// Get thread startup information
|
||||
_thread_start_info * ti = (_thread_start_info *) aArg;
|
||||
|
||||
try
|
||||
{
|
||||
// Call the actual client thread function
|
||||
ti->mFunction(ti->mArg);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// Uncaught exceptions will terminate the application (default behavior
|
||||
// according to C++11)
|
||||
std::terminate();
|
||||
}
|
||||
// Get thread startup information
|
||||
_thread_start_info * ti = (_thread_start_info *) aArg;
|
||||
|
||||
// The thread is no longer executing
|
||||
if (ti->mThread){
|
||||
lock_guard<mutex> guard(ti->mThread->mDataMutex);
|
||||
ti->mThread->mNotAThread = true;
|
||||
ti->mThread->ti_copy = 0;
|
||||
}
|
||||
try {
|
||||
// Call the actual client thread function
|
||||
ti->mFunction(ti->mArg);
|
||||
} catch (...) {
|
||||
// Uncaught exceptions will terminate the application (default behavior
|
||||
// according to C++11)
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
// The thread is responsible for freeing the startup information
|
||||
delete ti;
|
||||
// The thread is no longer executing
|
||||
if (ti->mThread) {
|
||||
lock_guard<mutex> guard(ti->mThread->mDataMutex);
|
||||
ti->mThread->mNotAThread = true;
|
||||
ti->mThread->ti_copy = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
thread::thread(void (*aFunction)(void *), void * aArg)
|
||||
{
|
||||
// Serialize access to this thread structure
|
||||
lock_guard<mutex> guard(mDataMutex);
|
||||
|
||||
// Fill out the thread startup information (passed to the thread wrapper,
|
||||
// which will eventually free it)
|
||||
_thread_start_info * ti = new _thread_start_info;
|
||||
ti_copy = ti;
|
||||
ti->mFunction = aFunction;
|
||||
ti->mArg = aArg;
|
||||
ti->mThread = this;
|
||||
|
||||
// The thread is now alive
|
||||
mNotAThread = false;
|
||||
|
||||
// Create the thread
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID);
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0)
|
||||
mHandle = 0;
|
||||
#endif
|
||||
|
||||
// Did we fail to create the thread?
|
||||
if(!mHandle)
|
||||
{
|
||||
mNotAThread = true;
|
||||
ti_copy = 0;
|
||||
// The thread is responsible for freeing the startup information
|
||||
delete ti;
|
||||
}
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
{
|
||||
if (ti_copy){
|
||||
((_thread_start_info *)ti_copy)->mThread = 0;
|
||||
return 0;
|
||||
}
|
||||
if(joinable())
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
void thread::join()
|
||||
{
|
||||
if(joinable())
|
||||
{
|
||||
thread::thread(void (*aFunction)(void *), void * aArg) {
|
||||
// Serialize access to this thread structure
|
||||
lock_guard<mutex> guard(mDataMutex);
|
||||
|
||||
// Fill out the thread startup information (passed to the thread wrapper,
|
||||
// which will eventually free it)
|
||||
_thread_start_info * ti = new _thread_start_info;
|
||||
ti_copy = ti;
|
||||
ti->mFunction = aFunction;
|
||||
ti->mArg = aArg;
|
||||
ti->mThread = this;
|
||||
|
||||
// The thread is now alive
|
||||
mNotAThread = false;
|
||||
|
||||
// Create the thread
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
WaitForSingleObject(mHandle, INFINITE);
|
||||
CloseHandle(mHandle);
|
||||
mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID);
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
pthread_join(mHandle, NULL);
|
||||
if (pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0)
|
||||
mHandle = 0;
|
||||
#endif
|
||||
|
||||
// Did we fail to create the thread?
|
||||
if (!mHandle) {
|
||||
mNotAThread = true;
|
||||
ti_copy = 0;
|
||||
delete ti;
|
||||
}
|
||||
}
|
||||
|
||||
thread::~thread() {
|
||||
if (ti_copy) {
|
||||
((_thread_start_info *)ti_copy)->mThread = 0;
|
||||
}
|
||||
if (joinable())
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
void thread::join() {
|
||||
if (joinable()) {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
WaitForSingleObject(mHandle, INFINITE);
|
||||
CloseHandle(mHandle);
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
pthread_join(mHandle, NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::joinable() const {
|
||||
mDataMutex.lock();
|
||||
bool result = !mNotAThread;
|
||||
mDataMutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
void thread::detach() {
|
||||
mDataMutex.lock();
|
||||
if (!mNotAThread) {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
CloseHandle(mHandle);
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
pthread_detach(mHandle);
|
||||
#endif
|
||||
mNotAThread = true;
|
||||
}
|
||||
mDataMutex.unlock();
|
||||
}
|
||||
|
||||
thread::id thread::get_id() const {
|
||||
if (!joinable())
|
||||
return id();
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
return id((unsigned long int) mWin32ThreadID);
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
return _pthread_t_to_ID(mHandle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::joinable() const
|
||||
{
|
||||
mDataMutex.lock();
|
||||
bool result = !mNotAThread;
|
||||
mDataMutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
mDataMutex.lock();
|
||||
if(!mNotAThread)
|
||||
{
|
||||
unsigned thread::hardware_concurrency() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
CloseHandle(mHandle);
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
pthread_detach(mHandle);
|
||||
#endif
|
||||
mNotAThread = true;
|
||||
}
|
||||
mDataMutex.unlock();
|
||||
}
|
||||
|
||||
thread::id thread::get_id() const
|
||||
{
|
||||
if(!joinable())
|
||||
return id();
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
return id((unsigned long int) mWin32ThreadID);
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
return _pthread_t_to_ID(mHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned thread::hardware_concurrency()
|
||||
{
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return (int) si.dwNumberOfProcessors;
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return (int) si.dwNumberOfProcessors;
|
||||
#elif defined(_SC_NPROCESSORS_ONLN)
|
||||
return (int) sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return (int) sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#elif defined(_SC_NPROC_ONLN)
|
||||
return (int) sysconf(_SC_NPROC_ONLN);
|
||||
return (int) sysconf(_SC_NPROC_ONLN);
|
||||
#else
|
||||
// The standard requires this function to return zero if the number of
|
||||
// hardware cores could not be determined.
|
||||
return 0;
|
||||
// The standard requires this function to return zero if the number of
|
||||
// hardware cores could not be determined.
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// this_thread
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
thread::id this_thread::get_id()
|
||||
{
|
||||
thread::id this_thread::get_id() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
return thread::id((unsigned long int) GetCurrentThreadId());
|
||||
return thread::id((unsigned long int) GetCurrentThreadId());
|
||||
#elif defined(_TTHREAD_POSIX_)
|
||||
return _pthread_t_to_ID(pthread_self());
|
||||
return _pthread_t_to_ID(pthread_self());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
779
lib/tinythread.h
779
lib/tinythread.h
|
@ -57,30 +57,30 @@ freely, subject to the following restrictions:
|
|||
|
||||
// Which platform are we on?
|
||||
#if !defined(_TTHREAD_PLATFORM_DEFINED_)
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
|
||||
#define _TTHREAD_WIN32_
|
||||
#else
|
||||
#define _TTHREAD_POSIX_
|
||||
#endif
|
||||
#define _TTHREAD_PLATFORM_DEFINED_
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
|
||||
#define _TTHREAD_WIN32_
|
||||
#else
|
||||
#define _TTHREAD_POSIX_
|
||||
#endif
|
||||
#define _TTHREAD_PLATFORM_DEFINED_
|
||||
#endif
|
||||
|
||||
// Platform specific includes
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define __UNDEF_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#ifdef __UNDEF_LEAN_AND_MEAN
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#undef __UNDEF_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define __UNDEF_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#ifdef __UNDEF_LEAN_AND_MEAN
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#undef __UNDEF_LEAN_AND_MEAN
|
||||
#endif
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Generic includes
|
||||
|
@ -95,23 +95,23 @@ freely, subject to the following restrictions:
|
|||
|
||||
// Do we have a fully featured C++11 compiler?
|
||||
#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
|
||||
#define _TTHREAD_CPP11_
|
||||
#define _TTHREAD_CPP11_
|
||||
#endif
|
||||
|
||||
// ...at least partial C++11?
|
||||
#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
|
||||
#define _TTHREAD_CPP11_PARTIAL_
|
||||
#define _TTHREAD_CPP11_PARTIAL_
|
||||
#endif
|
||||
|
||||
// Macro for disabling assignments of objects.
|
||||
#ifdef _TTHREAD_CPP11_PARTIAL_
|
||||
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \
|
||||
name(const name&) = delete; \
|
||||
name& operator=(const name&) = delete;
|
||||
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \
|
||||
name(const name&) = delete; \
|
||||
name& operator=(const name&) = delete;
|
||||
#else
|
||||
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \
|
||||
name(const name&); \
|
||||
name& operator=(const name&);
|
||||
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \
|
||||
name(const name&); \
|
||||
name& operator=(const name&);
|
||||
#endif
|
||||
|
||||
/// @def thread_local
|
||||
|
@ -136,11 +136,11 @@ freely, subject to the following restrictions:
|
|||
/// @hideinitializer
|
||||
|
||||
#if !defined(_TTHREAD_CPP11_) && !defined(thread_local)
|
||||
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
|
||||
#define thread_local __thread
|
||||
#else
|
||||
#define thread_local __declspec(thread)
|
||||
#endif
|
||||
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
|
||||
#define thread_local __thread
|
||||
#else
|
||||
#define thread_local __declspec(thread)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -156,91 +156,86 @@ namespace tthread {
|
|||
/// program may deadlock if the thread that owns a mutex object calls lock()
|
||||
/// on that object).
|
||||
/// @see recursive_mutex
|
||||
class mutex {
|
||||
public:
|
||||
/// Constructor.
|
||||
mutex()
|
||||
class mutex {
|
||||
public:
|
||||
/// Constructor.
|
||||
mutex()
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
: mAlreadyLocked(false)
|
||||
: mAlreadyLocked(false)
|
||||
#endif
|
||||
{
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
InitializeCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutex_init(&mHandle, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
~mutex()
|
||||
{
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
DeleteCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutex_destroy(&mHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Lock the mutex.
|
||||
/// The method will block the calling thread until a lock on the mutex can
|
||||
/// be obtained. The mutex remains locked until @c unlock() is called.
|
||||
/// @see lock_guard
|
||||
inline void lock()
|
||||
{
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
EnterCriticalSection(&mHandle);
|
||||
while(mAlreadyLocked) Sleep(1000); // Simulate deadlock...
|
||||
mAlreadyLocked = true;
|
||||
#else
|
||||
pthread_mutex_lock(&mHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Try to lock the mutex.
|
||||
/// The method will try to lock the mutex. If it fails, the function will
|
||||
/// return immediately (non-blocking).
|
||||
/// @return @c true if the lock was acquired, or @c false if the lock could
|
||||
/// not be acquired.
|
||||
inline bool try_lock()
|
||||
{
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
|
||||
if(ret && mAlreadyLocked)
|
||||
{
|
||||
LeaveCriticalSection(&mHandle);
|
||||
ret = false;
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
InitializeCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutex_init(&mHandle, NULL);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
#else
|
||||
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Unlock the mutex.
|
||||
/// If any threads are waiting for the lock on this mutex, one of them will
|
||||
/// be unblocked.
|
||||
inline void unlock()
|
||||
{
|
||||
/// Destructor.
|
||||
~mutex() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
mAlreadyLocked = false;
|
||||
LeaveCriticalSection(&mHandle);
|
||||
DeleteCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutex_unlock(&mHandle);
|
||||
pthread_mutex_destroy(&mHandle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
_TTHREAD_DISABLE_ASSIGNMENT(mutex)
|
||||
|
||||
private:
|
||||
/// Lock the mutex.
|
||||
/// The method will block the calling thread until a lock on the mutex can
|
||||
/// be obtained. The mutex remains locked until @c unlock() is called.
|
||||
/// @see lock_guard
|
||||
inline void lock() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
CRITICAL_SECTION mHandle;
|
||||
bool mAlreadyLocked;
|
||||
EnterCriticalSection(&mHandle);
|
||||
while (mAlreadyLocked) Sleep(1000); // Simulate deadlock...
|
||||
mAlreadyLocked = true;
|
||||
#else
|
||||
pthread_mutex_t mHandle;
|
||||
pthread_mutex_lock(&mHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Try to lock the mutex.
|
||||
/// The method will try to lock the mutex. If it fails, the function will
|
||||
/// return immediately (non-blocking).
|
||||
/// @return @c true if the lock was acquired, or @c false if the lock could
|
||||
/// not be acquired.
|
||||
inline bool try_lock() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
|
||||
if (ret && mAlreadyLocked) {
|
||||
LeaveCriticalSection(&mHandle);
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
#else
|
||||
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Unlock the mutex.
|
||||
/// If any threads are waiting for the lock on this mutex, one of them will
|
||||
/// be unblocked.
|
||||
inline void unlock() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
mAlreadyLocked = false;
|
||||
LeaveCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutex_unlock(&mHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
_TTHREAD_DISABLE_ASSIGNMENT(mutex)
|
||||
|
||||
private:
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
CRITICAL_SECTION mHandle;
|
||||
bool mAlreadyLocked;
|
||||
#else
|
||||
pthread_mutex_t mHandle;
|
||||
#endif
|
||||
|
||||
friend class condition_variable;
|
||||
};
|
||||
friend class condition_variable;
|
||||
};
|
||||
|
||||
/// Recursive mutex class.
|
||||
/// This is a mutual exclusion object for synchronizing access to shared
|
||||
|
@ -248,81 +243,76 @@ class mutex {
|
|||
/// may lock the mutex several times, as long as it unlocks the mutex the same
|
||||
/// number of times).
|
||||
/// @see mutex
|
||||
class recursive_mutex {
|
||||
public:
|
||||
/// Constructor.
|
||||
recursive_mutex()
|
||||
{
|
||||
class recursive_mutex {
|
||||
public:
|
||||
/// Constructor.
|
||||
recursive_mutex() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
InitializeCriticalSection(&mHandle);
|
||||
InitializeCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&mHandle, &attr);
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&mHandle, &attr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
~recursive_mutex()
|
||||
{
|
||||
/// Destructor.
|
||||
~recursive_mutex() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
DeleteCriticalSection(&mHandle);
|
||||
DeleteCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutex_destroy(&mHandle);
|
||||
pthread_mutex_destroy(&mHandle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// Lock the mutex.
|
||||
/// The method will block the calling thread until a lock on the mutex can
|
||||
/// be obtained. The mutex remains locked until @c unlock() is called.
|
||||
/// @see lock_guard
|
||||
inline void lock()
|
||||
{
|
||||
/// Lock the mutex.
|
||||
/// The method will block the calling thread until a lock on the mutex can
|
||||
/// be obtained. The mutex remains locked until @c unlock() is called.
|
||||
/// @see lock_guard
|
||||
inline void lock() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
EnterCriticalSection(&mHandle);
|
||||
EnterCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutex_lock(&mHandle);
|
||||
pthread_mutex_lock(&mHandle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to lock the mutex.
|
||||
/// The method will try to lock the mutex. If it fails, the function will
|
||||
/// return immediately (non-blocking).
|
||||
/// @return @c true if the lock was acquired, or @c false if the lock could
|
||||
/// not be acquired.
|
||||
inline bool try_lock()
|
||||
{
|
||||
/// Try to lock the mutex.
|
||||
/// The method will try to lock the mutex. If it fails, the function will
|
||||
/// return immediately (non-blocking).
|
||||
/// @return @c true if the lock was acquired, or @c false if the lock could
|
||||
/// not be acquired.
|
||||
inline bool try_lock() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
return TryEnterCriticalSection(&mHandle) ? true : false;
|
||||
return TryEnterCriticalSection(&mHandle) ? true : false;
|
||||
#else
|
||||
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
|
||||
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// Unlock the mutex.
|
||||
/// If any threads are waiting for the lock on this mutex, one of them will
|
||||
/// be unblocked.
|
||||
inline void unlock()
|
||||
{
|
||||
/// Unlock the mutex.
|
||||
/// If any threads are waiting for the lock on this mutex, one of them will
|
||||
/// be unblocked.
|
||||
inline void unlock() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
LeaveCriticalSection(&mHandle);
|
||||
LeaveCriticalSection(&mHandle);
|
||||
#else
|
||||
pthread_mutex_unlock(&mHandle);
|
||||
pthread_mutex_unlock(&mHandle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
_TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex)
|
||||
_TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex)
|
||||
|
||||
private:
|
||||
private:
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
CRITICAL_SECTION mHandle;
|
||||
CRITICAL_SECTION mHandle;
|
||||
#else
|
||||
pthread_mutex_t mHandle;
|
||||
pthread_mutex_t mHandle;
|
||||
#endif
|
||||
|
||||
friend class condition_variable;
|
||||
};
|
||||
friend class condition_variable;
|
||||
};
|
||||
|
||||
/// Lock guard class.
|
||||
/// The constructor locks the mutex, and the destructor unlocks the mutex, so
|
||||
|
@ -339,30 +329,28 @@ class recursive_mutex {
|
|||
/// }
|
||||
/// @endcode
|
||||
|
||||
template <class T>
|
||||
class lock_guard {
|
||||
public:
|
||||
typedef T mutex_type;
|
||||
template <class T>
|
||||
class lock_guard {
|
||||
public:
|
||||
typedef T mutex_type;
|
||||
|
||||
lock_guard() : mMutex(0) {}
|
||||
lock_guard() : mMutex(0) {}
|
||||
|
||||
/// The constructor locks the mutex.
|
||||
explicit lock_guard(mutex_type &aMutex)
|
||||
{
|
||||
mMutex = &aMutex;
|
||||
mMutex->lock();
|
||||
}
|
||||
/// The constructor locks the mutex.
|
||||
explicit lock_guard(mutex_type & aMutex) {
|
||||
mMutex = &aMutex;
|
||||
mMutex->lock();
|
||||
}
|
||||
|
||||
/// The destructor unlocks the mutex.
|
||||
~lock_guard()
|
||||
{
|
||||
if(mMutex)
|
||||
mMutex->unlock();
|
||||
}
|
||||
/// The destructor unlocks the mutex.
|
||||
~lock_guard() {
|
||||
if (mMutex)
|
||||
mMutex->unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
mutex_type * mMutex;
|
||||
};
|
||||
private:
|
||||
mutex_type * mMutex;
|
||||
};
|
||||
|
||||
/// Condition variable class.
|
||||
/// This is a signalling object for synchronizing the execution flow for
|
||||
|
@ -389,323 +377,308 @@ class lock_guard {
|
|||
/// cond.notify_all();
|
||||
/// }
|
||||
/// @endcode
|
||||
class condition_variable {
|
||||
public:
|
||||
/// Constructor.
|
||||
class condition_variable {
|
||||
public:
|
||||
/// Constructor.
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
condition_variable();
|
||||
condition_variable();
|
||||
#else
|
||||
condition_variable()
|
||||
{
|
||||
pthread_cond_init(&mHandle, NULL);
|
||||
}
|
||||
condition_variable() {
|
||||
pthread_cond_init(&mHandle, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Destructor.
|
||||
/// Destructor.
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
~condition_variable();
|
||||
~condition_variable();
|
||||
#else
|
||||
~condition_variable()
|
||||
{
|
||||
pthread_cond_destroy(&mHandle);
|
||||
}
|
||||
~condition_variable() {
|
||||
pthread_cond_destroy(&mHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Wait for the condition.
|
||||
/// The function will block the calling thread until the condition variable
|
||||
/// is woken by @c notify_one(), @c notify_all() or a spurious wake up.
|
||||
/// @param[in] aMutex A mutex that will be unlocked when the wait operation
|
||||
/// starts, an locked again as soon as the wait operation is finished.
|
||||
template <class _mutexT>
|
||||
inline void wait(_mutexT &aMutex)
|
||||
{
|
||||
/// Wait for the condition.
|
||||
/// The function will block the calling thread until the condition variable
|
||||
/// is woken by @c notify_one(), @c notify_all() or a spurious wake up.
|
||||
/// @param[in] aMutex A mutex that will be unlocked when the wait operation
|
||||
/// starts, an locked again as soon as the wait operation is finished.
|
||||
template <class _mutexT>
|
||||
inline void wait(_mutexT & aMutex) {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
// Increment number of waiters
|
||||
EnterCriticalSection(&mWaitersCountLock);
|
||||
++ mWaitersCount;
|
||||
LeaveCriticalSection(&mWaitersCountLock);
|
||||
// Increment number of waiters
|
||||
EnterCriticalSection(&mWaitersCountLock);
|
||||
++ mWaitersCount;
|
||||
LeaveCriticalSection(&mWaitersCountLock);
|
||||
|
||||
// Release the mutex while waiting for the condition (will decrease
|
||||
// the number of waiters when done)...
|
||||
aMutex.unlock();
|
||||
_wait();
|
||||
aMutex.lock();
|
||||
// Release the mutex while waiting for the condition (will decrease
|
||||
// the number of waiters when done)...
|
||||
aMutex.unlock();
|
||||
_wait();
|
||||
aMutex.lock();
|
||||
#else
|
||||
pthread_cond_wait(&mHandle, &aMutex.mHandle);
|
||||
pthread_cond_wait(&mHandle, &aMutex.mHandle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// Notify one thread that is waiting for the condition.
|
||||
/// If at least one thread is blocked waiting for this condition variable,
|
||||
/// one will be woken up.
|
||||
/// @note Only threads that started waiting prior to this call will be
|
||||
/// woken up.
|
||||
/// Notify one thread that is waiting for the condition.
|
||||
/// If at least one thread is blocked waiting for this condition variable,
|
||||
/// one will be woken up.
|
||||
/// @note Only threads that started waiting prior to this call will be
|
||||
/// woken up.
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
void notify_one();
|
||||
void notify_one();
|
||||
#else
|
||||
inline void notify_one()
|
||||
{
|
||||
pthread_cond_signal(&mHandle);
|
||||
}
|
||||
inline void notify_one() {
|
||||
pthread_cond_signal(&mHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Notify all threads that are waiting for the condition.
|
||||
/// All threads that are blocked waiting for this condition variable will
|
||||
/// be woken up.
|
||||
/// @note Only threads that started waiting prior to this call will be
|
||||
/// woken up.
|
||||
/// Notify all threads that are waiting for the condition.
|
||||
/// All threads that are blocked waiting for this condition variable will
|
||||
/// be woken up.
|
||||
/// @note Only threads that started waiting prior to this call will be
|
||||
/// woken up.
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
void notify_all();
|
||||
void notify_all();
|
||||
#else
|
||||
inline void notify_all()
|
||||
{
|
||||
pthread_cond_broadcast(&mHandle);
|
||||
}
|
||||
inline void notify_all() {
|
||||
pthread_cond_broadcast(&mHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
_TTHREAD_DISABLE_ASSIGNMENT(condition_variable)
|
||||
_TTHREAD_DISABLE_ASSIGNMENT(condition_variable)
|
||||
|
||||
private:
|
||||
private:
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
void _wait();
|
||||
HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs.
|
||||
unsigned int mWaitersCount; ///< Count of the number of waiters.
|
||||
CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
|
||||
void _wait();
|
||||
HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs.
|
||||
unsigned int mWaitersCount; ///< Count of the number of waiters.
|
||||
CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
|
||||
#else
|
||||
pthread_cond_t mHandle;
|
||||
pthread_cond_t mHandle;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/// Thread class.
|
||||
class thread {
|
||||
public:
|
||||
class thread {
|
||||
public:
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
typedef HANDLE native_handle_type;
|
||||
typedef HANDLE native_handle_type;
|
||||
#else
|
||||
typedef pthread_t native_handle_type;
|
||||
typedef pthread_t native_handle_type;
|
||||
#endif
|
||||
|
||||
class id;
|
||||
class id;
|
||||
|
||||
/// Default constructor.
|
||||
/// Construct a @c thread object without an associated thread of execution
|
||||
/// (i.e. non-joinable).
|
||||
thread() : mHandle(0), mNotAThread(true)
|
||||
/// Default constructor.
|
||||
/// Construct a @c thread object without an associated thread of execution
|
||||
/// (i.e. non-joinable).
|
||||
thread() : mHandle(0), mNotAThread(true)
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
, mWin32ThreadID(0)
|
||||
, mWin32ThreadID(0)
|
||||
#endif
|
||||
{}
|
||||
{}
|
||||
|
||||
/// Thread starting constructor.
|
||||
/// Construct a @c thread object with a new thread of execution.
|
||||
/// @param[in] aFunction A function pointer to a function of type:
|
||||
/// <tt>void fun(void * arg)</tt>
|
||||
/// @param[in] aArg Argument to the thread function.
|
||||
/// @note This constructor is not fully compatible with the standard C++
|
||||
/// thread class. It is more similar to the pthread_create() (POSIX) and
|
||||
/// CreateThread() (Windows) functions.
|
||||
thread(void (*aFunction)(void *), void * aArg);
|
||||
/// Thread starting constructor.
|
||||
/// Construct a @c thread object with a new thread of execution.
|
||||
/// @param[in] aFunction A function pointer to a function of type:
|
||||
/// <tt>void fun(void * arg)</tt>
|
||||
/// @param[in] aArg Argument to the thread function.
|
||||
/// @note This constructor is not fully compatible with the standard C++
|
||||
/// thread class. It is more similar to the pthread_create() (POSIX) and
|
||||
/// CreateThread() (Windows) functions.
|
||||
thread(void (*aFunction)(void *), void * aArg);
|
||||
|
||||
/// Destructor.
|
||||
/// @note If the thread is joinable upon destruction, @c std::terminate()
|
||||
/// will be called, which terminates the process. It is always wise to do
|
||||
/// @c join() before deleting a thread object.
|
||||
~thread();
|
||||
/// Destructor.
|
||||
/// @note If the thread is joinable upon destruction, @c std::terminate()
|
||||
/// will be called, which terminates the process. It is always wise to do
|
||||
/// @c join() before deleting a thread object.
|
||||
~thread();
|
||||
|
||||
/// Wait for the thread to finish (join execution flows).
|
||||
/// After calling @c join(), the thread object is no longer associated with
|
||||
/// a thread of execution (i.e. it is not joinable, and you may not join
|
||||
/// with it nor detach from it).
|
||||
void join();
|
||||
/// Wait for the thread to finish (join execution flows).
|
||||
/// After calling @c join(), the thread object is no longer associated with
|
||||
/// a thread of execution (i.e. it is not joinable, and you may not join
|
||||
/// with it nor detach from it).
|
||||
void join();
|
||||
|
||||
/// Check if the thread is joinable.
|
||||
/// A thread object is joinable if it has an associated thread of execution.
|
||||
bool joinable() const;
|
||||
/// Check if the thread is joinable.
|
||||
/// A thread object is joinable if it has an associated thread of execution.
|
||||
bool joinable() const;
|
||||
|
||||
/// Detach from the thread.
|
||||
/// After calling @c detach(), the thread object is no longer assicated with
|
||||
/// a thread of execution (i.e. it is not joinable). The thread continues
|
||||
/// execution without the calling thread blocking, and when the thread
|
||||
/// ends execution, any owned resources are released.
|
||||
void detach();
|
||||
/// Detach from the thread.
|
||||
/// After calling @c detach(), the thread object is no longer assicated with
|
||||
/// a thread of execution (i.e. it is not joinable). The thread continues
|
||||
/// execution without the calling thread blocking, and when the thread
|
||||
/// ends execution, any owned resources are released.
|
||||
void detach();
|
||||
|
||||
/// Return the thread ID of a thread object.
|
||||
id get_id() const;
|
||||
/// Return the thread ID of a thread object.
|
||||
id get_id() const;
|
||||
|
||||
/// Get the native handle for this thread.
|
||||
/// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this
|
||||
/// is a @c pthread_t.
|
||||
inline native_handle_type native_handle()
|
||||
{
|
||||
return mHandle;
|
||||
}
|
||||
/// Get the native handle for this thread.
|
||||
/// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this
|
||||
/// is a @c pthread_t.
|
||||
inline native_handle_type native_handle() {
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
/// Determine the number of threads which can possibly execute concurrently.
|
||||
/// This function is useful for determining the optimal number of threads to
|
||||
/// use for a task.
|
||||
/// @return The number of hardware thread contexts in the system.
|
||||
/// @note If this value is not defined, the function returns zero (0).
|
||||
static unsigned hardware_concurrency();
|
||||
/// Determine the number of threads which can possibly execute concurrently.
|
||||
/// This function is useful for determining the optimal number of threads to
|
||||
/// use for a task.
|
||||
/// @return The number of hardware thread contexts in the system.
|
||||
/// @note If this value is not defined, the function returns zero (0).
|
||||
static unsigned hardware_concurrency();
|
||||
|
||||
_TTHREAD_DISABLE_ASSIGNMENT(thread)
|
||||
_TTHREAD_DISABLE_ASSIGNMENT(thread)
|
||||
|
||||
private:
|
||||
native_handle_type mHandle; ///< Thread handle.
|
||||
mutable mutex mDataMutex; ///< Serializer for access to the thread private data.
|
||||
bool mNotAThread; ///< True if this object is not a thread of execution.
|
||||
void * ti_copy;
|
||||
private:
|
||||
native_handle_type mHandle; ///< Thread handle.
|
||||
mutable mutex mDataMutex; ///< Serializer for access to the thread private data.
|
||||
bool mNotAThread; ///< True if this object is not a thread of execution.
|
||||
void * ti_copy;
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex).
|
||||
unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex).
|
||||
#endif
|
||||
|
||||
// This is the internal thread wrapper function.
|
||||
// This is the internal thread wrapper function.
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
static unsigned WINAPI wrapper_function(void * aArg);
|
||||
static unsigned WINAPI wrapper_function(void * aArg);
|
||||
#else
|
||||
static void * wrapper_function(void * aArg);
|
||||
static void * wrapper_function(void * aArg);
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
/// Thread ID.
|
||||
/// The thread ID is a unique identifier for each thread.
|
||||
/// @see thread::get_id()
|
||||
class thread::id {
|
||||
public:
|
||||
/// Default constructor.
|
||||
/// The default constructed ID is that of thread without a thread of
|
||||
/// execution.
|
||||
id() : mId(0) {};
|
||||
class thread::id {
|
||||
public:
|
||||
/// Default constructor.
|
||||
/// The default constructed ID is that of thread without a thread of
|
||||
/// execution.
|
||||
id() : mId(0) {};
|
||||
|
||||
id(unsigned long int aId) : mId(aId) {};
|
||||
id(unsigned long int aId) : mId(aId) {};
|
||||
|
||||
id(const id& aId) : mId(aId.mId) {};
|
||||
id(const id & aId) : mId(aId.mId) {};
|
||||
|
||||
inline id & operator=(const id &aId)
|
||||
{
|
||||
mId = aId.mId;
|
||||
return *this;
|
||||
}
|
||||
inline id & operator=(const id & aId) {
|
||||
mId = aId.mId;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline friend bool operator==(const id &aId1, const id &aId2)
|
||||
{
|
||||
return (aId1.mId == aId2.mId);
|
||||
}
|
||||
inline friend bool operator==(const id & aId1, const id & aId2) {
|
||||
return (aId1.mId == aId2.mId);
|
||||
}
|
||||
|
||||
inline friend bool operator!=(const id &aId1, const id &aId2)
|
||||
{
|
||||
return (aId1.mId != aId2.mId);
|
||||
}
|
||||
inline friend bool operator!=(const id & aId1, const id & aId2) {
|
||||
return (aId1.mId != aId2.mId);
|
||||
}
|
||||
|
||||
inline friend bool operator<=(const id &aId1, const id &aId2)
|
||||
{
|
||||
return (aId1.mId <= aId2.mId);
|
||||
}
|
||||
inline friend bool operator<=(const id & aId1, const id & aId2) {
|
||||
return (aId1.mId <= aId2.mId);
|
||||
}
|
||||
|
||||
inline friend bool operator<(const id &aId1, const id &aId2)
|
||||
{
|
||||
return (aId1.mId < aId2.mId);
|
||||
}
|
||||
inline friend bool operator<(const id & aId1, const id & aId2) {
|
||||
return (aId1.mId < aId2.mId);
|
||||
}
|
||||
|
||||
inline friend bool operator>=(const id &aId1, const id &aId2)
|
||||
{
|
||||
return (aId1.mId >= aId2.mId);
|
||||
}
|
||||
inline friend bool operator>=(const id & aId1, const id & aId2) {
|
||||
return (aId1.mId >= aId2.mId);
|
||||
}
|
||||
|
||||
inline friend bool operator>(const id &aId1, const id &aId2)
|
||||
{
|
||||
return (aId1.mId > aId2.mId);
|
||||
}
|
||||
inline friend bool operator>(const id & aId1, const id & aId2) {
|
||||
return (aId1.mId > aId2.mId);
|
||||
}
|
||||
|
||||
inline friend std::ostream& operator <<(std::ostream &os, const id &obj)
|
||||
{
|
||||
os << obj.mId;
|
||||
return os;
|
||||
}
|
||||
inline friend std::ostream & operator <<(std::ostream & os, const id & obj) {
|
||||
os << obj.mId;
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned long int mId;
|
||||
};
|
||||
private:
|
||||
unsigned long int mId;
|
||||
};
|
||||
|
||||
|
||||
// Related to <ratio> - minimal to be able to support chrono.
|
||||
typedef long long __intmax_t;
|
||||
typedef long long __intmax_t;
|
||||
|
||||
/// Minimal implementation of the @c ratio class. This class provides enough
|
||||
/// functionality to implement some basic @c chrono classes.
|
||||
template <__intmax_t N, __intmax_t D = 1> class ratio {
|
||||
public:
|
||||
static double _as_double() { return double(N) / double(D); }
|
||||
};
|
||||
|
||||
/// Minimal implementation of the @c chrono namespace.
|
||||
/// The @c chrono namespace provides types for specifying time intervals.
|
||||
namespace chrono {
|
||||
/// Duration template class. This class provides enough functionality to
|
||||
/// implement @c this_thread::sleep_for().
|
||||
template <class _Rep, class _Period = ratio<1> > class duration {
|
||||
private:
|
||||
_Rep rep_;
|
||||
template <__intmax_t N, __intmax_t D = 1> class ratio {
|
||||
public:
|
||||
typedef _Rep rep;
|
||||
typedef _Period period;
|
||||
|
||||
/// Construct a duration object with the given duration.
|
||||
template <class _Rep2>
|
||||
explicit duration(const _Rep2& r) : rep_(r) {};
|
||||
|
||||
/// Return the value of the duration object.
|
||||
rep count() const
|
||||
{
|
||||
return rep_;
|
||||
static double _as_double() {
|
||||
return double(N) / double(D);
|
||||
}
|
||||
};
|
||||
|
||||
// Standard duration types.
|
||||
typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds.
|
||||
typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds.
|
||||
typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds.
|
||||
typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds.
|
||||
typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes.
|
||||
typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours.
|
||||
}
|
||||
/// Minimal implementation of the @c chrono namespace.
|
||||
/// The @c chrono namespace provides types for specifying time intervals.
|
||||
namespace chrono {
|
||||
/// Duration template class. This class provides enough functionality to
|
||||
/// implement @c this_thread::sleep_for().
|
||||
template <class _Rep, class _Period = ratio<1> > class duration {
|
||||
private:
|
||||
_Rep rep_;
|
||||
public:
|
||||
typedef _Rep rep;
|
||||
typedef _Period period;
|
||||
|
||||
/// Construct a duration object with the given duration.
|
||||
template <class _Rep2>
|
||||
explicit duration(const _Rep2 & r) : rep_(r) {};
|
||||
|
||||
/// Return the value of the duration object.
|
||||
rep count() const {
|
||||
return rep_;
|
||||
}
|
||||
};
|
||||
|
||||
// Standard duration types.
|
||||
typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds.
|
||||
typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds.
|
||||
typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds.
|
||||
typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds.
|
||||
typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes.
|
||||
typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours.
|
||||
}
|
||||
|
||||
/// The namespace @c this_thread provides methods for dealing with the
|
||||
/// calling thread.
|
||||
namespace this_thread {
|
||||
/// Return the thread ID of the calling thread.
|
||||
thread::id get_id();
|
||||
namespace this_thread {
|
||||
/// Return the thread ID of the calling thread.
|
||||
thread::id get_id();
|
||||
|
||||
/// Yield execution to another thread.
|
||||
/// Offers the operating system the opportunity to schedule another thread
|
||||
/// that is ready to run on the current processor.
|
||||
inline void yield()
|
||||
{
|
||||
/// Yield execution to another thread.
|
||||
/// Offers the operating system the opportunity to schedule another thread
|
||||
/// that is ready to run on the current processor.
|
||||
inline void yield() {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
Sleep(0);
|
||||
Sleep(0);
|
||||
#else
|
||||
sched_yield();
|
||||
sched_yield();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// Blocks the calling thread for a period of time.
|
||||
/// @param[in] aTime Minimum time to put the thread to sleep.
|
||||
/// Example usage:
|
||||
/// @code
|
||||
/// // Sleep for 100 milliseconds
|
||||
/// this_thread::sleep_for(chrono::milliseconds(100));
|
||||
/// @endcode
|
||||
/// @note Supported duration types are: nanoseconds, microseconds,
|
||||
/// milliseconds, seconds, minutes and hours.
|
||||
template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime)
|
||||
{
|
||||
/// Blocks the calling thread for a period of time.
|
||||
/// @param[in] aTime Minimum time to put the thread to sleep.
|
||||
/// Example usage:
|
||||
/// @code
|
||||
/// // Sleep for 100 milliseconds
|
||||
/// this_thread::sleep_for(chrono::milliseconds(100));
|
||||
/// @endcode
|
||||
/// @note Supported duration types are: nanoseconds, microseconds,
|
||||
/// milliseconds, seconds, minutes and hours.
|
||||
template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period> & aTime) {
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5));
|
||||
Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5));
|
||||
#else
|
||||
usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5));
|
||||
usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
8
lib/ts_packet.cpp
Executable file → Normal file
8
lib/ts_packet.cpp
Executable file → Normal file
|
@ -36,9 +36,9 @@ namespace TS {
|
|||
/// It fills the content with the next 188 bytes int he file.
|
||||
/// \param Data The data to be read into the packet.
|
||||
/// \return true if it was possible to read in a full packet, false otherwise.
|
||||
bool Packet::FromFile(FILE * data){
|
||||
bool Packet::FromFile(FILE * data) {
|
||||
strBuf.resize(188);
|
||||
if (!fread((void*)strBuf.data(), 188, 1, data)){
|
||||
if (!fread((void *)strBuf.data(), 188, 1, data)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -577,12 +577,12 @@ namespace TS {
|
|||
///Gets the payload of this packet, as a raw char array
|
||||
///\return The payload of this ts packet as a char pointer
|
||||
const char * Packet::getPayload() {
|
||||
return strBuf.data() + (4 + (AdaptationField( ) > 1 ? AdaptationFieldLen() + 1 : 0));
|
||||
return strBuf.data() + (4 + (AdaptationField() > 1 ? AdaptationFieldLen() + 1 : 0));
|
||||
}
|
||||
|
||||
///Gets the length of the payload for this apcket
|
||||
///\return The amount of bytes payload in this packet
|
||||
int Packet::getPayloadLength(){
|
||||
int Packet::getPayloadLength() {
|
||||
return 184 - ((AdaptationField() > 1 ? AdaptationFieldLen() + 1 : 0));
|
||||
}
|
||||
|
||||
|
|
30
lib/ts_packet.h
Executable file → Normal file
30
lib/ts_packet.h
Executable file → Normal file
|
@ -162,13 +162,14 @@ namespace TS {
|
|||
//0xF000 = reserved(3) = 7, network pid = 4096
|
||||
//0x2AB104B2 = CRC32
|
||||
static char PAT[188] = {0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xB0, 0x0D, 0x00, 0x01, 0xC1, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x2A, 0xB1, 0x04,
|
||||
0xB2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
0xB2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
/// A standard Program Mapping Table, as generated by FFMPEG.
|
||||
/// Contains both Audio and Video mappings, works also on video- or audio-only streams.
|
||||
|
@ -192,13 +193,14 @@ namespace TS {
|
|||
//0xF000 = reserved(4) = 15, es_info_len = 0
|
||||
//0x2F44B99B = CRC32
|
||||
static char PMT[188] = {0x47, 0x50, 0x00, 0x10, 0x00, 0x02, 0xB0, 0x17, 0x00, 0x01, 0xC1, 0x00, 0x00, 0xE1, 0x00, 0xF0, 0x00, 0x1B, 0xE1, 0x00,
|
||||
0xF0, 0x00, 0x0F, 0xE1, 0x01, 0xF0, 0x00, 0x2F, 0x44, 0xB9, 0x9B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
0xF0, 0x00, 0x0F, 0xE1, 0x01, 0xF0, 0x00, 0x2F, 0x44, 0xB9, 0x9B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
} //TS namespace
|
||||
|
||||
|
|
380
lib/vorbis.cpp
380
lib/vorbis.cpp
|
@ -10,224 +10,224 @@
|
|||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
namespace vorbis{
|
||||
long long unsigned int reverseByte16(long long unsigned int input){
|
||||
namespace vorbis {
|
||||
long long unsigned int reverseByte16(long long unsigned int input) {
|
||||
return ((input & 0xFF00) >> 8) | ((input & 0xFF) << 8);
|
||||
}
|
||||
|
||||
long long unsigned int reverseByte24(long long unsigned int input){
|
||||
return ((input & 0xFF0000) >> 16)| (input & 0xFF00) | ((input & 0xFF) << 16);
|
||||
long long unsigned int reverseByte24(long long unsigned int input) {
|
||||
return ((input & 0xFF0000) >> 16) | (input & 0xFF00) | ((input & 0xFF) << 16);
|
||||
}
|
||||
|
||||
long long unsigned int reverseByte32(long long unsigned int input){
|
||||
return ((input & 0xFF000000) >> 24)| ((input & 0xFF0000) >> 8) | ((input & 0xFF00) << 8) | ((input & 0xFF) << 24);
|
||||
long long unsigned int reverseByte32(long long unsigned int input) {
|
||||
return ((input & 0xFF000000) >> 24) | ((input & 0xFF0000) >> 8) | ((input & 0xFF00) << 8) | ((input & 0xFF) << 24);
|
||||
}
|
||||
|
||||
|
||||
header::header(){
|
||||
header::header() {
|
||||
data = NULL;
|
||||
datasize = 0;
|
||||
}
|
||||
|
||||
header::header(char * newData, unsigned int length){
|
||||
header::header(char * newData, unsigned int length) {
|
||||
data = NULL;
|
||||
datasize = 0;
|
||||
read(newData, length);
|
||||
}
|
||||
|
||||
int header::getHeaderType(){
|
||||
|
||||
int header::getHeaderType() {
|
||||
return (int)(data[0]);
|
||||
}
|
||||
|
||||
long unsigned int header::getVorbisVersion(){
|
||||
if (getHeaderType() == 1){
|
||||
|
||||
long unsigned int header::getVorbisVersion() {
|
||||
if (getHeaderType() == 1) {
|
||||
return getInt32(7);
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char header::getAudioChannels(){
|
||||
if (getHeaderType() == 1){
|
||||
|
||||
char header::getAudioChannels() {
|
||||
if (getHeaderType() == 1) {
|
||||
return data[11];
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
long unsigned int header::getAudioSampleRate(){
|
||||
if (getHeaderType() == 1){
|
||||
|
||||
long unsigned int header::getAudioSampleRate() {
|
||||
if (getHeaderType() == 1) {
|
||||
return ntohl(getInt32(12));
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
long unsigned int header::getBitrateMaximum(){
|
||||
if (getHeaderType() == 1){
|
||||
|
||||
long unsigned int header::getBitrateMaximum() {
|
||||
if (getHeaderType() == 1) {
|
||||
return getInt32(16);
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
long unsigned int header::getBitrateNominal(){
|
||||
if (getHeaderType() == 1){
|
||||
|
||||
long unsigned int header::getBitrateNominal() {
|
||||
if (getHeaderType() == 1) {
|
||||
return getInt32(20);
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
long unsigned int header::getBitrateMinimum(){
|
||||
if (getHeaderType() == 1){
|
||||
|
||||
long unsigned int header::getBitrateMinimum() {
|
||||
if (getHeaderType() == 1) {
|
||||
return getInt32(24);
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char header::getBlockSize0(){
|
||||
if (getHeaderType() == 1){
|
||||
|
||||
char header::getBlockSize0() {
|
||||
if (getHeaderType() == 1) {
|
||||
return data[28] & 0x0F;
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char header::getBlockSize1(){
|
||||
if (getHeaderType() == 1){
|
||||
return (data[28]>>4) & 0x0F;
|
||||
}else{
|
||||
char header::getBlockSize1() {
|
||||
if (getHeaderType() == 1) {
|
||||
return (data[28] >> 4) & 0x0F;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char header::getFramingFlag(){
|
||||
if (getHeaderType() == 1){
|
||||
|
||||
char header::getFramingFlag() {
|
||||
if (getHeaderType() == 1) {
|
||||
return data[29];
|
||||
}else{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool header::checkDataSize(unsigned int size){
|
||||
if (size > datasize){
|
||||
void* tmp = realloc(data,size);
|
||||
if (tmp){
|
||||
data = (char*)tmp;
|
||||
|
||||
bool header::checkDataSize(unsigned int size) {
|
||||
if (size > datasize) {
|
||||
void * tmp = realloc(data, size);
|
||||
if (tmp) {
|
||||
data = (char *)tmp;
|
||||
datasize = size;
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool header::validate(){
|
||||
switch(getHeaderType()){
|
||||
bool header::validate() {
|
||||
switch (getHeaderType()) {
|
||||
case 1://ID header
|
||||
if (datasize!=30){
|
||||
if (datasize != 30) {
|
||||
return false;
|
||||
}
|
||||
if (getVorbisVersion()!=0){
|
||||
if (getVorbisVersion() != 0) {
|
||||
return false;
|
||||
}
|
||||
if (getAudioChannels()<=0){
|
||||
if (getAudioChannels() <= 0) {
|
||||
return false;
|
||||
};
|
||||
if (getAudioSampleRate()<=0) {
|
||||
if (getAudioSampleRate() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (getBlockSize0()>getBlockSize1()){
|
||||
if (getBlockSize0() > getBlockSize1()) {
|
||||
return false;
|
||||
};
|
||||
if (getFramingFlag()!=1){
|
||||
if (getFramingFlag() != 1) {
|
||||
return false;
|
||||
};
|
||||
break;
|
||||
break;
|
||||
case 3://comment header
|
||||
break;
|
||||
break;
|
||||
case 5://init header
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool header::read(char* newData, unsigned int length){
|
||||
if (length < 7){
|
||||
bool header::read(char * newData, unsigned int length) {
|
||||
if (length < 7) {
|
||||
return false;
|
||||
}
|
||||
if(memcmp(newData+1, "vorbis", 6)!=0){
|
||||
if (memcmp(newData + 1, "vorbis", 6) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkDataSize(length)){
|
||||
if (checkDataSize(length)) {
|
||||
memcpy(data, newData, length);
|
||||
}else{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::deque<mode> header::readModeDeque(char audioChannels){
|
||||
|
||||
std::deque<mode> header::readModeDeque(char audioChannels) {
|
||||
Utils::bitstreamLSBF stream;
|
||||
stream.append(data,datasize);
|
||||
stream.append(data, datasize);
|
||||
stream.skip(28); //skipping common header part
|
||||
stream.skip(28); //skipping common header part
|
||||
char codebook_count = stream.get(8) + 1;
|
||||
for (int i = 0; i < codebook_count; i++){
|
||||
for (int i = 0; i < codebook_count; i++) {
|
||||
long long unsigned int CMN = stream.get(24);
|
||||
if (CMN != 0x564342){
|
||||
DEBUG_MSG(DLVL_WARN,"Is dit het? VCB != %c%c%c", (char)(CMN >> 16), (char)(CMN >> 8), (char)CMN);
|
||||
if (CMN != 0x564342) {
|
||||
DEBUG_MSG(DLVL_WARN, "Is dit het? VCB != %c%c%c", (char)(CMN >> 16), (char)(CMN >> 8), (char)CMN);
|
||||
exit(1);
|
||||
}
|
||||
unsigned short codebook_dimensions = stream.get(16);
|
||||
unsigned int codebook_entries = stream.get(24);
|
||||
bool orderedFlag = stream.get(1);
|
||||
if (!orderedFlag){
|
||||
if (!orderedFlag) {
|
||||
bool sparseFlag = stream.get(1);
|
||||
if (sparseFlag){//sparse flag
|
||||
if (sparseFlag) { //sparse flag
|
||||
//sparse handling
|
||||
for (unsigned int o = 0; o < codebook_entries; o++){
|
||||
if (stream.get(1)){
|
||||
for (unsigned int o = 0; o < codebook_entries; o++) {
|
||||
if (stream.get(1)) {
|
||||
stream.skip(5);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for (unsigned int o = 0; o < codebook_entries; o++){
|
||||
} else {
|
||||
for (unsigned int o = 0; o < codebook_entries; o++) {
|
||||
stream.skip(5);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
//ordered handling
|
||||
stream.skip(5);
|
||||
for (unsigned int o = 0; o < codebook_entries; o++){
|
||||
int readnow = (std::log(codebook_entries-o))/(std::log(2))+1;
|
||||
o+=stream.get(readnow);
|
||||
|
||||
for (unsigned int o = 0; o < codebook_entries; o++) {
|
||||
int readnow = (std::log(codebook_entries - o)) / (std::log(2)) + 1;
|
||||
o += stream.get(readnow);
|
||||
|
||||
}
|
||||
}
|
||||
char codebook_lookup_type = stream.get(4);
|
||||
if (codebook_lookup_type != 0){
|
||||
if (codebook_lookup_type != 0) {
|
||||
stream.skip(32);
|
||||
stream.skip(32);
|
||||
char codebook_value_bits = stream.get(4) + 1;
|
||||
stream.skip(1);
|
||||
unsigned int codebook_lookup_value;
|
||||
if (codebook_lookup_type == 1){
|
||||
codebook_lookup_value = std::pow(codebook_entries, (1.0/codebook_dimensions));
|
||||
}else{
|
||||
if (codebook_lookup_type == 1) {
|
||||
codebook_lookup_value = std::pow(codebook_entries, (1.0 / codebook_dimensions));
|
||||
} else {
|
||||
codebook_lookup_value = codebook_entries * codebook_dimensions;
|
||||
}
|
||||
for (unsigned int i = 0; i < codebook_lookup_value; i++){
|
||||
for (unsigned int i = 0; i < codebook_lookup_value; i++) {
|
||||
stream.skip(codebook_value_bits);
|
||||
}
|
||||
}
|
||||
|
@ -235,140 +235,140 @@ namespace vorbis{
|
|||
//end of codebooks
|
||||
//time domain transforms
|
||||
long long unsigned int TDT = stream.get(6) + 1;
|
||||
for (unsigned int i = 0; i < TDT; i++){
|
||||
for (unsigned int i = 0; i < TDT; i++) {
|
||||
stream.skip(16);
|
||||
}
|
||||
//Floors
|
||||
long long unsigned int floors = stream.get(6) + 1;
|
||||
for (unsigned int i = 0; i < floors; i++){
|
||||
for (unsigned int i = 0; i < floors; i++) {
|
||||
long long unsigned int floorType = stream.get(16);
|
||||
switch(floorType){
|
||||
case 0:{
|
||||
DEBUG_MSG(DLVL_WARN, "FloorType 0 in vorbis setup header not tested!");
|
||||
stream.skip(8);//order
|
||||
stream.skip(16);//rate
|
||||
stream.skip(16);//bark_map_size
|
||||
stream.skip(6);//amplitude bits
|
||||
stream.skip(8);//amplitude offset
|
||||
long long unsigned int numberOfBooks = stream.get(4)+1;
|
||||
for (unsigned int o = 0; o < numberOfBooks; o++){
|
||||
stream.skip(8);//book list array
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:{
|
||||
long long unsigned int floorPartitions = stream.get(5);
|
||||
long long int max = -1;
|
||||
std::deque<int> partition_class;
|
||||
for (unsigned int o = 0; o < floorPartitions; o++){
|
||||
long long int temp = stream.get(4);
|
||||
partition_class.push_back(temp);
|
||||
if (temp>max) max = temp;
|
||||
}
|
||||
std::deque<int> class_dimensions;
|
||||
for (int o = 0; o <= max; o++){
|
||||
class_dimensions.push_back(stream.get(3)+1);//class dimensions PUT IN ARRAY!
|
||||
int class_subclass = stream.get(2);
|
||||
if (class_subclass !=0){
|
||||
stream.skip(8);//class_master_books
|
||||
}
|
||||
for (int p = 0; p < (1<<class_subclass); p++){
|
||||
stream.skip(8);
|
||||
switch (floorType) {
|
||||
case 0: {
|
||||
DEBUG_MSG(DLVL_WARN, "FloorType 0 in vorbis setup header not tested!");
|
||||
stream.skip(8);//order
|
||||
stream.skip(16);//rate
|
||||
stream.skip(16);//bark_map_size
|
||||
stream.skip(6);//amplitude bits
|
||||
stream.skip(8);//amplitude offset
|
||||
long long unsigned int numberOfBooks = stream.get(4) + 1;
|
||||
for (unsigned int o = 0; o < numberOfBooks; o++) {
|
||||
stream.skip(8);//book list array
|
||||
}
|
||||
break;
|
||||
}
|
||||
stream.skip(2);//floor1_multiplier
|
||||
int rangebits = stream.get(4);//rangebits
|
||||
long long unsigned int count = 0;
|
||||
long long unsigned int skipper = 0;
|
||||
for (unsigned int o = 0; o < floorPartitions; o++){
|
||||
count += class_dimensions[(partition_class[o])];
|
||||
while (skipper < count){
|
||||
stream.skip(rangebits);
|
||||
skipper ++;
|
||||
case 1: {
|
||||
long long unsigned int floorPartitions = stream.get(5);
|
||||
long long int max = -1;
|
||||
std::deque<int> partition_class;
|
||||
for (unsigned int o = 0; o < floorPartitions; o++) {
|
||||
long long int temp = stream.get(4);
|
||||
partition_class.push_back(temp);
|
||||
if (temp > max) max = temp;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::deque<int> class_dimensions;
|
||||
for (int o = 0; o <= max; o++) {
|
||||
class_dimensions.push_back(stream.get(3) + 1); //class dimensions PUT IN ARRAY!
|
||||
int class_subclass = stream.get(2);
|
||||
if (class_subclass != 0) {
|
||||
stream.skip(8);//class_master_books
|
||||
}
|
||||
for (int p = 0; p < (1 << class_subclass); p++) {
|
||||
stream.skip(8);
|
||||
}
|
||||
}
|
||||
stream.skip(2);//floor1_multiplier
|
||||
int rangebits = stream.get(4);//rangebits
|
||||
long long unsigned int count = 0;
|
||||
long long unsigned int skipper = 0;
|
||||
for (unsigned int o = 0; o < floorPartitions; o++) {
|
||||
count += class_dimensions[(partition_class[o])];
|
||||
while (skipper < count) {
|
||||
stream.skip(rangebits);
|
||||
skipper ++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
//Residues
|
||||
long long unsigned int residues = stream.get(6) + 1;
|
||||
for(unsigned int i = 0; i < residues; i++){
|
||||
for (unsigned int i = 0; i < residues; i++) {
|
||||
std::deque<char> residueCascade;
|
||||
long long unsigned int residueType = stream.get(16);
|
||||
if(residueType<=2){
|
||||
if (residueType <= 2) {
|
||||
stream.skip(24);//residue begin
|
||||
stream.skip(24);//residue end
|
||||
stream.skip(24);//residue partition size
|
||||
long long unsigned int residueClass = stream.get(6)+1;//residue classifications
|
||||
long long unsigned int residueClass = stream.get(6) + 1; //residue classifications
|
||||
stream.skip(8);//residue classbook
|
||||
for (unsigned int o = 0; o < residueClass; o++){
|
||||
for (unsigned int o = 0; o < residueClass; o++) {
|
||||
char temp = stream.get(3);//low bits
|
||||
bool bitFlag = stream.get(1);
|
||||
if (bitFlag){
|
||||
if (bitFlag) {
|
||||
temp += stream.get(5) << 3;
|
||||
}
|
||||
residueCascade.push_back(temp);
|
||||
}
|
||||
for (unsigned int o = 0; o < residueClass; o++){
|
||||
for (unsigned int p = 0; p < 7; p++){
|
||||
if (((residueCascade[o] >> p) & 1) == 1){
|
||||
for (unsigned int o = 0; o < residueClass; o++) {
|
||||
for (unsigned int p = 0; p < 7; p++) {
|
||||
if (((residueCascade[o] >> p) & 1) == 1) {
|
||||
stream.skip(8);
|
||||
}else{
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
//Mappings
|
||||
long long unsigned int mappings = stream.get(6) + 1;
|
||||
for(unsigned int i = 0; i < mappings; i++){
|
||||
for (unsigned int i = 0; i < mappings; i++) {
|
||||
long long unsigned int mapType = stream.get(16);
|
||||
if (mapType == 0){
|
||||
if (mapType == 0) {
|
||||
char mappingSubmaps = 1;
|
||||
if (stream.get(1)==1){
|
||||
if (stream.get(1) == 1) {
|
||||
mappingSubmaps = stream.get(4);//vorbis mapping submaps
|
||||
}
|
||||
long long unsigned int coupling_steps = 0;
|
||||
if (stream.get(1)==1){
|
||||
coupling_steps = stream.get(8)+1;
|
||||
for (unsigned int o = 0; o<coupling_steps; o++){
|
||||
int temp = (std::log((audioChannels-o)-1))/(std::log(2)) + 1;
|
||||
if (temp>0){
|
||||
if (stream.get(1) == 1) {
|
||||
coupling_steps = stream.get(8) + 1;
|
||||
for (unsigned int o = 0; o < coupling_steps; o++) {
|
||||
int temp = (std::log((audioChannels - o) - 1)) / (std::log(2)) + 1;
|
||||
if (temp > 0) {
|
||||
stream.skip(temp);//mapping magnitude
|
||||
stream.skip(temp);//mapping angle
|
||||
}
|
||||
}
|
||||
}
|
||||
char meh = stream.get(2);
|
||||
if (meh != 0){
|
||||
if (meh != 0) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Sanity check ==0 : %i", (int)meh);
|
||||
exit(0);
|
||||
}
|
||||
if (mappingSubmaps > 1){
|
||||
for (int o = 0; o < audioChannels; o++){
|
||||
if (mappingSubmaps > 1) {
|
||||
for (int o = 0; o < audioChannels; o++) {
|
||||
stream.skip(4);
|
||||
}
|
||||
}
|
||||
for (int o = 0; o < mappingSubmaps; o++){
|
||||
for (int o = 0; o < mappingSubmaps; o++) {
|
||||
stream.skip(8);//placeholder
|
||||
stream.skip(8);//vorbis Mapping subfloor
|
||||
stream.skip(8);//vorbis mapping submap residue
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
//Modes
|
||||
long long unsigned int modes = stream.get(6) + 1;
|
||||
std::deque<mode> retVal;
|
||||
for (unsigned int i = 0; i < modes; i++){
|
||||
for (unsigned int i = 0; i < modes; i++) {
|
||||
mode temp;
|
||||
temp.blockFlag = stream.get(1);
|
||||
temp.windowType = stream.get(16);
|
||||
|
@ -380,46 +380,46 @@ namespace vorbis{
|
|||
return retVal;
|
||||
}
|
||||
|
||||
uint32_t header::getInt32(size_t index){
|
||||
if (datasize >= (index + 3)){
|
||||
uint32_t header::getInt32(size_t index) {
|
||||
if (datasize >= (index + 3)) {
|
||||
return (data[index] << 24) + (data[index + 1] << 16) + (data[index + 2] << 8) + data[index + 3];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t header::getInt24(size_t index){
|
||||
if (datasize >= (index + 2)){
|
||||
uint32_t header::getInt24(size_t index) {
|
||||
if (datasize >= (index + 2)) {
|
||||
return 0 + (data[index] << 16) + (data[index + 1] << 8) + data[index + 2];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t header::getInt16(size_t index){
|
||||
if (datasize >= (index + 1)){
|
||||
uint16_t header::getInt16(size_t index) {
|
||||
if (datasize >= (index + 1)) {
|
||||
return 0 + (data[index] << 8) + data[index + 1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string header::toPrettyString(size_t indent){
|
||||
|
||||
std::string header::toPrettyString(size_t indent) {
|
||||
std::stringstream r;
|
||||
r << std::string(indent+1,' ') << "Vorbis Header" << std::endl;
|
||||
r << std::string(indent+2,' ') << "Magic Number: " << std::string(data + 1,6) << std::endl;
|
||||
r << std::string(indent+2,' ') << "Header Type: " << getHeaderType() << std::endl;
|
||||
if (getHeaderType() == 1){
|
||||
r << std::string(indent+2,' ') << "ID Header" << std::endl;
|
||||
r << std::string(indent+2,' ') << "VorbisVersion: " << getVorbisVersion() << std::endl;
|
||||
r << std::string(indent+2,' ') << "AudioChannels: " << (int)getAudioChannels() << std::endl;
|
||||
r << std::string(indent+2,' ') << "BitrateMaximum: " << std::hex << getBitrateMaximum() << std::dec << std::endl;
|
||||
r << std::string(indent+2,' ') << "BitrateNominal: " << std::hex << getBitrateNominal() << std::dec << std::endl;
|
||||
r << std::string(indent+2,' ') << "BitrateMinimum: " << std::hex << getBitrateMinimum() << std::dec << std::endl;
|
||||
r << std::string(indent+2,' ') << "BlockSize0: " << (int)getBlockSize0() << std::endl;
|
||||
r << std::string(indent+2,' ') << "BlockSize1: " << (int)getBlockSize1() << std::endl;
|
||||
r << std::string(indent+2,' ') << "FramingFlag: " << (int)getFramingFlag() << std::endl;
|
||||
} else if (getHeaderType() == 3){
|
||||
r << std::string(indent+2,' ') << "Comment Header" << std::endl;
|
||||
} else if (getHeaderType() == 5){
|
||||
r << std::string(indent+2,' ') << "Setup Header" << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Vorbis Header" << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "Magic Number: " << std::string(data + 1, 6) << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "Header Type: " << getHeaderType() << std::endl;
|
||||
if (getHeaderType() == 1) {
|
||||
r << std::string(indent + 2, ' ') << "ID Header" << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "VorbisVersion: " << getVorbisVersion() << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "AudioChannels: " << (int)getAudioChannels() << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "BitrateMaximum: " << std::hex << getBitrateMaximum() << std::dec << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "BitrateNominal: " << std::hex << getBitrateNominal() << std::dec << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "BitrateMinimum: " << std::hex << getBitrateMinimum() << std::dec << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "BlockSize0: " << (int)getBlockSize0() << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "BlockSize1: " << (int)getBlockSize1() << std::endl;
|
||||
r << std::string(indent + 2, ' ') << "FramingFlag: " << (int)getFramingFlag() << std::endl;
|
||||
} else if (getHeaderType() == 3) {
|
||||
r << std::string(indent + 2, ' ') << "Comment Header" << std::endl;
|
||||
} else if (getHeaderType() == 5) {
|
||||
r << std::string(indent + 2, ' ') << "Setup Header" << std::endl;
|
||||
}
|
||||
return r.str();
|
||||
}
|
||||
|
|
22
lib/vorbis.h
22
lib/vorbis.h
|
@ -5,23 +5,23 @@
|
|||
#include <string>
|
||||
#include <deque>
|
||||
|
||||
namespace vorbis{
|
||||
struct mode{
|
||||
namespace vorbis {
|
||||
struct mode {
|
||||
bool blockFlag;
|
||||
unsigned short windowType;
|
||||
unsigned short transformType;
|
||||
char mapping;
|
||||
};
|
||||
|
||||
inline unsigned int ilog(unsigned int input){
|
||||
return (std::log(input))/(std::log(2))+1;
|
||||
|
||||
inline unsigned int ilog(unsigned int input) {
|
||||
return (std::log(input)) / (std::log(2)) + 1;
|
||||
}
|
||||
|
||||
class header{
|
||||
|
||||
class header {
|
||||
public:
|
||||
header();
|
||||
header(char* newData, unsigned int length);
|
||||
bool read(char* newData, unsigned int length);
|
||||
header(char * newData, unsigned int length);
|
||||
bool read(char * newData, unsigned int length);
|
||||
int getHeaderType();
|
||||
long unsigned int getVorbisVersion();
|
||||
char getAudioChannels();
|
||||
|
@ -40,9 +40,9 @@ namespace vorbis{
|
|||
uint16_t getInt16(size_t index);
|
||||
private:
|
||||
std::deque<mode> modes;
|
||||
char* data;
|
||||
char * data;
|
||||
unsigned int datasize;
|
||||
bool checkDataSize(unsigned int size);
|
||||
bool validate();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue