bbstring.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. #include "bbstring.h"
  2. #include "bbarray.h"
  3. #include "bbplatform.h"
  4. #include "bbmonkey.h"
  5. #include <cwctype>
  6. #include <clocale>
  7. #ifdef BB_THREADS
  8. #include <mutex>
  9. #endif
  10. bbString::Rep bbString::_nullRep;
  11. #if BB_ANDROID
  12. #include <jni.h>
  13. //FIXME: SDL2 dependancy!
  14. extern "C" void *SDL_AndroidGetJNIEnv();
  15. #endif
  16. namespace{
  17. #if BB_ANDROID
  18. jclass jclass_lang;
  19. jmethodID jmethod_toUpper;
  20. jmethodID jmethod_toLower;
  21. jmethodID jmethod_capitalize;
  22. bbString JStringToString( JNIEnv *env,jstring jstr ){
  23. if( !jstr ) return "";
  24. const char *cstr=env->GetStringUTFChars( jstr,0 );
  25. bbString str=bbString::fromCString( cstr );
  26. env->ReleaseStringUTFChars( jstr,cstr );
  27. return str;
  28. }
  29. jstring StringToJString( JNIEnv *env,bbString str ){
  30. int n=str.utf8Length()+1;
  31. char *buf=new char[n];
  32. str.toCString( buf,n );
  33. jstring jstr=env->NewStringUTF( buf );
  34. return jstr;
  35. }
  36. bbString invokeStaticStringMethod( jmethodID jmethod,bbString arg ){
  37. JNIEnv *env=(JNIEnv*)SDL_AndroidGetJNIEnv();
  38. jstring jarg=StringToJString( env,arg );
  39. jstring jres=(jstring)env->CallStaticObjectMethod( jclass_lang,jmethod,jarg );
  40. bbString res=JStringToString( env,jres );
  41. env->DeleteLocalRef( jres );
  42. env->DeleteLocalRef( jarg );
  43. return res;
  44. }
  45. #endif
  46. void initLocale(){
  47. #if BB_THREADS
  48. static std::atomic_bool inited;
  49. if( inited.exchange( true ) ) return;
  50. #else
  51. static bool inited;
  52. if( inited ) return;
  53. inited=true;
  54. #endif
  55. #if BB_ANDROID
  56. JNIEnv *env=(JNIEnv*)SDL_AndroidGetJNIEnv();
  57. jclass_lang=env->FindClass( "com/monkey2/lib/Monkey2Lang" );
  58. jmethod_toUpper=env->GetStaticMethodID( jclass_lang,"toUpper","(Ljava/lang/String;)Ljava/lang/String;" );
  59. jmethod_toLower=env->GetStaticMethodID( jclass_lang,"toLower","(Ljava/lang/String;)Ljava/lang/String;" );
  60. jmethod_capitalize=env->GetStaticMethodID( jclass_lang,"capitalize","(Ljava/lang/String;)Ljava/lang/String;" );
  61. bb_printf( "initLocale: env=%p\n",env );
  62. #elif BB_WINDOWS
  63. std::setlocale( LC_ALL,"English" );
  64. // std::setlocale( LC_CTYPE,"English" );
  65. #else
  66. std::setlocale( LC_CTYPE,"en_US.UTF-8" );
  67. #endif
  68. }
  69. template<class C> int t_memcmp( const C *p1,const C *p2,int count ){
  70. return memcmp( p1,p2,count*sizeof(C) );
  71. }
  72. //returns END of dst!
  73. template<class C> C *t_memcpy( C *dst,const C *src,int count ){
  74. return (C*)memcpy( dst,src,count*sizeof(C) )+count;
  75. }
  76. int countUtf8Chars( const char *p,int sz ){
  77. const char *e=p+sz;
  78. int n=0;
  79. while( p!=e ){
  80. int c=*p++;
  81. if( c & 0x80 ){
  82. if( (c & 0xe0)==0xc0 ){
  83. if( p==e || (p[0] & 0xc0)!=0x80 ) return -1;
  84. p+=1;
  85. }else if( (c & 0xf0)==0xe0 ){
  86. if( p==e || p+1==e || (p[0] & 0xc0)!=0x80 || (p[1] & 0xc0)!=0x80 ) return -1;
  87. p+=2;
  88. }else{
  89. return -1;
  90. }
  91. }
  92. n+=1;
  93. }
  94. return n;
  95. }
  96. int countNullTerminatedUtf8Chars( const char *p,int sz ){
  97. const char *e=p+sz;
  98. int n=0;
  99. while( p!=e && *p ){
  100. int c=*p++;
  101. if( c & 0x80 ){
  102. if( (c & 0xe0)==0xc0 ){
  103. if( p==e || (p[0] & 0xc0)!=0x80 ) return -1;
  104. p+=1;
  105. }else if( (c & 0xf0)==0xe0 ){
  106. if( p==e || p+1==e || (p[0] & 0xc0)!=0x80 || (p[1] & 0xc0)!=0x80 ) return -1;
  107. p+=2;
  108. }else{
  109. return -1;
  110. }
  111. }
  112. n+=1;
  113. }
  114. return n;
  115. }
  116. void charsToUtf8( const bbChar *p,int n,char *dst,int size ){
  117. char *end=dst+size;
  118. const bbChar *e=p+n;
  119. while( p<e && dst<end ){
  120. bbChar c=*p++;
  121. if( c<0x80 ){
  122. *dst++=c;
  123. }else if( c<0x800 ){
  124. if( dst+2>end ) break;
  125. *dst++=0xc0 | (c>>6);
  126. *dst++=0x80 | (c & 0x3f);
  127. }else{
  128. if( dst+3>end ) break;
  129. *dst++=0xe0 | (c>>12);
  130. *dst++=0x80 | ((c>>6) & 0x3f);
  131. *dst++=0x80 | (c & 0x3f);
  132. }
  133. }
  134. if( dst<end ) *dst++=0;
  135. }
  136. void utf8ToChars( const char *p,bbChar *dst,int n ){
  137. while( n-- ){
  138. int c=*p++;
  139. if( c & 0x80 ){
  140. if( (c & 0xe0)==0xc0 ){
  141. c=((c & 0x1f)<<6) | (p[0] & 0x3f);
  142. p+=1;
  143. }else if( (c & 0xf0)==0xe0 ){
  144. c=((c & 0x0f)<<12) | ((p[0] & 0x3f)<<6) | (p[1] & 0x3f);
  145. p+=2;
  146. }
  147. }
  148. *dst++=c;
  149. }
  150. }
  151. }
  152. // ***** bbString::Rep *****
  153. bbString::Rep *bbString::Rep::alloc( int length ){
  154. if( !length ) return &_nullRep;
  155. Rep *rep=(Rep*)bbGC::malloc( sizeof(Rep)+length*sizeof(bbChar) );
  156. rep->refs=1;
  157. rep->length=length;
  158. return rep;
  159. }
  160. // ***** bbString *****
  161. bbString::bbString( const void *p ){
  162. const char *cp=(const char*)p;
  163. if( !cp ){
  164. _rep=&_nullRep;
  165. return;
  166. }
  167. int sz=strlen( cp );
  168. int n=countNullTerminatedUtf8Chars( cp,sz );
  169. if( n==-1 || n==sz ){
  170. _rep=Rep::create( cp,sz );
  171. return;
  172. }
  173. Rep *rep=Rep::alloc( n );
  174. utf8ToChars( cp,rep->data,n );
  175. _rep=rep;
  176. }
  177. bbString::bbString( const void *p,int sz ){
  178. const char *cp=(const char*)p;
  179. if( !cp ){
  180. _rep=&_nullRep;
  181. return;
  182. }
  183. int n=countUtf8Chars( cp,sz );
  184. if( n==-1 || n==sz ){
  185. _rep=Rep::create( cp,sz );
  186. return;
  187. }
  188. Rep *rep=Rep::alloc( n );
  189. utf8ToChars( cp,rep->data,n );
  190. _rep=rep;
  191. }
  192. bbString::bbString( const bbChar *data ):_rep( Rep::create( data ) ){
  193. }
  194. bbString::bbString( const bbChar *data,int length ):_rep( Rep::create( data,length ) ){
  195. }
  196. bbString::bbString( const wchar_t *data ):_rep( Rep::create( data ) ){
  197. }
  198. bbString::bbString( const wchar_t *data,int length ):_rep( Rep::create( data,length ) ){
  199. }
  200. int bbString::utf8Length()const{
  201. const bbChar *p=data();
  202. const bbChar *e=p+length();
  203. int n=0;
  204. while( p<e ){
  205. bbChar c=*p++;
  206. if( c<0x80 ){
  207. n+=1;
  208. }else if( c<0x800 ){
  209. n+=2;
  210. }else{
  211. n+=3;
  212. }
  213. }
  214. return n;
  215. }
  216. bbString::bbString( bool b ){
  217. _rep=Rep::create( b ? "True" : "False" );
  218. }
  219. bbString::bbString( int n ){
  220. char data[64];
  221. sprintf( data,"%d",n );
  222. _rep=Rep::create( data );
  223. }
  224. bbString::bbString( unsigned int n ){
  225. char data[64];
  226. sprintf( data,"%u",n );
  227. _rep=Rep::create( data );
  228. }
  229. bbString::bbString( long n ){
  230. char data[64];
  231. sprintf( data,"%ld",n );
  232. _rep=Rep::create( data );
  233. }
  234. bbString::bbString( unsigned long n ){
  235. char data[64];
  236. sprintf( data,"%lu",n );
  237. _rep=Rep::create( data );
  238. }
  239. bbString::bbString( long long n ){
  240. char data[64];
  241. sprintf( data,"%lld",n );
  242. _rep=Rep::create( data );
  243. }
  244. bbString::bbString( unsigned long long n ){
  245. char data[64];
  246. sprintf( data,"%llu",n );
  247. _rep=Rep::create( data );
  248. }
  249. bbString::bbString( float n ){
  250. char data[64];
  251. sprintf( data,"%.9g",n );
  252. _rep=Rep::create( data );
  253. }
  254. bbString::bbString( double n ){
  255. char data[64];
  256. sprintf( data,"%.17g",n );
  257. _rep=Rep::create( data );
  258. }
  259. void bbString::toCString( void *buf,int size )const{
  260. Rep *rep=_rep;
  261. charsToUtf8( rep->data,rep->length,(char*)buf,size );
  262. }
  263. void bbString::toWString( void *buf,int size )const{
  264. size=size/sizeof(wchar_t);
  265. if( size<=0 ) return;
  266. int sz=length();
  267. if( sz>size ) sz=size;
  268. for( int i=0;i<sz;++i ) ((wchar_t*)buf)[i]=data()[i];
  269. if( sz<size ) ((wchar_t*)buf)[sz]=0;
  270. }
  271. const char *bbString::c_str()const{
  272. static int _sz;
  273. static char *_tmp;
  274. int sz=utf8Length()+1;
  275. #ifdef BB_THREADS
  276. std::mutex _mutex;
  277. _mutex.lock();
  278. #endif
  279. if( sz>_sz ){
  280. ::free( _tmp );
  281. _tmp=(char*)::malloc( _sz=sz );
  282. }
  283. #ifdef BB_THREADS
  284. _mutex.unlock();
  285. #endif
  286. toCString( _tmp,sz );
  287. return _tmp;
  288. }
  289. bool bbString::startsWith( const bbString &str )const{
  290. if( str.length()>length() ) return false;
  291. return t_memcmp( data(),str.data(),str.length() )==0;
  292. }
  293. bool bbString::endsWith( const bbString &str )const{
  294. if( str.length()>length() ) return false;
  295. return t_memcmp( data()+(length()-str.length()),str.data(),str.length() )==0;
  296. }
  297. bbString bbString::fromChar( int chr ){
  298. wchar_t chrs[]={ wchar_t(chr) };
  299. return bbString( chrs,1 );
  300. }
  301. bbArray<bbString> bbString::split( bbString sep )const{
  302. if( !sep.length() ){
  303. bbArray<bbString> bits=bbArray<bbString>( length() );
  304. bits.retain();
  305. for( int i=0;i<length();++i ){
  306. bits[i]=bbString( &data()[i],1 );
  307. }
  308. bits.release();
  309. return bits;
  310. }
  311. int i=0,i2,n=1;
  312. while( (i2=find( sep,i ))!=-1 ){
  313. ++n;
  314. i=i2+sep.length();
  315. }
  316. bbArray<bbString> bits=bbArray<bbString>( n );
  317. bits.retain();
  318. if( n==1 ){
  319. bits[0]=*this;
  320. }else{
  321. i=0;n=0;
  322. while( (i2=find( sep,i ))!=-1 ){
  323. bits[n++]=slice( i,i2 );
  324. i=i2+sep.length();
  325. }
  326. bits[n]=slice( i );
  327. }
  328. bits.release();
  329. return bits;
  330. }
  331. bbString bbString::join( bbArray<bbString> bits )const{
  332. if( bits.length()==0 ) return bbString();
  333. if( bits.length()==1 ) return bits[0];
  334. int len=length() * (bits.length()-1);
  335. for( int i=0;i<bits.length();++i ) len+=bits[i].length();
  336. Rep *rep=Rep::alloc( len );
  337. bbChar *p=rep->data;
  338. p=t_memcpy( p,bits[0].data(),bits[0].length() );
  339. for( int i=1;i<bits.length();++i ){
  340. p=t_memcpy( p,data(),length() );
  341. p=t_memcpy( p,bits[i].data(),bits[i].length() );
  342. }
  343. return rep;
  344. }
  345. bbString bbString::fromChars( bbArray<int> chrs ){
  346. return Rep::create( chrs.data(),chrs.length() );
  347. }
  348. bbString bbString::operator-()const{
  349. Rep *rep=Rep::alloc( length() );
  350. const bbChar *p=data()+length();
  351. for( int i=0;i<rep->length;++i ) rep->data[i]=*--p;
  352. return rep;
  353. }
  354. bbString bbString::operator+( const bbString &str )const{
  355. if( !length() ) return str;
  356. if( !str.length() ) return *this;
  357. Rep *rep=Rep::alloc( length()+str.length() );
  358. t_memcpy( rep->data,data(),length() );
  359. t_memcpy( rep->data+length(),str.data(),str.length() );
  360. return rep;
  361. }
  362. bbString bbString::operator*( int n )const{
  363. Rep *rep=Rep::alloc( length()*n );
  364. bbChar *p=rep->data;
  365. for( int j=0;j<n;++j ){
  366. for( int i=0;i<length();++i ) *p++=data()[i];
  367. }
  368. return rep;
  369. }
  370. int bbString::find( bbString str,int from )const{
  371. if( from<0 ) from=0;
  372. for( int i=from;i<=length()-str.length();++i ){
  373. if( !t_memcmp( data()+i,str.data(),str.length() ) ) return i;
  374. }
  375. return -1;
  376. }
  377. int bbString::findLast( const bbString &str,int from )const{
  378. if( from<0 ) from=0;
  379. for( int i=length()-str.length();i>=from;--i ){
  380. if( !t_memcmp( data()+i,str.data(),str.length() ) ) return i;
  381. }
  382. return -1;
  383. }
  384. bbString bbString::slice( int from )const{
  385. int length=this->length();
  386. if( from<0 ){
  387. from+=length;
  388. if( from<0 ) from=0;
  389. }else if( from>length ){
  390. from=length;
  391. }
  392. if( !from ) return *this;
  393. return bbString( data()+from,length-from );
  394. }
  395. bbString bbString::slice( int from,int term )const{
  396. int length=this->length();
  397. if( from<0 ){
  398. from+=length;
  399. if( from<0 ) from=0;
  400. }else if( from>length ){
  401. from=length;
  402. }
  403. if( term<0 ){
  404. term+=length;
  405. if( term<from ) term=from;
  406. }else if( term<from ){
  407. term=from;
  408. }else if( term>length ){
  409. term=length;
  410. }
  411. if( !from && term==length ) return *this;
  412. return bbString( data()+from,term-from );
  413. }
  414. bbString bbString::toUpper()const{
  415. initLocale();
  416. #if BB_ANDROID
  417. return invokeStaticStringMethod( jmethod_toUpper,*this );
  418. #else
  419. Rep *rep=Rep::alloc( length() );
  420. for( int i=0;i<length();++i ) rep->data[i]=::towupper( data()[i] );
  421. return rep;
  422. #endif
  423. }
  424. bbString bbString::toLower()const{
  425. initLocale();
  426. #if BB_ANDROID
  427. return invokeStaticStringMethod( jmethod_toLower,*this );
  428. #else
  429. Rep *rep=Rep::alloc( length() );
  430. for( int i=0;i<length();++i ) rep->data[i]=::towlower( data()[i] );
  431. return rep;
  432. #endif
  433. }
  434. bbString bbString::capitalize()const{
  435. initLocale();
  436. #if BB_ANDROID
  437. return invokeStaticStringMethod( jmethod_capitalize,*this );
  438. #else
  439. if( !length() ) return &_nullRep;
  440. Rep *rep=Rep::alloc( length() );
  441. rep->data[0]=::towupper( data()[0] );
  442. for( int i=1;i<length();++i ) rep->data[i]=data()[i];
  443. return rep;
  444. #endif
  445. }
  446. bbString bbString::trim()const{
  447. const bbChar *beg=data();
  448. const bbChar *end=data()+length();
  449. while( beg!=end && *beg<=32 ) ++beg;
  450. while( beg!=end && *(end-1)<=32 ) --end;
  451. if( end-beg==length() ) return *this;
  452. return bbString( beg,end-beg );
  453. }
  454. bbString bbString::trimStart()const{
  455. const bbChar *beg=data();
  456. const bbChar *end=data()+length();
  457. while( beg!=end && *beg<=32 ) ++beg;
  458. if( end-beg==length() ) return *this;
  459. return bbString( beg,end-beg );
  460. }
  461. bbString bbString::trimEnd()const{
  462. const bbChar *beg=data();
  463. const bbChar *end=data()+length();
  464. while( beg!=end && *(end-1)<=32 ) --end;
  465. if( end-beg==length() ) return *this;
  466. return bbString( beg,end-beg );
  467. }
  468. bbString bbString::dup( int n )const{
  469. Rep *rep=Rep::alloc( length()*n );
  470. bbChar *p=rep->data;
  471. for( int j=0;j<n;++j ){
  472. for( int i=0;i<length();++i ) *p++=data()[i];
  473. }
  474. return rep;
  475. }
  476. bbString bbString::replace( const bbString &str,const bbString &repl )const{
  477. int n=0;
  478. for( int i=0;; ){
  479. i=find( str,i );
  480. if( i==-1 ) break;
  481. i+=str.length();
  482. ++n;
  483. }
  484. if( !n ) return *this;
  485. Rep *rep=Rep::alloc( length()+n*(repl.length()-str.length()) );
  486. bbChar *dst=rep->data;
  487. for( int i=0;; ){
  488. int i2=find( str,i );
  489. if( i2==-1 ){
  490. t_memcpy( dst,data()+i,(length()-i) );
  491. break;
  492. }
  493. t_memcpy( dst,data()+i,(i2-i) );
  494. dst+=(i2-i);
  495. t_memcpy( dst,repl.data(),repl.length() );
  496. dst+=repl.length();
  497. i=i2+str.length();
  498. }
  499. return rep;
  500. }
  501. int bbString::compare( const bbString &t )const{
  502. int len=length()<t.length() ? length() : t.length();
  503. for( int i=0;i<len;++i ){
  504. if( int n=data()[i]-t.data()[i] ) return n;
  505. }
  506. return length()-t.length();
  507. }
  508. bbString::operator bbInt()const{
  509. return std::atoi( c_str() );
  510. }
  511. bbString::operator bbByte()const{
  512. return operator bbInt() & 0xff;
  513. }
  514. bbString::operator bbUByte()const{
  515. return operator bbInt() & 0xffu;
  516. }
  517. bbString::operator bbShort()const{
  518. return operator bbInt() & 0xffff;
  519. }
  520. bbString::operator bbUShort()const{
  521. return operator bbInt() & 0xffffu;
  522. }
  523. bbString::operator bbUInt()const{
  524. bbUInt n=0;
  525. sscanf( c_str(),"%u",&n );
  526. return n;
  527. }
  528. bbString::operator bbLong()const{
  529. bbLong n=0;
  530. sscanf( c_str(),"%lld",&n );
  531. return n;
  532. }
  533. bbString::operator bbULong()const{
  534. bbULong n=0;
  535. sscanf( c_str(),"%llu",&n );
  536. return n;
  537. }
  538. bbString::operator float()const{
  539. return std::atof( c_str() );
  540. }
  541. bbString::operator double()const{
  542. return std::atof( c_str() );
  543. }
  544. // ***** CString *****
  545. bbCString::bbCString( const bbString &str ){
  546. int size=str.utf8Length()+1;
  547. _data=(char*)bbGC::malloc( size );
  548. str.toCString( _data,size );
  549. }
  550. bbCString::~bbCString(){
  551. bbGC::free( _data );
  552. }
  553. bbCString::operator char*()const{
  554. return _data;
  555. }
  556. bbCString::operator signed char*()const{
  557. return (signed char*)_data;
  558. }
  559. bbCString::operator unsigned char*()const{
  560. return (unsigned char*)_data;
  561. }
  562. // ***** WString *****
  563. bbWString::bbWString( const bbString &str ){
  564. int size=(str.length()+1)*sizeof(wchar_t);
  565. _data=(wchar_t*)bbGC::malloc( size );
  566. str.toWString( _data,size );
  567. }
  568. bbWString::~bbWString(){
  569. bbGC::free( _data );
  570. }
  571. bbWString::operator wchar_t*()const{
  572. return _data;
  573. }