mirror of
https://github.com/danog/libtgvoip.git
synced 2024-12-03 10:07:45 +01:00
5caaaafa42
I'm now using the entire audio processing module from WebRTC as opposed to individual DSP algorithms pulled from there before. Seems to work better this way.
446 lines
13 KiB
C++
446 lines
13 KiB
C++
/*
|
|
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "rtc_base/stringencode.h"
|
|
|
|
#include <cstdio>
|
|
|
|
#include "rtc_base/arraysize.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/stringutils.h"
|
|
|
|
namespace rtc {
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// String Encoding Utilities
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
size_t url_decode(char* buffer,
|
|
size_t buflen,
|
|
const char* source,
|
|
size_t srclen) {
|
|
if (nullptr == buffer)
|
|
return srclen + 1;
|
|
if (buflen <= 0)
|
|
return 0;
|
|
|
|
unsigned char h1, h2;
|
|
size_t srcpos = 0, bufpos = 0;
|
|
while ((srcpos < srclen) && (bufpos + 1 < buflen)) {
|
|
unsigned char ch = source[srcpos++];
|
|
if (ch == '+') {
|
|
buffer[bufpos++] = ' ';
|
|
} else if ((ch == '%') && (srcpos + 1 < srclen) &&
|
|
hex_decode(source[srcpos], &h1) &&
|
|
hex_decode(source[srcpos + 1], &h2)) {
|
|
buffer[bufpos++] = (h1 << 4) | h2;
|
|
srcpos += 2;
|
|
} else {
|
|
buffer[bufpos++] = ch;
|
|
}
|
|
}
|
|
buffer[bufpos] = '\0';
|
|
return bufpos;
|
|
}
|
|
|
|
static const char HEX[] = "0123456789abcdef";
|
|
|
|
char hex_encode(unsigned char val) {
|
|
RTC_DCHECK_LT(val, 16);
|
|
return (val < 16) ? HEX[val] : '!';
|
|
}
|
|
|
|
bool hex_decode(char ch, unsigned char* val) {
|
|
if ((ch >= '0') && (ch <= '9')) {
|
|
*val = ch - '0';
|
|
} else if ((ch >= 'A') && (ch <= 'F')) {
|
|
*val = (ch - 'A') + 10;
|
|
} else if ((ch >= 'a') && (ch <= 'f')) {
|
|
*val = (ch - 'a') + 10;
|
|
} else {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
size_t hex_encode(char* buffer,
|
|
size_t buflen,
|
|
const char* csource,
|
|
size_t srclen) {
|
|
return hex_encode_with_delimiter(buffer, buflen, csource, srclen, 0);
|
|
}
|
|
|
|
size_t hex_encode_with_delimiter(char* buffer,
|
|
size_t buflen,
|
|
const char* csource,
|
|
size_t srclen,
|
|
char delimiter) {
|
|
RTC_DCHECK(buffer); // TODO(kwiberg): estimate output size
|
|
if (buflen == 0)
|
|
return 0;
|
|
|
|
// Init and check bounds.
|
|
const unsigned char* bsource =
|
|
reinterpret_cast<const unsigned char*>(csource);
|
|
size_t srcpos = 0, bufpos = 0;
|
|
size_t needed = delimiter ? (srclen * 3) : (srclen * 2 + 1);
|
|
if (buflen < needed)
|
|
return 0;
|
|
|
|
while (srcpos < srclen) {
|
|
unsigned char ch = bsource[srcpos++];
|
|
buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
|
|
buffer[bufpos + 1] = hex_encode((ch)&0xF);
|
|
bufpos += 2;
|
|
|
|
// Don't write a delimiter after the last byte.
|
|
if (delimiter && (srcpos < srclen)) {
|
|
buffer[bufpos] = delimiter;
|
|
++bufpos;
|
|
}
|
|
}
|
|
|
|
// Null terminate.
|
|
buffer[bufpos] = '\0';
|
|
return bufpos;
|
|
}
|
|
|
|
std::string hex_encode(const std::string& str) {
|
|
return hex_encode(str.c_str(), str.size());
|
|
}
|
|
|
|
std::string hex_encode(const char* source, size_t srclen) {
|
|
return hex_encode_with_delimiter(source, srclen, 0);
|
|
}
|
|
|
|
std::string hex_encode_with_delimiter(const char* source,
|
|
size_t srclen,
|
|
char delimiter) {
|
|
const size_t kBufferSize = srclen * 3;
|
|
char* buffer = STACK_ARRAY(char, kBufferSize);
|
|
size_t length =
|
|
hex_encode_with_delimiter(buffer, kBufferSize, source, srclen, delimiter);
|
|
RTC_DCHECK(srclen == 0 || length > 0);
|
|
return std::string(buffer, length);
|
|
}
|
|
|
|
size_t hex_decode(char* cbuffer,
|
|
size_t buflen,
|
|
const char* source,
|
|
size_t srclen) {
|
|
return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
|
|
}
|
|
|
|
size_t hex_decode_with_delimiter(char* cbuffer,
|
|
size_t buflen,
|
|
const char* source,
|
|
size_t srclen,
|
|
char delimiter) {
|
|
RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size
|
|
if (buflen == 0)
|
|
return 0;
|
|
|
|
// Init and bounds check.
|
|
unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
|
|
size_t srcpos = 0, bufpos = 0;
|
|
size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
|
|
if (buflen < needed)
|
|
return 0;
|
|
|
|
while (srcpos < srclen) {
|
|
if ((srclen - srcpos) < 2) {
|
|
// This means we have an odd number of bytes.
|
|
return 0;
|
|
}
|
|
|
|
unsigned char h1, h2;
|
|
if (!hex_decode(source[srcpos], &h1) ||
|
|
!hex_decode(source[srcpos + 1], &h2))
|
|
return 0;
|
|
|
|
bbuffer[bufpos++] = (h1 << 4) | h2;
|
|
srcpos += 2;
|
|
|
|
// Remove the delimiter if needed.
|
|
if (delimiter && (srclen - srcpos) > 1) {
|
|
if (source[srcpos] != delimiter)
|
|
return 0;
|
|
++srcpos;
|
|
}
|
|
}
|
|
|
|
return bufpos;
|
|
}
|
|
|
|
size_t hex_decode(char* buffer, size_t buflen, const std::string& source) {
|
|
return hex_decode_with_delimiter(buffer, buflen, source, 0);
|
|
}
|
|
size_t hex_decode_with_delimiter(char* buffer,
|
|
size_t buflen,
|
|
const std::string& source,
|
|
char delimiter) {
|
|
return hex_decode_with_delimiter(buffer, buflen, source.c_str(),
|
|
source.length(), delimiter);
|
|
}
|
|
|
|
size_t transform(std::string& value,
|
|
size_t maxlen,
|
|
const std::string& source,
|
|
Transform t) {
|
|
char* buffer = STACK_ARRAY(char, maxlen + 1);
|
|
size_t length = t(buffer, maxlen + 1, source.data(), source.length());
|
|
value.assign(buffer, length);
|
|
return length;
|
|
}
|
|
|
|
std::string s_transform(const std::string& source, Transform t) {
|
|
// Ask transformation function to approximate the destination size (returns
|
|
// upper bound)
|
|
size_t maxlen = t(nullptr, 0, source.data(), source.length());
|
|
char* buffer = STACK_ARRAY(char, maxlen);
|
|
size_t len = t(buffer, maxlen, source.data(), source.length());
|
|
std::string result(buffer, len);
|
|
return result;
|
|
}
|
|
|
|
size_t tokenize(const std::string& source,
|
|
char delimiter,
|
|
std::vector<std::string>* fields) {
|
|
fields->clear();
|
|
size_t last = 0;
|
|
for (size_t i = 0; i < source.length(); ++i) {
|
|
if (source[i] == delimiter) {
|
|
if (i != last) {
|
|
fields->push_back(source.substr(last, i - last));
|
|
}
|
|
last = i + 1;
|
|
}
|
|
}
|
|
if (last != source.length()) {
|
|
fields->push_back(source.substr(last, source.length() - last));
|
|
}
|
|
return fields->size();
|
|
}
|
|
|
|
size_t tokenize_with_empty_tokens(const std::string& source,
|
|
char delimiter,
|
|
std::vector<std::string>* fields) {
|
|
fields->clear();
|
|
size_t last = 0;
|
|
for (size_t i = 0; i < source.length(); ++i) {
|
|
if (source[i] == delimiter) {
|
|
fields->push_back(source.substr(last, i - last));
|
|
last = i + 1;
|
|
}
|
|
}
|
|
fields->push_back(source.substr(last, source.length() - last));
|
|
return fields->size();
|
|
}
|
|
|
|
size_t tokenize_append(const std::string& source,
|
|
char delimiter,
|
|
std::vector<std::string>* fields) {
|
|
if (!fields)
|
|
return 0;
|
|
|
|
std::vector<std::string> new_fields;
|
|
tokenize(source, delimiter, &new_fields);
|
|
fields->insert(fields->end(), new_fields.begin(), new_fields.end());
|
|
return fields->size();
|
|
}
|
|
|
|
size_t tokenize(const std::string& source,
|
|
char delimiter,
|
|
char start_mark,
|
|
char end_mark,
|
|
std::vector<std::string>* fields) {
|
|
if (!fields)
|
|
return 0;
|
|
fields->clear();
|
|
|
|
std::string remain_source = source;
|
|
while (!remain_source.empty()) {
|
|
size_t start_pos = remain_source.find(start_mark);
|
|
if (std::string::npos == start_pos)
|
|
break;
|
|
std::string pre_mark;
|
|
if (start_pos > 0) {
|
|
pre_mark = remain_source.substr(0, start_pos - 1);
|
|
}
|
|
|
|
++start_pos;
|
|
size_t end_pos = remain_source.find(end_mark, start_pos);
|
|
if (std::string::npos == end_pos)
|
|
break;
|
|
|
|
// We have found the matching marks. First tokenize the pre-mask. Then add
|
|
// the marked part as a single field. Finally, loop back for the post-mark.
|
|
tokenize_append(pre_mark, delimiter, fields);
|
|
fields->push_back(remain_source.substr(start_pos, end_pos - start_pos));
|
|
remain_source = remain_source.substr(end_pos + 1);
|
|
}
|
|
|
|
return tokenize_append(remain_source, delimiter, fields);
|
|
}
|
|
|
|
bool tokenize_first(const std::string& source,
|
|
const char delimiter,
|
|
std::string* token,
|
|
std::string* rest) {
|
|
// Find the first delimiter
|
|
size_t left_pos = source.find(delimiter);
|
|
if (left_pos == std::string::npos) {
|
|
return false;
|
|
}
|
|
|
|
// Look for additional occurrances of delimiter.
|
|
size_t right_pos = left_pos + 1;
|
|
while (source[right_pos] == delimiter) {
|
|
right_pos++;
|
|
}
|
|
|
|
*token = source.substr(0, left_pos);
|
|
*rest = source.substr(right_pos);
|
|
return true;
|
|
}
|
|
|
|
std::string join(const std::vector<std::string>& source, char delimiter) {
|
|
if (source.size() == 0) {
|
|
return std::string();
|
|
}
|
|
// Find length of the string to be returned to pre-allocate memory.
|
|
size_t source_string_length = 0;
|
|
for (size_t i = 0; i < source.size(); ++i) {
|
|
source_string_length += source[i].length();
|
|
}
|
|
|
|
// Build the joined string.
|
|
std::string joined_string;
|
|
joined_string.reserve(source_string_length + source.size() - 1);
|
|
for (size_t i = 0; i < source.size(); ++i) {
|
|
if (i != 0) {
|
|
joined_string += delimiter;
|
|
}
|
|
joined_string += source[i];
|
|
}
|
|
return joined_string;
|
|
}
|
|
|
|
size_t split(const std::string& source,
|
|
char delimiter,
|
|
std::vector<std::string>* fields) {
|
|
RTC_DCHECK(fields);
|
|
fields->clear();
|
|
size_t last = 0;
|
|
for (size_t i = 0; i < source.length(); ++i) {
|
|
if (source[i] == delimiter) {
|
|
fields->push_back(source.substr(last, i - last));
|
|
last = i + 1;
|
|
}
|
|
}
|
|
fields->push_back(source.substr(last, source.length() - last));
|
|
return fields->size();
|
|
}
|
|
|
|
std::string ToString(const bool b) {
|
|
return b ? "true" : "false";
|
|
}
|
|
|
|
std::string ToString(const char* const s) {
|
|
return std::string(s);
|
|
}
|
|
std::string ToString(const std::string s) {
|
|
return s;
|
|
}
|
|
|
|
std::string ToString(const short s) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%hd", s);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
std::string ToString(const unsigned short s) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%hu", s);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
std::string ToString(const int s) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%d", s);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
std::string ToString(const unsigned int s) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%u", s);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
std::string ToString(const long int s) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%ld", s);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
std::string ToString(const unsigned long int s) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%lu", s);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
std::string ToString(const long long int s) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%lld", s);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
std::string ToString(const unsigned long long int s) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%llu", s);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
|
|
std::string ToString(const double d) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%g", d);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
|
|
std::string ToString(const long double d) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%Lg", d);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
|
|
std::string ToString(const void* const p) {
|
|
char buf[32];
|
|
const int len = snprintf(&buf[0], arraysize(buf), "%p", p);
|
|
RTC_DCHECK_LE(len, arraysize(buf));
|
|
return std::string(&buf[0], len);
|
|
}
|
|
|
|
bool FromString(const std::string& s, bool* b) {
|
|
if (s == "false") {
|
|
*b = false;
|
|
return true;
|
|
}
|
|
if (s == "true") {
|
|
*b = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace rtc
|