framework2
1123 строки · 29.6 Кб
1#include "ofUtils.h"
2// FIXME: split ofUtils in two files, one which uses urlparser / ofImage, other without for smaller apps.
3#include "ofImage.h"
4#include "ofLog.h"
5#include "ofAppBaseWindow.h"
6#include "ofMainLoop.h"
7#include "ofAppRunner.h"
8#include "ofEvents.h"
9#include "ofGLUtils.h"
10#include "ofMath.h"
11#include "ofPixels.h"
12
13#include <chrono>
14#include <numeric>
15#include <locale>
16#include "uriparser/Uri.h"
17
18#ifdef TARGET_WIN32 // For ofLaunchBrowser.
19#include <shellapi.h>
20#ifndef _MSC_VER
21#include <unistd.h> // this if for MINGW / _getcwd
22#include <sys/param.h> // for MAXPATHLEN
23// FIXME: else
24#endif
25#ifdef _MSC_VER
26#include <direct.h>
27#endif
28#include <mmsystem.h>
29#endif
30
31#if defined(TARGET_OF_IOS) || defined(TARGET_OSX ) || defined(TARGET_LINUX) || defined(TARGET_EMSCRIPTEN)
32#include <sys/time.h>
33#endif
34
35#ifdef TARGET_OSX
36#ifndef TARGET_OF_IOS
37#include <mach-o/dyld.h>
38#include <sys/param.h> // for MAXPATHLEN
39#endif
40#include <mach/clock.h>
41#include <mach/mach.h>
42#endif
43
44#ifdef TARGET_OF_IOS
45#include "ofxiOSExtras.h"
46#endif
47
48#ifdef TARGET_ANDROID
49#include "ofxAndroidUtils.h"
50#endif
51
52#ifndef MAXPATHLEN
53#define MAXPATHLEN 1024
54#endif
55
56using std::vector;
57using std::string;
58using std::setfill;
59
60namespace of{
61namespace priv{
62void initutils(){
63ofResetElapsedTimeCounter();
64of::random::Engine::construct();
65}
66
67void endutils(){
68//#ifdef TARGET_OSX
69// mach_port_deallocate(mach_task_self(), cs);
70//#endif
71}
72
73class Clock{
74public:
75Clock(){
76#ifdef TARGET_OSX
77host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cs);
78#endif
79}
80
81//--------------------------------------
82void setTimeModeSystem(){
83mode = ofTime::System;
84loopListener.unsubscribe();
85}
86
87//--------------------------------------
88void setTimeModeFixedRate(uint64_t stepNanos, ofMainLoop & mainLoop){
89fixedRateTime = getMonotonicTimeForMode(ofTime::System);
90mode = ofTime::FixedRate;
91fixedRateStep = stepNanos;
92loopListener = mainLoop.loopEvent.newListener([this]{
93fixedRateTime.nanoseconds += fixedRateStep;
94while(fixedRateTime.nanoseconds>1000000000){
95fixedRateTime.nanoseconds -= 1000000000;
96fixedRateTime.seconds += 1;
97}
98});
99}
100
101//--------------------------------------
102ofTime getCurrentTime(){
103return getMonotonicTimeForMode(mode);
104}
105
106//--------------------------------------
107std::chrono::nanoseconds getElapsedTime(){
108return getCurrentTime() - startTime;
109}
110
111//--------------------------------------
112void resetElapsedTimeCounter(){
113startTime = getMonotonicTimeForMode(ofTime::System);
114}
115
116private:
117
118//--------------------------------------
119ofTime getMonotonicTimeForMode(ofTime::Mode mode){
120ofTime t;
121t.mode = mode;
122if(mode == ofTime::System){
123#if (defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI_LEGACY)) || defined(TARGET_EMSCRIPTEN)
124struct timespec now;
125clock_gettime(CLOCK_MONOTONIC, &now);
126t.seconds = now.tv_sec;
127t.nanoseconds = now.tv_nsec;
128#elif defined(TARGET_OSX)
129mach_timespec_t now;
130clock_get_time(cs, &now);
131t.seconds = now.tv_sec;
132t.nanoseconds = now.tv_nsec;
133#elif defined( TARGET_WIN32 )
134LARGE_INTEGER freq;
135LARGE_INTEGER counter;
136QueryPerformanceFrequency(&freq);
137QueryPerformanceCounter(&counter);
138t.seconds = counter.QuadPart/freq.QuadPart;
139t.nanoseconds = (counter.QuadPart % freq.QuadPart)*1000000000/freq.QuadPart;
140#else
141struct timeval now;
142gettimeofday( &now, nullptr );
143t.seconds = now.tv_sec;
144t.nanoseconds = now.tv_usec * 1000;
145#endif
146}else{
147t = fixedRateTime;
148}
149return t;
150}
151uint64_t fixedRateStep = 1666667;
152ofTime fixedRateTime;
153ofTime startTime;
154ofTime::Mode mode = ofTime::System;
155ofEventListener loopListener;
156#ifdef TARGET_OSX
157clock_serv_t cs;
158#endif
159};
160
161Clock & getClock(){
162static Clock * clock = new Clock;
163return *clock;
164}
165}
166}
167
168
169//--------------------------------------
170uint64_t ofTime::getAsMilliseconds() const{
171auto seconds = std::chrono::seconds(this->seconds);
172auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds);
173return (std::chrono::duration_cast<std::chrono::milliseconds>(seconds) +
174std::chrono::duration_cast<std::chrono::milliseconds>(nanoseconds)).count();
175}
176
177//--------------------------------------
178uint64_t ofTime::getAsMicroseconds() const{
179auto seconds = std::chrono::seconds(this->seconds);
180auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds);
181return (std::chrono::duration_cast<std::chrono::microseconds>(seconds) +
182std::chrono::duration_cast<std::chrono::microseconds>(nanoseconds)).count();
183}
184
185//--------------------------------------
186uint64_t ofTime::getAsNanoseconds() const{
187auto seconds = std::chrono::seconds(this->seconds);
188auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds);
189return (std::chrono::duration_cast<std::chrono::nanoseconds>(seconds) + nanoseconds).count();
190}
191
192//--------------------------------------
193double ofTime::getAsSeconds() const{
194return seconds + nanoseconds / 1000000000.;
195}
196
197#ifndef TARGET_WIN32
198timespec ofTime::getAsTimespec() const{
199timespec ret;
200ret.tv_sec = seconds;
201ret.tv_nsec = nanoseconds;
202return ret;
203}
204#endif
205
206//--------------------------------------
207std::chrono::time_point<std::chrono::nanoseconds> ofTime::getAsTimePoint() const{
208auto seconds = std::chrono::seconds(this->seconds);
209auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds);
210return std::chrono::time_point<std::chrono::nanoseconds>(
211std::chrono::duration_cast<std::chrono::nanoseconds>(seconds) + nanoseconds);
212}
213
214//--------------------------------------
215std::chrono::nanoseconds ofTime::operator-(const ofTime& other) const{
216auto seconds = std::chrono::seconds(this->seconds) - std::chrono::seconds(other.seconds);
217auto nanoseconds = std::chrono::nanoseconds(this->nanoseconds) - std::chrono::nanoseconds(other.nanoseconds);
218return std::chrono::duration_cast<std::chrono::nanoseconds>(seconds) + nanoseconds;
219}
220
221//--------------------------------------
222bool ofTime::operator<(const ofTime & other) const{
223return seconds < other.seconds || (seconds == other.seconds && nanoseconds < other.nanoseconds);
224}
225
226//--------------------------------------
227bool ofTime::operator>(const ofTime & other) const{
228return seconds > other.seconds || (seconds == other.seconds && nanoseconds > other.nanoseconds);
229}
230
231//--------------------------------------
232bool ofTime::operator<=(const ofTime & other) const{
233return seconds <= other.seconds || (seconds == other.seconds && nanoseconds <= other.nanoseconds);
234}
235
236//--------------------------------------
237bool ofTime::operator>=(const ofTime & other) const{
238return seconds >= other.seconds || (seconds == other.seconds && nanoseconds >= other.nanoseconds);
239}
240
241//--------------------------------------
242uint64_t ofGetFixedStepForFps(double fps){
243return 1000000000 / fps;
244}
245
246//--------------------------------------
247void ofSetTimeModeSystem(){
248auto mainLoop = ofGetMainLoop();
249if(!mainLoop){
250ofLogError("ofSetSystemTimeMode") << "ofMainLoop is not initialized yet, can't set time mode";
251return;
252}
253auto window = mainLoop->getCurrentWindow();
254if(!window){
255ofLogError("ofSetSystemTimeMode") << "No window setup yet can't set time mode";
256return;
257}
258window->events().setTimeModeSystem();
259of::priv::getClock().setTimeModeSystem();
260}
261
262//--------------------------------------
263void ofSetTimeModeFixedRate(uint64_t stepNanos){
264auto mainLoop = ofGetMainLoop();
265if(!mainLoop){
266ofLogError("ofSetSystemTimeMode") << "ofMainLoop is not initialized yet, can't set time mode";
267return;
268}
269auto window = mainLoop->getCurrentWindow();
270if(!window){
271ofLogError("ofSetSystemTimeMode") << "No window setup yet can't set time mode";
272return;
273}
274window->events().setTimeModeFixedRate(stepNanos);
275of::priv::getClock().setTimeModeFixedRate(stepNanos, *mainLoop);
276}
277
278//--------------------------------------
279void ofSetTimeModeFiltered(float alpha){
280auto mainLoop = ofGetMainLoop();
281if(!mainLoop){
282ofLogError("ofSetSystemTimeMode") << "ofMainLoop is not initialized yet, can't set time mode";
283return;
284}
285auto window = mainLoop->getCurrentWindow();
286if(!window){
287ofLogError("ofSetSystemTimeMode") << "No window setup yet can't set time mode";
288return;
289}
290window->events().setTimeModeFiltered(alpha);
291of::priv::getClock().setTimeModeSystem();
292}
293
294//--------------------------------------
295ofTime ofGetCurrentTime(){
296return of::priv::getClock().getCurrentTime();
297}
298
299
300//--------------------------------------
301uint64_t ofGetElapsedTimeMillis(){
302return std::chrono::duration_cast<std::chrono::milliseconds>(of::priv::getClock().getElapsedTime()).count();
303}
304
305//--------------------------------------
306uint64_t ofGetElapsedTimeMicros(){
307return std::chrono::duration_cast<std::chrono::microseconds>(of::priv::getClock().getElapsedTime()).count();
308}
309
310//--------------------------------------
311float ofGetElapsedTimef(){
312return std::chrono::duration<double>(of::priv::getClock().getElapsedTime()).count();
313}
314
315//--------------------------------------
316void ofResetElapsedTimeCounter(){
317of::priv::getClock().resetElapsedTimeCounter();
318}
319
320//--------------------------------------
321uint64_t ofGetSystemTime( ) {
322return of::priv::getClock().getCurrentTime().getAsMilliseconds();
323}
324
325//--------------------------------------
326uint64_t ofGetSystemTimeMillis( ) {
327return of::priv::getClock().getCurrentTime().getAsMilliseconds();
328}
329
330//--------------------------------------
331uint64_t ofGetSystemTimeMicros( ) {
332return of::priv::getClock().getCurrentTime().getAsMicroseconds();
333}
334
335//--------------------------------------------------
336uint64_t ofGetUnixTime(){
337return static_cast<uint64_t>(time(nullptr));
338}
339
340uint64_t ofGetUnixTimeMillis() {
341auto elapsed = std::chrono::system_clock::now().time_since_epoch();
342return std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
343}
344
345//--------------------------------------
346void ofSleepMillis(int millis){
347#ifdef TARGET_WIN32
348Sleep(millis);
349#elif defined(TARGET_LINUX)
350timespec interval = {millis/1000, millis%1000*1000000};
351timespec rem = {0,0};
352clock_nanosleep(CLOCK_MONOTONIC,0,&interval,&rem);
353#elif !defined(TARGET_EMSCRIPTEN)
354usleep(millis * 1000);
355#endif
356}
357
358//default ofGetTimestampString returns in this format: 2011-01-15-18-29-35-299
359//--------------------------------------------------
360string ofGetTimestampString(){
361
362string timeFormat = "%Y-%m-%d-%H-%M-%S-%i";
363
364return ofGetTimestampString(timeFormat);
365}
366
367//specify the string format - eg: %Y-%m-%d-%H-%M-%S-%i ( 2011-01-15-18-29-35-299 )
368//--------------------------------------------------
369string ofGetTimestampString(const string& timestampFormat){
370std::stringstream str;
371auto now = std::chrono::system_clock::now();
372auto t = std::chrono::system_clock::to_time_t(now); std::chrono::duration<double> s = now - std::chrono::system_clock::from_time_t(t);
373int ms = s.count() * 1000;
374auto tm = *std::localtime(&t);
375constexpr int bufsize = 256;
376char buf[bufsize];
377
378// Beware! an invalid timestamp string crashes windows apps.
379// so we have to filter out %i (which is not supported by vs)
380// earlier.
381auto tmpTimestampFormat = timestampFormat;
382ofStringReplace(tmpTimestampFormat, "%i", ofToString(ms, 3, '0'));
383
384if (strftime(buf,bufsize, tmpTimestampFormat.c_str(),&tm) != 0){
385str << buf;
386}
387auto ret = str.str();
388
389
390return ret;
391}
392
393//--------------------------------------------------
394int ofGetSeconds(){
395time_t curr;
396tm local;
397time(&curr);
398local =*(localtime(&curr));
399return local.tm_sec;
400}
401
402//--------------------------------------------------
403int ofGetMinutes(){
404time_t curr;
405tm local;
406time(&curr);
407local =*(localtime(&curr));
408return local.tm_min;
409}
410
411//--------------------------------------------------
412int ofGetHours(){
413time_t curr;
414tm local;
415time(&curr);
416local =*(localtime(&curr));
417return local.tm_hour;
418}
419
420//--------------------------------------------------
421int ofGetYear(){
422time_t curr;
423tm local;
424time(&curr);
425local =*(localtime(&curr));
426int year = local.tm_year + 1900;
427return year;
428}
429
430//--------------------------------------------------
431int ofGetMonth(){
432time_t curr;
433tm local;
434time(&curr);
435local =*(localtime(&curr));
436int month = local.tm_mon + 1;
437return month;
438}
439
440//--------------------------------------------------
441int ofGetDay(){
442time_t curr;
443tm local;
444time(&curr);
445local =*(localtime(&curr));
446return local.tm_mday;
447}
448
449//--------------------------------------------------
450int ofGetWeekday(){
451time_t curr;
452tm local;
453time(&curr);
454local =*(localtime(&curr));
455return local.tm_wday;
456}
457
458//----------------------------------------
459template<>
460string ofFromString(const string& value){
461return value;
462}
463
464//----------------------------------------
465template<>
466const char * ofFromString(const string& value){
467return value.c_str();
468}
469
470//----------------------------------------
471template <>
472string ofToHex(const string& value) {
473std::ostringstream out;
474// how many bytes are in the string
475std::size_t numBytes = value.size();
476for(std::size_t i = 0; i < numBytes; i++) {
477// print each byte as a 2-character wide hex value
478out << setfill('0') << std::setw(2) << std::hex << (unsigned int) ((unsigned char)value[i]);
479}
480return out.str();
481}
482
483//----------------------------------------
484string ofToHex(const char* value) {
485// this function is necessary if you want to print a string
486// using a syntax like ofToHex("test")
487return ofToHex((string) value);
488}
489
490//----------------------------------------
491int ofToInt(const string& intString) {
492return ofTo<int>(intString);
493}
494
495//----------------------------------------
496int ofHexToInt(const string& intHexString) {
497int x = 0;
498std::istringstream cur(intHexString);
499cur >> std::hex >> x;
500return x;
501}
502
503//----------------------------------------
504char ofHexToChar(const string& charHexString) {
505int x = 0;
506std::istringstream cur(charHexString);
507cur >> std::hex >> x;
508return (char) x;
509}
510
511//----------------------------------------
512float ofHexToFloat(const string& floatHexString) {
513union intFloatUnion {
514uint32_t i;
515float f;
516} myUnion;
517myUnion.i = 0;
518std::istringstream cur(floatHexString);
519cur >> std::hex >> myUnion.i;
520return myUnion.f;
521}
522
523//----------------------------------------
524string ofHexToString(const string& stringHexString) {
525std::stringstream out;
526std::stringstream stream(stringHexString);
527// a hex string has two characters per byte
528std::size_t numBytes = stringHexString.size() / 2;
529for(std::size_t i = 0; i < numBytes; i++) {
530string curByte;
531// grab two characters from the hex string
532stream >> std::setw(2) >> curByte;
533// prepare to parse the two characters
534std::stringstream curByteStream(curByte);
535int cur = 0;
536// parse the two characters as a hex-encoded int
537curByteStream >> std::hex >> cur;
538// add the int as a char to our output stream
539out << (char) cur;
540}
541return out.str();
542}
543
544//----------------------------------------
545float ofToFloat(const string& floatString) {
546return ofTo<float>(floatString);
547}
548
549//----------------------------------------
550double ofToDouble(const string& doubleString) {
551return ofTo<double>(doubleString);
552}
553
554//----------------------------------------
555int64_t ofToInt64(const string& intString) {
556return ofTo<int64_t>(intString);
557}
558
559//----------------------------------------
560bool ofToBool(const string& boolString) {
561auto lower = ofToLower(boolString);
562if(lower == "true") {
563return true;
564}
565if(lower == "false") {
566return false;
567}
568bool x = false;
569std::istringstream cur(lower);
570cur >> x;
571return x;
572}
573
574//----------------------------------------
575char ofToChar(const string& charString) {
576return ofTo<char>(charString);
577}
578
579//----------------------------------------
580template <> string ofToBinary(const string& value) {
581std::stringstream out;
582std::size_t numBytes = value.size();
583for(std::size_t i = 0; i < numBytes; i++) {
584std::bitset<8> bitBuffer(value[i]);
585out << bitBuffer;
586}
587return out.str();
588}
589
590//----------------------------------------
591string ofToBinary(const char* value) {
592// this function is necessary if you want to print a string
593// using a syntax like ofToBinary("test")
594return ofToBinary((string) value);
595}
596
597//----------------------------------------
598int ofBinaryToInt(const string& value) {
599const int intSize = sizeof(int) * 8;
600std::bitset<intSize> binaryString(value);
601return (int) binaryString.to_ulong();
602}
603
604//----------------------------------------
605char ofBinaryToChar(const string& value) {
606const int charSize = sizeof(char) * 8;
607std::bitset<charSize> binaryString(value);
608return (char) binaryString.to_ulong();
609}
610
611//----------------------------------------
612float ofBinaryToFloat(const string& value) {
613const int floatSize = sizeof(float) * 8;
614std::bitset<floatSize> binaryString(value);
615union ulongFloatUnion {
616unsigned long result;
617float f;
618} myUFUnion;
619myUFUnion.result = binaryString.to_ulong();
620return myUFUnion.f;
621}
622//----------------------------------------
623string ofBinaryToString(const string& value) {
624std::ostringstream out;
625std::stringstream stream(value);
626std::bitset<8> byteString;
627std::size_t numBytes = value.size() / 8;
628for(std::size_t i = 0; i < numBytes; i++) {
629stream >> byteString;
630out << (char) byteString.to_ulong();
631}
632return out.str();
633}
634
635//--------------------------------------------------
636vector <string> ofSplitString(const string & source, const string & delimiter, bool ignoreEmpty, bool trim) {
637vector<string> result;
638if (delimiter.empty()) {
639result.push_back(source);
640return result;
641}
642string::const_iterator substart = source.begin(), subend;
643while (true) {
644subend = search(substart, source.end(), delimiter.begin(), delimiter.end());
645string sub(substart, subend);
646if(trim) {
647sub = ofTrim(sub);
648}
649if (!ignoreEmpty || !sub.empty()) {
650result.push_back(sub);
651}
652if (subend == source.end()) {
653break;
654}
655substart = subend + delimiter.size();
656}
657return result;
658}
659
660//--------------------------------------------------
661string ofJoinString(const vector<string>& stringElements, const string& delimiter){
662string str;
663if(stringElements.empty()){
664return str;
665}
666auto numStrings = stringElements.size();
667string::size_type strSize = delimiter.size() * (numStrings - 1);
668for (const string &s : stringElements) {
669strSize += s.size();
670}
671str.reserve(strSize);
672str += stringElements[0];
673for (decltype(numStrings) i = 1; i < numStrings; ++i) {
674str += delimiter;
675str += stringElements[i];
676}
677return str;
678}
679
680//--------------------------------------------------
681void ofStringReplace(string& input, const string& searchStr, const string& replaceStr){
682auto pos = input.find(searchStr);
683while(pos != std::string::npos){
684input.replace(pos, searchStr.size(), replaceStr);
685pos += replaceStr.size();
686std::string nextfind(input.begin() + pos, input.end());
687auto nextpos = nextfind.find(searchStr);
688if(nextpos==std::string::npos){
689break;
690}
691pos += nextpos;
692}
693}
694
695//--------------------------------------------------
696bool ofIsStringInString(const string& haystack, const string& needle){
697return haystack.find(needle) != std::string::npos;
698}
699
700//--------------------------------------------------
701std::size_t ofStringTimesInString(const string& haystack, const string& needle){
702const size_t step = needle.size();
703
704size_t count(0);
705size_t pos(0) ;
706
707while( (pos=haystack.find(needle, pos)) != std::string::npos) {
708pos +=step;
709++count ;
710}
711
712return count;
713}
714
715
716ofUTF8Iterator::ofUTF8Iterator(const string & str){
717try{
718utf8::replace_invalid(str.begin(),str.end(),back_inserter(src_valid));
719}catch(...){
720}
721}
722
723utf8::iterator<std::string::const_iterator> ofUTF8Iterator::begin() const{
724try {
725return utf8::iterator<std::string::const_iterator>(src_valid.begin(), src_valid.begin(), src_valid.end());
726}
727catch (...) {
728return utf8::iterator<std::string::const_iterator>();
729}
730}
731
732utf8::iterator<std::string::const_iterator> ofUTF8Iterator::end() const{
733try {
734return utf8::iterator<std::string::const_iterator>(src_valid.end(), src_valid.begin(), src_valid.end());
735}
736catch (...) {
737return utf8::iterator<std::string::const_iterator>();
738}
739}
740
741utf8::iterator<std::string::const_reverse_iterator> ofUTF8Iterator::rbegin() const {
742try {
743return utf8::iterator<std::string::const_reverse_iterator>(src_valid.rbegin(), src_valid.rbegin(), src_valid.rend());
744}
745catch (...) {
746return utf8::iterator<std::string::const_reverse_iterator>();
747}
748}
749
750utf8::iterator<std::string::const_reverse_iterator> ofUTF8Iterator::rend() const {
751try {
752return utf8::iterator<std::string::const_reverse_iterator>(src_valid.rbegin(), src_valid.rbegin(), src_valid.rend());
753}
754catch (...) {
755return utf8::iterator<std::string::const_reverse_iterator>();
756}
757}
758
759
760//--------------------------------------------------
761// helper method to get locale from name
762static std::locale getLocale(const string & locale) {
763std::locale loc;
764#if defined(TARGET_WIN32) && !_MSC_VER
765static bool printonce = true;
766if( printonce ){
767std::string current( setlocale(LC_ALL,NULL) );
768setlocale (LC_ALL,"");
769ofLogWarning("ofUtils") << "std::locale not supported. Using C locale: " << current ;
770printonce = false;
771}
772#else
773try {
774loc = std::locale(locale.c_str());
775}
776catch (...) {
777ofLogWarning("ofUtils") << "Couldn't create locale " << locale << " using default, " << loc.name();
778}
779#endif
780return loc;
781}
782
783//--------------------------------------------------
784string ofToLower(const string & src, const string & locale){
785std::string dst;
786std::locale loc = getLocale(locale);
787try{
788for(auto c: ofUTF8Iterator(src)){
789utf8::append(std::tolower<wchar_t>(c, loc), back_inserter(dst));
790}
791}catch(...){
792}
793return dst;
794}
795
796//--------------------------------------------------
797string ofToUpper(const string & src, const string & locale){
798std::string dst;
799std::locale loc = getLocale(locale);
800try{
801for(auto c: ofUTF8Iterator(src)){
802utf8::append(std::toupper<wchar_t>(c, loc), back_inserter(dst));
803}
804}catch(...){
805}
806return dst;
807}
808
809//--------------------------------------------------
810string ofTrimFront(const string & src, const string& locale){
811auto dst = src;
812std::locale loc = getLocale(locale);
813dst.erase(dst.begin(),std::find_if_not(dst.begin(),dst.end(),[&](char & c){return std::isspace<char>(c,loc);}));
814return dst;
815}
816
817//--------------------------------------------------
818string ofTrimBack(const string & src, const string& locale){
819auto dst = src;
820std::locale loc = getLocale(locale);
821dst.erase(std::find_if_not(dst.rbegin(),dst.rend(),[&](char & c){return std::isspace<char>(c,loc);}).base(), dst.end());
822return dst;
823}
824
825//--------------------------------------------------
826string ofTrim(const string & src, const string& locale){
827return ofTrimFront(ofTrimBack(src));
828}
829
830//--------------------------------------------------
831void ofAppendUTF8(string & str, uint32_t utf8){
832try{
833utf8::append(utf8, back_inserter(str));
834}catch(...){}
835}
836
837//--------------------------------------------------
838void ofUTF8Append(string & str, uint32_t utf8){
839try{
840utf8::append(utf8, back_inserter(str));
841}catch(...){}
842}
843
844//--------------------------------------------------
845void ofUTF8Insert(string & str, size_t pos, uint32_t utf8){
846std::string newText;
847size_t i = 0;
848for(auto c: ofUTF8Iterator(str)){
849if(i==pos){
850ofUTF8Append(newText, utf8);
851}
852ofUTF8Append(newText, c);
853i+=1;
854}
855if(i==pos){
856ofUTF8Append(newText, utf8);
857}
858str = newText;
859}
860
861//--------------------------------------------------
862void ofUTF8Erase(string & str, size_t start, size_t len){
863std::string newText;
864size_t i = 0;
865for(auto c: ofUTF8Iterator(str)){
866if(i<start || i>=start + len){
867ofUTF8Append(newText, c);
868}
869i+=1;
870}
871str = newText;
872}
873
874//--------------------------------------------------
875std::string ofUTF8Substring(const string & str, size_t start, size_t len){
876size_t i=0;
877std::string newText;
878for(auto c: ofUTF8Iterator(str)){
879if(i>=start){
880ofUTF8Append(newText, c);
881}
882i += 1;
883if(i==start + len){
884break;
885}
886}
887return newText;
888}
889
890//--------------------------------------------------
891std::string ofUTF8ToString(uint32_t utf8){
892std::string str;
893ofUTF8Append(str, utf8);
894return str;
895}
896
897//--------------------------------------------------
898size_t ofUTF8Length(const std::string & str){
899try{
900return utf8::distance(str.begin(), str.end());
901}catch(...){
902return 0;
903}
904}
905
906//--------------------------------------------------
907void ofLaunchBrowser(const string& url, bool uriEncodeQuery){
908UriParserStateA state;
909UriUriA uri;
910state.uri = &uri;
911if(uriParseUriA(&state, url.c_str())!=URI_SUCCESS){
912ofLogError("ofUtils") << "ofLaunchBrowser(): malformed url \"" << url << "\"";
913uriFreeUriMembersA(&uri);
914return;
915}
916if(uriEncodeQuery) {
917uriNormalizeSyntaxA(&uri); // URI encodes during set
918}
919std::string scheme(uri.scheme.first, uri.scheme.afterLast);
920int size;
921uriToStringCharsRequiredA(&uri, &size);
922std::vector<char> buffer(size+1, 0);
923int written;
924uriToStringA(buffer.data(), &uri, url.size()*2, &written);
925std::string uriStr(buffer.data(), written-1);
926uriFreeUriMembersA(&uri);
927
928
929// http://support.microsoft.com/kb/224816
930// make sure it is a properly formatted url:
931// some platforms, like Android, require urls to start with lower-case http/https
932// Poco::URI automatically converts the scheme to lower case
933if(scheme != "http" && scheme != "https"){
934ofLogError("ofUtils") << "ofLaunchBrowser(): url does not begin with http:// or https://: \"" << uriStr << "\"";
935return;
936}
937
938#ifdef TARGET_WIN32
939ShellExecuteA(nullptr, "open", uriStr.c_str(),
940nullptr, nullptr, SW_SHOWNORMAL);
941#endif
942
943#ifdef TARGET_OSX
944// could also do with LSOpenCFURLRef
945string commandStr = "open \"" + uriStr + "\"";
946int ret = system(commandStr.c_str());
947if(ret!=0) {
948ofLogError("ofUtils") << "ofLaunchBrowser(): couldn't open browser, commandStr \"" << commandStr << "\"";
949}
950#endif
951
952#ifdef TARGET_LINUX
953string commandStr = "xdg-open \"" + uriStr + "\"";
954int ret = system(commandStr.c_str());
955if(ret!=0) {
956ofLogError("ofUtils") << "ofLaunchBrowser(): couldn't open browser, commandStr \"" << commandStr << "\"";
957}
958#endif
959
960#ifdef TARGET_OF_IOS
961ofxiOSLaunchBrowser(uriStr);
962#endif
963
964#ifdef TARGET_ANDROID
965ofxAndroidLaunchBrowser(uriStr);
966#endif
967
968#ifdef TARGET_EMSCRIPTEN
969ofLogError("ofUtils") << "ofLaunchBrowser() not implementeed in emscripten";
970#endif
971}
972
973//--------------------------------------------------
974string ofGetVersionInfo(){
975std::stringstream sstr;
976sstr << OF_VERSION_MAJOR << "." << OF_VERSION_MINOR << "." << OF_VERSION_PATCH;
977
978if (!std::string(OF_VERSION_PRE_RELEASE).empty())
979{
980sstr << "-" << OF_VERSION_PRE_RELEASE;
981}
982
983return sstr.str();
984}
985
986unsigned int ofGetVersionMajor() {
987return OF_VERSION_MAJOR;
988}
989
990unsigned int ofGetVersionMinor() {
991return OF_VERSION_MINOR;
992}
993
994unsigned int ofGetVersionPatch() {
995return OF_VERSION_PATCH;
996}
997
998std::string ofGetVersionPreRelease() {
999return OF_VERSION_PRE_RELEASE;
1000}
1001
1002
1003//---- new to 006
1004//from the forums http://www.openframeworks.cc/forum/viewtopic.php?t=1413
1005
1006//--------------------------------------------------
1007void ofSaveScreen(const string& filename) {
1008/*ofImage screen;
1009screen.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_COLOR);
1010screen.grabScreen(0, 0, ofGetWidth(), ofGetHeight());
1011screen.save(filename);*/
1012ofPixels pixels;
1013ofGetGLRenderer()->saveFullViewport(pixels);
1014ofSaveImage(pixels,filename);
1015}
1016
1017//--------------------------------------------------
1018void ofSaveViewport(const string& filename) {
1019// because ofSaveScreen doesn't related to viewports
1020/*ofImage screen;
1021ofRectangle view = ofGetCurrentViewport();
1022screen.allocate(view.width, view.height, OF_IMAGE_COLOR);
1023screen.grabScreen(0, 0, view.width, view.height);
1024screen.save(filename);*/
1025
1026ofPixels pixels;
1027ofGetGLRenderer()->saveFullViewport(pixels);
1028ofSaveImage(pixels,filename);
1029}
1030
1031//--------------------------------------------------
1032int saveImageCounter = 0;
1033void ofSaveFrame(bool bUseViewport){
1034string fileName = ofToString(saveImageCounter) + ".png";
1035if (bUseViewport){
1036ofSaveViewport(fileName);
1037} else {
1038ofSaveScreen(fileName);
1039}
1040saveImageCounter++;
1041}
1042
1043//--------------------------------------------------
1044string ofSystem(const string& command){
1045FILE * ret = nullptr;
1046#ifdef TARGET_WIN32
1047ret = _popen(command.c_str(),"r");
1048#else
1049ret = popen(command.c_str(),"r");
1050#endif
1051
1052string strret;
1053int c;
1054
1055if (ret == nullptr){
1056ofLogError("ofUtils") << "ofSystem(): error opening return file for command \"" << command << "\"";
1057}else{
1058c = fgetc (ret);
1059while (c != EOF) {
1060strret += c;
1061c = fgetc (ret);
1062}
1063#ifdef TARGET_WIN32
1064_pclose (ret);
1065#else
1066pclose (ret);
1067#endif
1068}
1069
1070return strret;
1071}
1072
1073//--------------------------------------------------
1074ofTargetPlatform ofGetTargetPlatform(){
1075#ifdef TARGET_LINUX
1076string arch = ofSystem("uname -m");
1077if(ofIsStringInString(arch,"x86_64")) {
1078return OF_TARGET_LINUX64;
1079} else if(ofIsStringInString(arch,"armv6l")) {
1080return OF_TARGET_LINUXARMV6L;
1081} else if(ofIsStringInString(arch,"armv7l")) {
1082return OF_TARGET_LINUXARMV7L;
1083} else if(ofIsStringInString(arch,"aarch64")) {
1084return OF_TARGET_LINUXAARCH64;
1085} else {
1086return OF_TARGET_LINUX;
1087}
1088#elif defined(TARGET_OSX)
1089return OF_TARGET_OSX;
1090#elif defined(TARGET_WIN32)
1091#if (_MSC_VER)
1092return OF_TARGET_WINVS;
1093#else
1094return OF_TARGET_MINGW;
1095#endif
1096#elif defined(TARGET_ANDROID)
1097return OF_TARGET_ANDROID;
1098#elif defined(TARGET_OF_IOS)
1099return OF_TARGET_IOS;
1100#elif defined(TARGET_EMSCRIPTEN)
1101return OF_TARGET_EMSCRIPTEN;
1102#endif
1103}
1104
1105std::string ofGetEnv(const std::string & var, const std::string defaultValue){
1106#ifdef TARGET_WIN32
1107const size_t BUFSIZE = 4096;
1108std::vector<char> pszOldVal(BUFSIZE, 0);
1109auto size = GetEnvironmentVariableA(var.c_str(), pszOldVal.data(), BUFSIZE);
1110if(size>0){
1111return std::string(pszOldVal.begin(), pszOldVal.begin()+size);
1112}else{
1113return defaultValue;
1114}
1115#else
1116auto value = getenv(var.c_str());
1117if(value){
1118return value;
1119}else{
1120return defaultValue;
1121}
1122#endif
1123}
1124