#include "ofUtils.h"
#include "ofImage.h"
#include "ofFileUtils.h"
#include "ofLog.h"
#include "ofAppBaseWindow.h"
#include "ofMainLoop.h"
#include "ofAppRunner.h"
#include "ofEvents.h"
#include "ofGLUtils.h"
#include "ofMath.h"
#include <chrono>
#include <numeric>
#include <locale>
#include <cstdarg>
#include "uriparser/Uri.h"
#ifdef TARGET_WIN32
#include <shellapi.h>
#endif
#ifdef TARGET_WIN32
#ifndef _MSC_VER
#include <unistd.h>
#include <sys/param.h>
#endif
#endif
#if defined(TARGET_OF_IOS) || defined(TARGET_OSX ) || defined(TARGET_LINUX) || defined(TARGET_EMSCRIPTEN)
#include <sys/time.h>
#endif
#ifdef TARGET_OSX
#ifndef TARGET_OF_IOS
#include <mach-o/dyld.h>
#include <sys/param.h>
#endif
#include <mach/clock.h>
#include <mach/mach.h>
#endif
#ifdef TARGET_WIN32
#include <mmsystem.h>
#ifdef _MSC_VER
#include <direct.h>
#endif
#endif
#ifdef TARGET_OF_IOS
#include "ofxiOSExtras.h"
#endif
#ifdef TARGET_ANDROID
#include "ofxAndroidUtils.h"
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
using namespace std;
namespace{
bool enableDataPath = true;
string defaultDataPath(){
#if defined TARGET_OSX
try{
return std::filesystem::canonical(ofFilePath::join(ofFilePath::getCurrentExeDir(), "../../../data/")).string();
}catch(...){
return ofFilePath::join(ofFilePath::getCurrentExeDir(), "../../../data/");
}
#elif defined TARGET_ANDROID
return string("sdcard/");
#else
try{
return std::filesystem::canonical(ofFilePath::join(ofFilePath::getCurrentExeDir(), "data/")).make_preferred().string();
}catch(...){
return ofFilePath::join(ofFilePath::getCurrentExeDir(), "data/");
}
#endif
}
std::filesystem::path & defaultWorkingDirectory(){
static auto * defaultWorkingDirectory = new std::filesystem::path();
return * defaultWorkingDirectory;
}
std::filesystem::path & dataPathRoot(){
static auto * dataPathRoot = new std::filesystem::path(defaultDataPath());
return *dataPathRoot;
}
}
namespace of{
namespace priv{
void initutils(){
defaultWorkingDirectory() = std::filesystem::absolute(std::filesystem::current_path());
ofResetElapsedTimeCounter();
ofSeedRandom();
}
void endutils(){
}
class Clock{
public:
Clock(){
#ifdef TARGET_OSX
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cs);
#endif
}
void setTimeModeSystem(){
mode = ofTime::System;
loopListener.unsubscribe();
}
void setTimeModeFixedRate(uint64_t stepNanos, ofMainLoop & mainLoop){
fixedRateTime = getMonotonicTimeForMode(ofTime::System);
mode = ofTime::FixedRate;
fixedRateStep = stepNanos;
loopListener = mainLoop.loopEvent.newListener([this]{
fixedRateTime.nanoseconds += fixedRateStep;
while(fixedRateTime.nanoseconds>1000000000){
fixedRateTime.nanoseconds -= 1000000000;
fixedRateTime.seconds += 1;
}
});
}
ofTime getCurrentTime(){
return getMonotonicTimeForMode(mode);
}
std::chrono::nanoseconds getElapsedTime(){
return getCurrentTime() - startTime;
}
void resetElapsedTimeCounter(){
startTime = getMonotonicTimeForMode(ofTime::System);
}
private:
ofTime getMonotonicTimeForMode(ofTime::Mode mode){
ofTime t;
t.mode = mode;
if(mode == ofTime::System){
#if (defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI_LEGACY)) || defined(TARGET_EMSCRIPTEN)
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
t.seconds = now.tv_sec;
t.nanoseconds = now.tv_nsec;
#elif defined(TARGET_OSX)
mach_timespec_t now;
clock_get_time(cs, &now);
t.seconds = now.tv_sec;
t.nanoseconds = now.tv_nsec;
#elif defined( TARGET_WIN32 )
LARGE_INTEGER freq;
LARGE_INTEGER counter;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&counter);
t.seconds = counter.QuadPart/freq.QuadPart;
t.nanoseconds = (counter.QuadPart % freq.QuadPart)*1000000000/freq.QuadPart;
#else
struct timeval now;
gettimeofday( &now, nullptr );
t.seconds = now.tv_sec;
t.nanoseconds = now.tv_usec * 1000;
#endif
}else{
t = fixedRateTime;
}
return t;
}
uint64_t fixedRateStep = 1666667;
ofTime fixedRateTime;
ofTime startTime;
ofTime::Mode mode = ofTime::System;
ofEventListener loopListener;
#ifdef TARGET_OSX
clock_serv_t cs;
#endif
};
Clock & getClock(){
static Clock * clock = new Clock;
return *clock;
}
}
}
uint64_t ofTime::getAsMilliseconds() const{
auto seconds = std::chrono::seconds(this->seconds);
auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds);
return (std::chrono::duration_cast<std::chrono::milliseconds>(seconds) +
std::chrono::duration_cast<std::chrono::milliseconds>(nanoseconds)).count();
}
uint64_t ofTime::getAsMicroseconds() const{
auto seconds = std::chrono::seconds(this->seconds);
auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds);
return (std::chrono::duration_cast<std::chrono::microseconds>(seconds) +
std::chrono::duration_cast<std::chrono::microseconds>(nanoseconds)).count();
}
uint64_t ofTime::getAsNanoseconds() const{
auto seconds = std::chrono::seconds(this->seconds);
auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds);
return (std::chrono::duration_cast<std::chrono::nanoseconds>(seconds) + nanoseconds).count();
}
double ofTime::getAsSeconds() const{
return seconds + nanoseconds / 1000000000.;
}
#ifndef TARGET_WIN32
timespec ofTime::getAsTimespec() const{
timespec ret;
ret.tv_sec = seconds;
ret.tv_nsec = nanoseconds;
return ret;
}
#endif
std::chrono::time_point<std::chrono::nanoseconds> ofTime::getAsTimePoint() const{
auto seconds = std::chrono::seconds(this->seconds);
auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds);
return std::chrono::time_point<std::chrono::nanoseconds>(
std::chrono::duration_cast<std::chrono::nanoseconds>(seconds) + nanoseconds);
}
std::chrono::nanoseconds ofTime::operator-(const ofTime& other) const{
auto seconds = std::chrono::seconds(this->seconds) - std::chrono::seconds(other.seconds);
auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds) - std::chrono::nanoseconds(other.nanoseconds);
return std::chrono::duration_cast<std::chrono::nanoseconds>(seconds) + nanoseconds;
}
bool ofTime::operator<(const ofTime & other) const{
return seconds < other.seconds || (seconds == other.seconds && nanoseconds < other.nanoseconds);
}
bool ofTime::operator>(const ofTime & other) const{
return seconds > other.seconds || (seconds == other.seconds && nanoseconds > other.nanoseconds);
}
bool ofTime::operator<=(const ofTime & other) const{
return seconds <= other.seconds || (seconds == other.seconds && nanoseconds <= other.nanoseconds);
}
bool ofTime::operator>=(const ofTime & other) const{
return seconds >= other.seconds || (seconds == other.seconds && nanoseconds >= other.nanoseconds);
}
uint64_t ofGetFixedStepForFps(double fps){
return 1000000000 / fps;
}
void ofSetTimeModeSystem(){
auto mainLoop = ofGetMainLoop();
if(!mainLoop){
ofLogError("ofSetSystemTimeMode") << "ofMainLoop is not initialized yet, can't set time mode";
return;
}
auto window = mainLoop->getCurrentWindow();
if(!window){
ofLogError("ofSetSystemTimeMode") << "No window setup yet can't set time mode";
return;
}
window->events().setTimeModeSystem();
of::priv::getClock().setTimeModeSystem();
}
void ofSetTimeModeFixedRate(uint64_t stepNanos){
auto mainLoop = ofGetMainLoop();
if(!mainLoop){
ofLogError("ofSetSystemTimeMode") << "ofMainLoop is not initialized yet, can't set time mode";
return;
}
auto window = mainLoop->getCurrentWindow();
if(!window){
ofLogError("ofSetSystemTimeMode") << "No window setup yet can't set time mode";
return;
}
window->events().setTimeModeFixedRate(stepNanos);
of::priv::getClock().setTimeModeFixedRate(stepNanos, *mainLoop);
}
void ofSetTimeModeFiltered(float alpha){
auto mainLoop = ofGetMainLoop();
if(!mainLoop){
ofLogError("ofSetSystemTimeMode") << "ofMainLoop is not initialized yet, can't set time mode";
return;
}
auto window = mainLoop->getCurrentWindow();
if(!window){
ofLogError("ofSetSystemTimeMode") << "No window setup yet can't set time mode";
return;
}
window->events().setTimeModeFiltered(alpha);
of::priv::getClock().setTimeModeSystem();
}
ofTime ofGetCurrentTime(){
return of::priv::getClock().getCurrentTime();
}
uint64_t ofGetElapsedTimeMillis(){
return std::chrono::duration_cast<std::chrono::milliseconds>(of::priv::getClock().getElapsedTime()).count();
}
uint64_t ofGetElapsedTimeMicros(){
return std::chrono::duration_cast<std::chrono::microseconds>(of::priv::getClock().getElapsedTime()).count();
}
float ofGetElapsedTimef(){
return std::chrono::duration<double>(of::priv::getClock().getElapsedTime()).count();
}
void ofResetElapsedTimeCounter(){
of::priv::getClock().resetElapsedTimeCounter();
}
uint64_t ofGetSystemTime( ) {
return of::priv::getClock().getCurrentTime().getAsMilliseconds();
}
uint64_t ofGetSystemTimeMillis( ) {
return of::priv::getClock().getCurrentTime().getAsMilliseconds();
}
uint64_t ofGetSystemTimeMicros( ) {
return of::priv::getClock().getCurrentTime().getAsMicroseconds();
}
unsigned int ofGetUnixTime(){
return (unsigned int)time(nullptr);
}
void ofSleepMillis(int millis){
#ifdef TARGET_WIN32
Sleep(millis);
#elif defined(TARGET_LINUX)
timespec interval = {millis/1000, millis%1000*1000000};
timespec rem = {0,0};
clock_nanosleep(CLOCK_MONOTONIC,0,&interval,&rem);
#elif !defined(TARGET_EMSCRIPTEN)
usleep(millis * 1000);
#endif
}
string ofGetTimestampString(){
string timeFormat = "%Y-%m-%d-%H-%M-%S-%i";
return ofGetTimestampString(timeFormat);
}
string ofGetTimestampString(const string& timestampFormat){
std::stringstream str;
auto now = std::chrono::system_clock::now();
auto t = std::chrono::system_clock::to_time_t(now); std::chrono::duration<double> s = now - std::chrono::system_clock::from_time_t(t);
int ms = s.count() * 1000;
auto tm = *std::localtime(&t);
constexpr int bufsize = 256;
char buf[bufsize];
auto tmpTimestampFormat = timestampFormat;
ofStringReplace(tmpTimestampFormat, "%i", ofToString(ms, 3, '0'));
if (strftime(buf,bufsize, tmpTimestampFormat.c_str(),&tm) != 0){
str << buf;
}
auto ret = str.str();
return ret;
}
int ofGetSeconds(){
time_t curr;
tm local;
time(&curr);
local =*(localtime(&curr));
return local.tm_sec;
}
int ofGetMinutes(){
time_t curr;
tm local;
time(&curr);
local =*(localtime(&curr));
return local.tm_min;
}
int ofGetHours(){
time_t curr;
tm local;
time(&curr);
local =*(localtime(&curr));
return local.tm_hour;
}
int ofGetYear(){
time_t curr;
tm local;
time(&curr);
local =*(localtime(&curr));
int year = local.tm_year + 1900;
return year;
}
int ofGetMonth(){
time_t curr;
tm local;
time(&curr);
local =*(localtime(&curr));
int month = local.tm_mon + 1;
return month;
}
int ofGetDay(){
time_t curr;
tm local;
time(&curr);
local =*(localtime(&curr));
return local.tm_mday;
}
int ofGetWeekday(){
time_t curr;
tm local;
time(&curr);
local =*(localtime(&curr));
return local.tm_wday;
}
void ofEnableDataPath(){
enableDataPath = true;
}
void ofDisableDataPath(){
enableDataPath = false;
}
bool ofRestoreWorkingDirectoryToDefault(){
try{
std::filesystem::current_path(defaultWorkingDirectory());
return true;
}catch(...){
return false;
}
}
void ofSetDataPathRoot(const std::filesystem::path& newRoot){
dataPathRoot() = newRoot;
}
string ofToDataPath(const std::filesystem::path & path, bool makeAbsolute){
if (makeAbsolute && path.is_absolute())
return path.string();
if (!enableDataPath)
return path.string();
bool hasTrailingSlash = !path.empty() && path.generic_string().back()=='/';
#ifdef TARGET_WIN32
if (defaultWorkingDirectory() != std::filesystem::current_path()) {
bool ret = ofRestoreWorkingDirectoryToDefault();
if(!ret){
ofLogWarning("ofUtils") << "ofToDataPath: error while trying to change back to default working directory " << defaultWorkingDirectory();
}
}
#endif
const auto & dataPath = dataPathRoot();
std::filesystem::path inputPath(path);
std::filesystem::path outputPath;
if (inputPath.is_absolute()) {
try {
auto outpath = std::filesystem::canonical(inputPath).make_preferred();
if(std::filesystem::is_directory(outpath) && hasTrailingSlash){
return ofFilePath::addTrailingSlash(outpath.string());
}else{
return outpath.string();
}
}
catch (...) {
return inputPath.string();
}
}
auto dirDataPath = dataPath.string();
dirDataPath = ofFilePath::addTrailingSlash(dirDataPath);
auto relativeDirDataPath = ofFilePath::makeRelative(std::filesystem::current_path().string(),dataPath.string());
relativeDirDataPath = ofFilePath::addTrailingSlash(relativeDirDataPath);
if (inputPath.string().find(dirDataPath) != 0 && inputPath.string().find(relativeDirDataPath)!=0) {
if(makeAbsolute){
outputPath = dirDataPath / inputPath;
}else{
outputPath = relativeDirDataPath / inputPath;
}
} else {
outputPath = inputPath;
}
if(makeAbsolute){
try {
auto outpath = std::filesystem::canonical(std::filesystem::absolute(outputPath)).make_preferred();
if(std::filesystem::is_directory(outpath) && hasTrailingSlash){
return ofFilePath::addTrailingSlash(outpath.string());
}else{
return outpath.string();
}
}
catch (std::exception &) {
return std::filesystem::absolute(outputPath).string();
}
}else{
return outputPath.string();
}
}
template<>
string ofFromString(const string& value){
return value;
}
template<>
const char * ofFromString(const string& value){
return value.c_str();
}
template <>
string ofToHex(const string& value) {
ostringstream out;
std::size_t numBytes = value.size();
for(std::size_t i = 0; i < numBytes; i++) {
out << setfill('0') << std::setw(2) << std::hex << (unsigned int) ((unsigned char)value[i]);
}
return out.str();
}
string ofToHex(const char* value) {
return ofToHex((string) value);
}
int ofToInt(const string& intString) {
return ofTo<int>(intString);
}
int ofHexToInt(const string& intHexString) {
int x = 0;
istringstream cur(intHexString);
cur >> std::hex >> x;
return x;
}
char ofHexToChar(const string& charHexString) {
int x = 0;
istringstream cur(charHexString);
cur >> std::hex >> x;
return (char) x;
}
float ofHexToFloat(const string& floatHexString) {
union intFloatUnion {
uint32_t i;
float f;
} myUnion;
myUnion.i = 0;
istringstream cur(floatHexString);
cur >> std::hex >> myUnion.i;
return myUnion.f;
}
string ofHexToString(const string& stringHexString) {
stringstream out;
stringstream stream(stringHexString);
std::size_t numBytes = stringHexString.size() / 2;
for(std::size_t i = 0; i < numBytes; i++) {
string curByte;
stream >> setw(2) >> curByte;
stringstream curByteStream(curByte);
int cur = 0;
curByteStream >> std::hex >> cur;
out << (char) cur;
}
return out.str();
}
float ofToFloat(const string& floatString) {
return ofTo<float>(floatString);
}
double ofToDouble(const string& doubleString) {
return ofTo<double>(doubleString);
}
int64_t ofToInt64(const string& intString) {
return ofTo<int64_t>(intString);
}
bool ofToBool(const string& boolString) {
auto lower = ofToLower(boolString);
if(lower == "true") {
return true;
}
if(lower == "false") {
return false;
}
bool x = false;
istringstream cur(lower);
cur >> x;
return x;
}
char ofToChar(const string& charString) {
return ofTo<char>(charString);
}
template <> string ofToBinary(const string& value) {
stringstream out;
std::size_t numBytes = value.size();
for(std::size_t i = 0; i < numBytes; i++) {
std::bitset<8> bitBuffer(value[i]);
out << bitBuffer;
}
return out.str();
}
string ofToBinary(const char* value) {
return ofToBinary((string) value);
}
int ofBinaryToInt(const string& value) {
const int intSize = sizeof(int) * 8;
std::bitset<intSize> binaryString(value);
return (int) binaryString.to_ulong();
}
char ofBinaryToChar(const string& value) {
const int charSize = sizeof(char) * 8;
std::bitset<charSize> binaryString(value);
return (char) binaryString.to_ulong();
}
float ofBinaryToFloat(const string& value) {
const int floatSize = sizeof(float) * 8;
std::bitset<floatSize> binaryString(value);
union ulongFloatUnion {
unsigned long result;
float f;
} myUFUnion;
myUFUnion.result = binaryString.to_ulong();
return myUFUnion.f;
}
string ofBinaryToString(const string& value) {
ostringstream out;
stringstream stream(value);
std::bitset<8> byteString;
std::size_t numBytes = value.size() / 8;
for(std::size_t i = 0; i < numBytes; i++) {
stream >> byteString;
out << (char) byteString.to_ulong();
}
return out.str();
}
vector <string> ofSplitString(const string & source, const string & delimiter, bool ignoreEmpty, bool trim) {
vector<string> result;
if (delimiter.empty()) {
result.push_back(source);
return result;
}
string::const_iterator substart = source.begin(), subend;
while (true) {
subend = search(substart, source.end(), delimiter.begin(), delimiter.end());
string sub(substart, subend);
if(trim) {
sub = ofTrim(sub);
}
if (!ignoreEmpty || !sub.empty()) {
result.push_back(sub);
}
if (subend == source.end()) {
break;
}
substart = subend + delimiter.size();
}
return result;
}
string ofJoinString(const vector<string>& stringElements, const string& delimiter){
string str;
if(stringElements.empty()){
return str;
}
auto numStrings = stringElements.size();
string::size_type strSize = delimiter.size() * (numStrings - 1);
for (const string &s : stringElements) {
strSize += s.size();
}
str.reserve(strSize);
str += stringElements[0];
for (decltype(numStrings) i = 1; i < numStrings; ++i) {
str += delimiter;
str += stringElements[i];
}
return str;
}
void ofStringReplace(string& input, const string& searchStr, const string& replaceStr){
auto pos = input.find(searchStr);
while(pos != std::string::npos){
input.replace(pos, searchStr.size(), replaceStr);
pos += replaceStr.size();
std::string nextfind(input.begin() + pos, input.end());
auto nextpos = nextfind.find(searchStr);
if(nextpos==std::string::npos){
break;
}
pos += nextpos;
}
}
bool ofIsStringInString(const string& haystack, const string& needle){
return haystack.find(needle) != std::string::npos;
}
std::size_t ofStringTimesInString(const string& haystack, const string& needle){
const size_t step = needle.size();
size_t count(0);
size_t pos(0) ;
while( (pos=haystack.find(needle, pos)) != std::string::npos) {
pos +=step;
++count ;
}
return count;
}
ofUTF8Iterator::ofUTF8Iterator(const string & str){
try{
utf8::replace_invalid(str.begin(),str.end(),back_inserter(src_valid));
}catch(...){
}
}
utf8::iterator<std::string::const_iterator> ofUTF8Iterator::begin() const{
try {
return utf8::iterator<std::string::const_iterator>(src_valid.begin(), src_valid.begin(), src_valid.end());
}
catch (...) {
return utf8::iterator<std::string::const_iterator>();
}
}
utf8::iterator<std::string::const_iterator> ofUTF8Iterator::end() const{
try {
return utf8::iterator<std::string::const_iterator>(src_valid.end(), src_valid.begin(), src_valid.end());
}
catch (...) {
return utf8::iterator<std::string::const_iterator>();
}
}
utf8::iterator<std::string::const_reverse_iterator> ofUTF8Iterator::rbegin() const {
try {
return utf8::iterator<std::string::const_reverse_iterator>(src_valid.rbegin(), src_valid.rbegin(), src_valid.rend());
}
catch (...) {
return utf8::iterator<std::string::const_reverse_iterator>();
}
}
utf8::iterator<std::string::const_reverse_iterator> ofUTF8Iterator::rend() const {
try {
return utf8::iterator<std::string::const_reverse_iterator>(src_valid.rbegin(), src_valid.rbegin(), src_valid.rend());
}
catch (...) {
return utf8::iterator<std::string::const_reverse_iterator>();
}
}
static std::locale getLocale(const string & locale) {
std::locale loc;
#if defined(TARGET_WIN32) && !_MSC_VER
static bool printonce = true;
if( printonce ){
std::string current( setlocale(LC_ALL,NULL) );
setlocale (LC_ALL,"");
ofLogWarning("ofUtils") << "std::locale not supported. Using C locale :" << current ;
printonce = false;
}
#else
try {
loc = std::locale(locale.c_str());
}
catch (...) {
ofLogWarning("ofUtils") << "Couldn't create locale " << locale << " using default, " << loc.name();
}
#endif
return loc;
}
string ofToLower(const string & src, const string & locale){
std::string dst;
std::locale loc = getLocale(locale);
try{
for(auto c: ofUTF8Iterator(src)){
utf8::append(std::tolower<wchar_t>(c, loc), back_inserter(dst));
}
}catch(...){
}
return dst;
}
string ofToUpper(const string & src, const string & locale){
std::string dst;
std::locale loc = getLocale(locale);
try{
for(auto c: ofUTF8Iterator(src)){
utf8::append(std::toupper<wchar_t>(c, loc), back_inserter(dst));
}
}catch(...){
}
return dst;
}
string ofTrimFront(const string & src, const string& locale){
auto dst = src;
std::locale loc = getLocale(locale);
dst.erase(dst.begin(),std::find_if_not(dst.begin(),dst.end(),[&](char & c){return std::isspace<char>(c,loc);}));
return dst;
}
string ofTrimBack(const string & src, const string& locale){
auto dst = src;
std::locale loc = getLocale(locale);
dst.erase(std::find_if_not(dst.rbegin(),dst.rend(),[&](char & c){return std::isspace<char>(c,loc);}).base(), dst.end());
return dst;
}
string ofTrim(const string & src, const string& locale){
return ofTrimFront(ofTrimBack(src));
}
void ofAppendUTF8(string & str, uint32_t utf8){
try{
utf8::append(utf8, back_inserter(str));
}catch(...){}
}
void ofUTF8Append(string & str, uint32_t utf8){
try{
utf8::append(utf8, back_inserter(str));
}catch(...){}
}
void ofUTF8Insert(string & str, size_t pos, uint32_t utf8){
std::string newText;
size_t i = 0;
for(auto c: ofUTF8Iterator(str)){
if(i==pos){
ofUTF8Append(newText, utf8);
}
ofUTF8Append(newText, c);
i+=1;
}
if(i==pos){
ofUTF8Append(newText, utf8);
}
str = newText;
}
void ofUTF8Erase(string & str, size_t start, size_t len){
std::string newText;
size_t i = 0;
for(auto c: ofUTF8Iterator(str)){
if(i<start || i>=start + len){
ofUTF8Append(newText, c);
}
i+=1;
}
str = newText;
}
std::string ofUTF8Substring(const string & str, size_t start, size_t len){
size_t i=0;
std::string newText;
for(auto c: ofUTF8Iterator(str)){
if(i>=start){
ofUTF8Append(newText, c);
}
i += 1;
if(i==start + len){
break;
}
}
return newText;
}
std::string ofUTF8ToString(uint32_t utf8){
std::string str;
ofUTF8Append(str, utf8);
return str;
}
size_t ofUTF8Length(const std::string & str){
try{
return utf8::distance(str.begin(), str.end());
}catch(...){
return 0;
}
}
string ofVAArgsToString(const char * format, ...){
va_list args;
va_start(args, format);
char buf[256];
size_t n = std::vsnprintf(buf, sizeof(buf), format, args);
va_end(args);
if (n < sizeof(buf)) {
return{ buf, n };
}
std::string s(n + 1, 0);
va_start(args, format);
std::vsnprintf(const_cast<char*>(s.data()), s.size(), format, args);
va_end(args);
return s;
}
string ofVAArgsToString(const char * format, va_list args){
char buf[256];
size_t n = std::vsnprintf(buf, sizeof(buf), format, args);
if (n < sizeof(buf)) {
return{ buf, n };
}
std::string s(n + 1, 0);
std::vsnprintf(const_cast<char*>(s.data()), s.size(), format, args);
return s;
}
void ofLaunchBrowser(const string& url, bool uriEncodeQuery){
UriParserStateA state;
UriUriA uri;
state.uri = &uri;
if(uriParseUriA(&state, url.c_str())!=URI_SUCCESS){
ofLogError("ofUtils") << "ofLaunchBrowser(): malformed url \"" << url << "\"";
uriFreeUriMembersA(&uri);
return;
}
if(uriEncodeQuery) {
uriNormalizeSyntaxA(&uri);
}
std::string scheme(uri.scheme.first, uri.scheme.afterLast);
int size;
uriToStringCharsRequiredA(&uri, &size);
std::vector<char> buffer(size+1, 0);
int written;
uriToStringA(buffer.data(), &uri, url.size()*2, &written);
std::string uriStr(buffer.data(), written-1);
uriFreeUriMembersA(&uri);
if(scheme != "http" && scheme != "https"){
ofLogError("ofUtils") << "ofLaunchBrowser(): url does not begin with http:// or https://: \"" << uriStr << "\"";
return;
}
#ifdef TARGET_WIN32
ShellExecuteA(nullptr, "open", uriStr.c_str(),
nullptr, nullptr, SW_SHOWNORMAL);
#endif
#ifdef TARGET_OSX
string commandStr = "open \"" + uriStr + "\"";
int ret = system(commandStr.c_str());
if(ret!=0) {
ofLogError("ofUtils") << "ofLaunchBrowser(): couldn't open browser, commandStr \"" << commandStr << "\"";
}
#endif
#ifdef TARGET_LINUX
string commandStr = "xdg-open \"" + uriStr + "\"";
int ret = system(commandStr.c_str());
if(ret!=0) {
ofLogError("ofUtils") << "ofLaunchBrowser(): couldn't open browser, commandStr \"" << commandStr << "\"";
}
#endif
#ifdef TARGET_OF_IOS
ofxiOSLaunchBrowser(uriStr);
#endif
#ifdef TARGET_ANDROID
ofxAndroidLaunchBrowser(uriStr);
#endif
#ifdef TARGET_EMSCRIPTEN
ofLogError("ofUtils") << "ofLaunchBrowser() not implementeed in emscripten";
#endif
}
string ofGetVersionInfo(){
stringstream sstr;
sstr << OF_VERSION_MAJOR << "." << OF_VERSION_MINOR << "." << OF_VERSION_PATCH;
if (!std::string(OF_VERSION_PRE_RELEASE).empty())
{
sstr << "-" << OF_VERSION_PRE_RELEASE;
}
return sstr.str();
}
unsigned int ofGetVersionMajor() {
return OF_VERSION_MAJOR;
}
unsigned int ofGetVersionMinor() {
return OF_VERSION_MINOR;
}
unsigned int ofGetVersionPatch() {
return OF_VERSION_PATCH;
}
std::string ofGetVersionPreRelease() {
return OF_VERSION_PRE_RELEASE;
}
void ofSaveScreen(const string& filename) {
ofPixels pixels;
ofGetGLRenderer()->saveFullViewport(pixels);
ofSaveImage(pixels,filename);
}
void ofSaveViewport(const string& filename) {
ofPixels pixels;
ofGetGLRenderer()->saveFullViewport(pixels);
ofSaveImage(pixels,filename);
}
int saveImageCounter = 0;
void ofSaveFrame(bool bUseViewport){
string fileName = ofToString(saveImageCounter) + ".png";
if (bUseViewport){
ofSaveViewport(fileName);
} else {
ofSaveScreen(fileName);
}
saveImageCounter++;
}
string ofSystem(const string& command){
FILE * ret = nullptr;
#ifdef TARGET_WIN32
ret = _popen(command.c_str(),"r");
#else
ret = popen(command.c_str(),"r");
#endif
string strret;
int c;
if (ret == nullptr){
ofLogError("ofUtils") << "ofSystem(): error opening return file for command \"" << command << "\"";
}else{
c = fgetc (ret);
while (c != EOF) {
strret += c;
c = fgetc (ret);
}
#ifdef TARGET_WIN32
_pclose (ret);
#else
pclose (ret);
#endif
}
return strret;
}
ofTargetPlatform ofGetTargetPlatform(){
#ifdef TARGET_LINUX
string arch = ofSystem("uname -m");
if(ofIsStringInString(arch,"x86_64")) {
return OF_TARGET_LINUX64;
} else if(ofIsStringInString(arch,"armv6l")) {
return OF_TARGET_LINUXARMV6L;
} else if(ofIsStringInString(arch,"armv7l")) {
return OF_TARGET_LINUXARMV7L;
} else {
return OF_TARGET_LINUX;
}
#elif defined(TARGET_OSX)
return OF_TARGET_OSX;
#elif defined(TARGET_WIN32)
#if (_MSC_VER)
return OF_TARGET_WINVS;
#else
return OF_TARGET_MINGW;
#endif
#elif defined(TARGET_ANDROID)
return OF_TARGET_ANDROID;
#elif defined(TARGET_OF_IOS)
return OF_TARGET_IOS;
#elif defined(TARGET_EMSCRIPTEN)
return OF_TARGET_EMSCRIPTEN;
#endif
}
std::string ofGetEnv(const std::string & var){
#ifdef TARGET_WIN32
const size_t BUFSIZE = 4096;
std::vector<char> pszOldVal(BUFSIZE, 0);
auto size = GetEnvironmentVariableA(var.c_str(), pszOldVal.data(), BUFSIZE);
if(size>0){
return std::string(pszOldVal.begin(), pszOldVal.begin()+size);
}else{
return "";
}
#else
auto value = getenv(var.c_str());
if(value){
return value;
}else{
return "";
}
#endif
}
Comments