natString.cc 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. // natString.cc - Implementation of java.lang.String native methods.
  2. /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
  3. 2007, 2008 Free Software Foundation
  4. This file is part of libgcj.
  5. This software is copyrighted work licensed under the terms of the
  6. Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
  7. details. */
  8. #include <config.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <gcj/cni.h>
  12. #include <java/lang/Character.h>
  13. #include <java/lang/CharSequence.h>
  14. #include <java/lang/String.h>
  15. #include <java/lang/IndexOutOfBoundsException.h>
  16. #include <java/lang/ArrayIndexOutOfBoundsException.h>
  17. #include <java/lang/StringIndexOutOfBoundsException.h>
  18. #include <java/lang/NullPointerException.h>
  19. #include <java/lang/StringBuffer.h>
  20. #include <java/io/ByteArrayOutputStream.h>
  21. #include <java/io/CharConversionException.h>
  22. #include <java/io/OutputStreamWriter.h>
  23. #include <java/io/ByteArrayInputStream.h>
  24. #include <java/io/InputStreamReader.h>
  25. #include <java/util/Locale.h>
  26. #include <gnu/gcj/convert/UnicodeToBytes.h>
  27. #include <gnu/gcj/convert/BytesToUnicode.h>
  28. #include <gnu/gcj/runtime/StringBuffer.h>
  29. #include <jvm.h>
  30. static jstring* strhash = NULL;
  31. static int strhash_count = 0; /* Number of slots used in strhash. */
  32. static int strhash_size = 0; /* Number of slots available in strhash.
  33. * Assumed be power of 2! */
  34. // Some defines used by toUpperCase / toLowerCase.
  35. #define ESSET 0x00df
  36. #define CAPITAL_S 0x0053
  37. #define SMALL_I 0x0069
  38. #define CAPITAL_I_WITH_DOT 0x0130
  39. #define SMALL_DOTLESS_I 0x0131
  40. #define CAPITAL_I 0x0049
  41. #define DELETED_STRING ((jstring)(~0))
  42. #define SET_STRING_IS_INTERNED(STR) /* nothing */
  43. #define UNMASK_PTR(Ptr) (((unsigned long) (Ptr)) & ~0x01)
  44. #define MASK_PTR(Ptr) (((unsigned long) (Ptr)) | 0x01)
  45. #define PTR_MASKED(Ptr) (((unsigned long) (Ptr)) & 0x01)
  46. /* Find a slot where the string with elements DATA, length LEN,
  47. and hash HASH should go in the strhash table of interned strings. */
  48. jstring*
  49. _Jv_StringFindSlot (jchar* data, jint len, jint hash)
  50. {
  51. JvSynchronize sync (&java::lang::String::class$);
  52. int start_index = hash & (strhash_size - 1);
  53. int deleted_index = -1;
  54. int index = start_index;
  55. /* step must be non-zero, and relatively prime with strhash_size. */
  56. jint step = (hash ^ (hash >> 16)) | 1;
  57. do
  58. {
  59. jstring* ptr = &strhash[index];
  60. jstring value = (jstring) UNMASK_PTR (*ptr);
  61. if (value == NULL)
  62. {
  63. if (deleted_index >= 0)
  64. return (&strhash[deleted_index]);
  65. else
  66. return ptr;
  67. }
  68. else if (*ptr == DELETED_STRING)
  69. deleted_index = index;
  70. else if (value->length() == len
  71. && memcmp(JvGetStringChars(value), data, 2*len) == 0)
  72. return (ptr);
  73. index = (index + step) & (strhash_size - 1);
  74. }
  75. while (index != start_index);
  76. // Note that we can have INDEX == START_INDEX if the table has no
  77. // NULL entries but does have DELETED_STRING entries.
  78. JvAssert (deleted_index >= 0);
  79. return &strhash[deleted_index];
  80. }
  81. /* Calculate a hash code for the string starting at PTR at given LENGTH.
  82. This uses the same formula as specified for java.lang.String.hash. */
  83. static jint
  84. hashChars (jchar* ptr, jint length)
  85. {
  86. jchar* limit = ptr + length;
  87. jint hash = 0;
  88. // Updated specification from
  89. // http://www.javasoft.com/docs/books/jls/clarify.html.
  90. while (ptr < limit)
  91. hash = (31 * hash) + *ptr++;
  92. return hash;
  93. }
  94. jint
  95. java::lang::String::hashCode()
  96. {
  97. if (cachedHashCode == 0)
  98. cachedHashCode = hashChars(JvGetStringChars(this), length());
  99. return cachedHashCode;
  100. }
  101. jstring*
  102. _Jv_StringGetSlot (jstring str)
  103. {
  104. jchar* data = JvGetStringChars(str);
  105. int length = str->length();
  106. return _Jv_StringFindSlot(data, length, hashChars (data, length));
  107. }
  108. static void
  109. rehash ()
  110. {
  111. JvSynchronize sync (&java::lang::String::class$);
  112. if (strhash == NULL)
  113. {
  114. strhash_size = 1024;
  115. strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring));
  116. }
  117. else
  118. {
  119. int i = strhash_size;
  120. jstring* ptr = strhash + i;
  121. int nsize = strhash_size * 2;
  122. jstring *next = (jstring *) _Jv_AllocBytes (nsize * sizeof (jstring));
  123. while (--i >= 0)
  124. {
  125. --ptr;
  126. if (*ptr == NULL || *ptr == DELETED_STRING)
  127. continue;
  128. /* This is faster equivalent of
  129. * *__JvGetInternSlot(*ptr) = *ptr; */
  130. jstring val = (jstring) UNMASK_PTR (*ptr);
  131. jint hash = val->hashCode();
  132. jint index = hash & (nsize - 1);
  133. jint step = (hash ^ (hash >> 16)) | 1;
  134. for (;;)
  135. {
  136. if (next[index] == NULL)
  137. {
  138. next[index] = *ptr;
  139. break;
  140. }
  141. index = (index + step) & (nsize - 1);
  142. }
  143. }
  144. strhash_size = nsize;
  145. strhash = next;
  146. }
  147. }
  148. jstring
  149. java::lang::String::intern()
  150. {
  151. JvSynchronize sync (&java::lang::String::class$);
  152. if (3 * strhash_count >= 2 * strhash_size)
  153. rehash();
  154. jstring* ptr = _Jv_StringGetSlot(this);
  155. if (*ptr != NULL && *ptr != DELETED_STRING)
  156. {
  157. // See description in _Jv_FinalizeString() to understand this.
  158. *ptr = (jstring) MASK_PTR (*ptr);
  159. return (jstring) UNMASK_PTR (*ptr);
  160. }
  161. jstring str = (this->data == this
  162. ? this
  163. : _Jv_NewString(JvGetStringChars(this), this->length()));
  164. SET_STRING_IS_INTERNED(str);
  165. strhash_count++;
  166. *ptr = str;
  167. // When string is GC'd, clear the slot in the hash table.
  168. _Jv_RegisterStringFinalizer (str);
  169. return str;
  170. }
  171. // The fake String finalizer. This is only used when the String has
  172. // been intern()d. However, we must check this case, as it might be
  173. // called by the Reference code for any String.
  174. void
  175. _Jv_FinalizeString (jobject obj)
  176. {
  177. JvSynchronize sync (&java::lang::String::class$);
  178. // We might not actually have intern()d any strings at all, if
  179. // we're being called from Reference.
  180. if (! strhash)
  181. return;
  182. jstring str = reinterpret_cast<jstring> (obj);
  183. jstring *ptr = _Jv_StringGetSlot(str);
  184. if (*ptr == NULL || *ptr == DELETED_STRING
  185. || (jobject) UNMASK_PTR (*ptr) != obj)
  186. return;
  187. // We assume the lowest bit of the pointer is free for our nefarious
  188. // manipulations. What we do is set it to `0' (implicitly) when
  189. // interning the String. If we subsequently re-intern the same
  190. // String, then we set the bit. When finalizing, if the bit is set
  191. // then we clear it and re-register the finalizer. We know this is
  192. // a safe approach because both intern() and _Jv_FinalizeString()
  193. // acquire the class lock; this bit can't be manipulated when the
  194. // lock is not held. So if we are finalizing and the bit is clear
  195. // then we know all references are gone and we can clear the entry
  196. // in the hash table. The naive approach of simply clearing the
  197. // pointer here fails in the case where a request to intern a new
  198. // string with the same contents is made between the time the
  199. // intern()d string is found to be unreachable and when the
  200. // finalizer is actually run. In this case we could clear a pointer
  201. // to a valid string, and future intern() calls for that particular
  202. // value would spuriously fail.
  203. if (PTR_MASKED (*ptr))
  204. {
  205. *ptr = (jstring) UNMASK_PTR (*ptr);
  206. _Jv_RegisterStringFinalizer (obj);
  207. }
  208. else
  209. {
  210. *ptr = DELETED_STRING;
  211. strhash_count--;
  212. }
  213. }
  214. jstring
  215. _Jv_NewStringUTF (const char *bytes)
  216. {
  217. int size = strlen (bytes);
  218. unsigned char *p = (unsigned char *) bytes;
  219. int length = _Jv_strLengthUtf8 ((char *) p, size);
  220. if (length < 0)
  221. return NULL;
  222. jstring jstr = JvAllocString (length);
  223. jchar *chrs = JvGetStringChars (jstr);
  224. p = (unsigned char *) bytes;
  225. unsigned char *limit = p + size;
  226. while (p < limit)
  227. *chrs++ = UTF8_GET (p, limit);
  228. return jstr;
  229. }
  230. jstring
  231. _Jv_NewStringUtf8Const (Utf8Const* str)
  232. {
  233. jchar *chrs;
  234. jchar buffer[100];
  235. jstring jstr;
  236. unsigned char* data = (unsigned char*) str->data;
  237. unsigned char* limit = data + str->length;
  238. int length = _Jv_strLengthUtf8(str->data, str->length);
  239. if (length <= (int) (sizeof(buffer) / sizeof(jchar)))
  240. {
  241. jstr = NULL;
  242. chrs = buffer;
  243. }
  244. else
  245. {
  246. jstr = JvAllocString(length);
  247. chrs = JvGetStringChars(jstr);
  248. }
  249. jint hash = 0;
  250. while (data < limit)
  251. {
  252. jchar ch = UTF8_GET(data, limit);
  253. hash = (31 * hash) + ch;
  254. *chrs++ = ch;
  255. }
  256. chrs -= length;
  257. JvSynchronize sync (&java::lang::String::class$);
  258. if (3 * strhash_count >= 2 * strhash_size)
  259. rehash();
  260. jstring* ptr = _Jv_StringFindSlot (chrs, length, hash);
  261. if (*ptr != NULL && *ptr != DELETED_STRING)
  262. return (jstring) UNMASK_PTR (*ptr);
  263. strhash_count++;
  264. if (jstr == NULL)
  265. {
  266. jstr = JvAllocString(length);
  267. chrs = JvGetStringChars(jstr);
  268. memcpy (chrs, buffer, sizeof(jchar)*length);
  269. }
  270. jstr->cachedHashCode = hash;
  271. *ptr = jstr;
  272. SET_STRING_IS_INTERNED(jstr);
  273. // When string is GC'd, clear the slot in the hash table. Note that
  274. // we don't have to call _Jv_RegisterStringFinalizer here, as we
  275. // know the new object cannot be referred to by a Reference.
  276. _Jv_RegisterFinalizer ((void *) jstr, _Jv_FinalizeString);
  277. return jstr;
  278. }
  279. jsize
  280. _Jv_GetStringUTFLength (jstring string)
  281. {
  282. jsize len = 0;
  283. jchar *ptr = JvGetStringChars (string);
  284. jsize i = string->length();
  285. while (--i >= 0)
  286. {
  287. jchar ch = *ptr++;
  288. if (ch > 0 && ch <= 0x7F)
  289. len += 1;
  290. else if (ch <= 0x7FF)
  291. len += 2;
  292. else
  293. len += 3;
  294. }
  295. return len;
  296. }
  297. // Not sure this quite matches GetStringUTFRegion.
  298. // null-termination of result? len? throw exception?
  299. jsize
  300. _Jv_GetStringUTFRegion (jstring str, jsize start, jsize len, char *buf)
  301. {
  302. jchar *sptr = JvGetStringChars (str) + start;
  303. jsize i = len;
  304. char *dptr = buf;
  305. while (--i >= 0)
  306. {
  307. jchar ch = *sptr++;
  308. if (ch > 0 && ch <= 0x7F)
  309. *dptr++ = (char) ch;
  310. else if (ch <= 0x7FF)
  311. {
  312. *dptr++ = (char) (0xC0 + ((ch >> 6) & 0x1F));
  313. *dptr++ = (char) (0x80 + (ch & 0x3F));
  314. }
  315. else
  316. {
  317. *dptr++ = (char) (0xE0 + ((ch >> 12) & 0xF));
  318. *dptr++ = (char) (0x80 + ((ch >> 6) & 0x3F));
  319. *dptr++ = (char) (0x80 + (ch & 0x3F));
  320. }
  321. }
  322. return dptr - buf;
  323. }
  324. /* Put printed (decimal) representation of NUM in a buffer.
  325. BUFEND marks the end of the buffer, which must be at least 11 jchars long.
  326. Returns the COUNT of jchars written. The result is in
  327. (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive). */
  328. jint
  329. _Jv_FormatInt (jchar* bufend, jint num)
  330. {
  331. register jchar* ptr = bufend;
  332. jboolean isNeg;
  333. if (num < 0)
  334. {
  335. isNeg = true;
  336. if (num != (jint) -2147483648U)
  337. num = -(num);
  338. else
  339. {
  340. // Handle special case of MIN_VALUE.
  341. *--ptr = '8';
  342. num = 214748364;
  343. }
  344. }
  345. else
  346. isNeg = false;
  347. do
  348. {
  349. *--ptr = (jchar) ((int) '0' + (num % 10));
  350. num /= 10;
  351. }
  352. while (num > 0);
  353. if (isNeg)
  354. *--ptr = '-';
  355. return bufend - ptr;
  356. }
  357. jstring
  358. java::lang::String::valueOf (jint num)
  359. {
  360. // Use an array large enough for "-2147483648"; i.e. 11 chars.
  361. jchar buffer[11];
  362. int i = _Jv_FormatInt (buffer+11, num);
  363. return _Jv_NewString (buffer+11-i, i);
  364. }
  365. jstring
  366. _Jv_NewString(const jchar *chars, jsize len)
  367. {
  368. jstring str = _Jv_AllocString(len);
  369. jchar* data = JvGetStringChars (str);
  370. memcpy (data, chars, len * sizeof (jchar));
  371. return str;
  372. }
  373. jstring
  374. _Jv_NewStringLatin1(const char *bytes, jsize len)
  375. {
  376. jstring str = JvAllocString(len);
  377. jchar* data = JvGetStringChars (str);
  378. while (--len >= 0)
  379. *data++ = *(unsigned char*)bytes++;
  380. return str;
  381. }
  382. void
  383. java::lang::String::init(jcharArray chars, jint offset, jint count,
  384. jboolean dont_copy)
  385. {
  386. if (! chars)
  387. throw new NullPointerException;
  388. jsize data_size = JvGetArrayLength (chars);
  389. if (offset < 0 || count < 0 || offset + count < 0
  390. || offset + count > data_size)
  391. throw new ArrayIndexOutOfBoundsException;
  392. jcharArray array;
  393. jchar *pdst;
  394. if (! dont_copy)
  395. {
  396. array = JvNewCharArray(count);
  397. pdst = elements (array);
  398. memcpy (pdst, elements (chars) + offset, count * sizeof (jchar));
  399. }
  400. else
  401. {
  402. array = chars;
  403. pdst = &(elements(array)[offset]);
  404. }
  405. data = array;
  406. boffset = (char *) pdst - (char *) array;
  407. this->count = count;
  408. }
  409. void
  410. java::lang::String::init(jbyteArray ascii, jint hibyte, jint offset,
  411. jint count)
  412. {
  413. if (! ascii)
  414. throw new NullPointerException;
  415. jsize data_size = JvGetArrayLength (ascii);
  416. if (offset < 0 || count < 0 || offset + count < 0
  417. || offset + count > data_size)
  418. throw new ArrayIndexOutOfBoundsException;
  419. jcharArray array = JvNewCharArray(count);
  420. jbyte *psrc = elements (ascii) + offset;
  421. jchar *pdst = elements (array);
  422. data = array;
  423. boffset = (char *) pdst - (char *) array;
  424. this->count = count;
  425. hibyte = (hibyte & 0xff) << 8;
  426. while (-- count >= 0)
  427. {
  428. *pdst++ = hibyte | (*psrc++ & 0xff);
  429. }
  430. }
  431. void
  432. java::lang::String::init (jbyteArray bytes, jint offset, jint count,
  433. jstring encoding)
  434. {
  435. if (! bytes)
  436. throw new NullPointerException;
  437. jsize data_size = JvGetArrayLength (bytes);
  438. if (offset < 0 || count < 0 || offset + count < 0
  439. || offset + count > data_size)
  440. throw new ArrayIndexOutOfBoundsException;
  441. jcharArray array = JvNewCharArray (count);
  442. gnu::gcj::convert::BytesToUnicode *converter
  443. = gnu::gcj::convert::BytesToUnicode::getDecoder(encoding);
  444. jint outpos = 0;
  445. int avail = count;
  446. converter->setInput(bytes, offset, offset+count);
  447. while (converter->inpos < converter->inlength)
  448. {
  449. int done;
  450. try
  451. {
  452. done = converter->read(array, outpos, avail);
  453. }
  454. catch (::java::io::CharConversionException *e)
  455. {
  456. // Ignore it and silently throw away the offending data.
  457. break;
  458. }
  459. if (done == 0)
  460. {
  461. // done is zero if either there is no space available in the
  462. // output *or* the input is incomplete. We assume that if
  463. // there are 20 characters available in the output, the
  464. // input must be incomplete and there is no more work to do.
  465. // This means we may skip several bytes of input, but that
  466. // is OK as the behavior is explicitly unspecified in this
  467. // case.
  468. if (avail - outpos > 20)
  469. break;
  470. jint new_size = 2 * (outpos + avail);
  471. jcharArray new_array = JvNewCharArray (new_size);
  472. memcpy (elements (new_array), elements (array),
  473. outpos * sizeof(jchar));
  474. array = new_array;
  475. avail = new_size - outpos;
  476. }
  477. else
  478. {
  479. outpos += done;
  480. avail -= done;
  481. }
  482. }
  483. converter->done ();
  484. this->data = array;
  485. this->boffset = (char *) elements (array) - (char *) array;
  486. this->count = outpos;
  487. }
  488. void
  489. java::lang::String::init (gnu::gcj::runtime::StringBuffer *buffer)
  490. {
  491. init (buffer->value, 0, buffer->count, true);
  492. }
  493. jboolean
  494. java::lang::String::equals(jobject anObject)
  495. {
  496. if (anObject == NULL)
  497. return false;
  498. if (anObject == this)
  499. return true;
  500. if (anObject->getClass() != &java::lang::String::class$)
  501. return false;
  502. jstring other = (jstring) anObject;
  503. if (count != other->count)
  504. return false;
  505. // If both have cached hash codes, check that. If the cached hash
  506. // codes are zero, don't bother trying to compute them.
  507. int myHash = cachedHashCode;
  508. int otherHash = other->cachedHashCode;
  509. if (myHash && otherHash && myHash != otherHash)
  510. return false;
  511. // We could see if both are interned, and return false. But that
  512. // seems too expensive.
  513. jchar *xptr = JvGetStringChars (this);
  514. jchar *yptr = JvGetStringChars (other);
  515. return ! memcmp (xptr, yptr, count * sizeof (jchar));
  516. }
  517. jboolean
  518. java::lang::String::contentEquals(java::lang::StringBuffer* buffer)
  519. {
  520. if (buffer == NULL)
  521. throw new NullPointerException;
  522. JvSynchronize sync(buffer);
  523. if (count != buffer->count)
  524. return false;
  525. if (data == buffer->value)
  526. return true; // Possible if shared.
  527. jchar *xptr = JvGetStringChars(this);
  528. jchar *yptr = elements(buffer->value);
  529. return ! memcmp (xptr, yptr, count * sizeof (jchar));
  530. }
  531. jboolean
  532. java::lang::String::contentEquals(java::lang::CharSequence *seq)
  533. {
  534. if (seq->length() != count)
  535. return false;
  536. jchar *value = JvGetStringChars(this);
  537. for (int i = 0; i < count; ++i)
  538. if (value[i] != seq->charAt(i))
  539. return false;
  540. return true;
  541. }
  542. jchar
  543. java::lang::String::charAt(jint i)
  544. {
  545. if (i < 0 || i >= count)
  546. throw new java::lang::StringIndexOutOfBoundsException(i);
  547. return JvGetStringChars(this)[i];
  548. }
  549. void
  550. java::lang::String::getChars(jint srcBegin, jint srcEnd,
  551. jcharArray dst, jint dstBegin)
  552. {
  553. jint dst_length = JvGetArrayLength (dst);
  554. if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
  555. throw new java::lang::StringIndexOutOfBoundsException;
  556. // The 2nd part of the test below is equivalent to
  557. // dstBegin + (srcEnd-srcBegin) > dst_length
  558. // except that it does not overflow.
  559. if (dstBegin < 0 || dstBegin > dst_length - (srcEnd-srcBegin))
  560. throw new ArrayIndexOutOfBoundsException;
  561. jchar *dPtr = elements (dst) + dstBegin;
  562. jchar *sPtr = JvGetStringChars (this) + srcBegin;
  563. jint i = srcEnd - srcBegin;
  564. memcpy (dPtr, sPtr, i * sizeof (jchar));
  565. }
  566. jbyteArray
  567. java::lang::String::getBytes (jstring enc)
  568. {
  569. jint todo = length();
  570. jint buflen = todo;
  571. jbyteArray buffer = JvNewByteArray(todo);
  572. jint bufpos = 0;
  573. jint offset = 0;
  574. gnu::gcj::convert::UnicodeToBytes *converter
  575. = gnu::gcj::convert::UnicodeToBytes::getEncoder(enc);
  576. while (todo > 0 || converter->havePendingBytes())
  577. {
  578. converter->setOutput(buffer, bufpos);
  579. int converted = converter->write(this, offset, todo, NULL);
  580. bufpos = converter->count;
  581. if (converted == 0)
  582. {
  583. buflen *= 2;
  584. jbyteArray newbuffer = JvNewByteArray(buflen);
  585. memcpy (elements (newbuffer), elements (buffer), bufpos);
  586. buffer = newbuffer;
  587. }
  588. else
  589. {
  590. offset += converted;
  591. todo -= converted;
  592. }
  593. }
  594. if (length() > 0)
  595. {
  596. converter->setFinished();
  597. converter->write(this, 0, 0, NULL);
  598. }
  599. converter->done ();
  600. if (bufpos == buflen)
  601. return buffer;
  602. jbyteArray result = JvNewByteArray(bufpos);
  603. memcpy (elements (result), elements (buffer), bufpos);
  604. return result;
  605. }
  606. void
  607. java::lang::String::getBytes(jint srcBegin, jint srcEnd,
  608. jbyteArray dst, jint dstBegin)
  609. {
  610. jint dst_length = JvGetArrayLength (dst);
  611. if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count)
  612. throw new java::lang::StringIndexOutOfBoundsException;
  613. // The 2nd part of the test below is equivalent to
  614. // dstBegin + (srcEnd-srcBegin) > dst_length
  615. // except that it does not overflow.
  616. if (dstBegin < 0 || dstBegin > dst_length - (srcEnd-srcBegin))
  617. throw new ArrayIndexOutOfBoundsException;
  618. jbyte *dPtr = elements (dst) + dstBegin;
  619. jchar *sPtr = JvGetStringChars (this) + srcBegin;
  620. jint i = srcEnd-srcBegin;
  621. while (--i >= 0)
  622. *dPtr++ = (jbyte) *sPtr++;
  623. }
  624. jcharArray
  625. java::lang::String::toCharArray()
  626. {
  627. jcharArray array = JvNewCharArray(count);
  628. jchar *dPtr = elements (array);
  629. jchar *sPtr = JvGetStringChars (this);
  630. jint i = count;
  631. memcpy (dPtr, sPtr, i * sizeof (jchar));
  632. return array;
  633. }
  634. jboolean
  635. java::lang::String::equalsIgnoreCase (jstring anotherString)
  636. {
  637. if (anotherString == NULL || count != anotherString->count)
  638. return false;
  639. jchar *tptr = JvGetStringChars (this);
  640. jchar *optr = JvGetStringChars (anotherString);
  641. jint i = count;
  642. while (--i >= 0)
  643. {
  644. jchar tch = *tptr++;
  645. jchar och = *optr++;
  646. if (tch != och
  647. && (java::lang::Character::toLowerCase (tch)
  648. != java::lang::Character::toLowerCase (och))
  649. && (java::lang::Character::toUpperCase (tch)
  650. != java::lang::Character::toUpperCase (och)))
  651. return false;
  652. }
  653. return true;
  654. }
  655. jboolean
  656. java::lang::String::regionMatches (jint toffset,
  657. jstring other, jint ooffset, jint len)
  658. {
  659. if (toffset < 0 || ooffset < 0 || len < 0
  660. || toffset > count - len
  661. || ooffset > other->count - len)
  662. return false;
  663. jchar *tptr = JvGetStringChars (this) + toffset;
  664. jchar *optr = JvGetStringChars (other) + ooffset;
  665. jint i = len;
  666. return ! memcmp (tptr, optr, i * sizeof (jchar));
  667. }
  668. jint
  669. java::lang::String::nativeCompareTo (jstring anotherString)
  670. {
  671. jchar *tptr = JvGetStringChars (this);
  672. jchar *optr = JvGetStringChars (anotherString);
  673. jint tlen = this->count;
  674. jint olen = anotherString->count;
  675. jint i = tlen > olen ? olen : tlen;
  676. while (--i >= 0)
  677. {
  678. jchar tch = *tptr++;
  679. jchar och = *optr++;
  680. if (tch != och)
  681. return (jint) tch - (jint) och;
  682. }
  683. return tlen - olen;
  684. }
  685. jboolean
  686. java::lang::String::regionMatches (jboolean ignoreCase, jint toffset,
  687. jstring other, jint ooffset, jint len)
  688. {
  689. if (toffset < 0 || ooffset < 0 || len < 0
  690. || toffset > count - len
  691. || ooffset > other->count - len)
  692. return false;
  693. jchar *tptr = JvGetStringChars (this) + toffset;
  694. jchar *optr = JvGetStringChars (other) + ooffset;
  695. jint i = len;
  696. if (ignoreCase)
  697. {
  698. while (--i >= 0)
  699. {
  700. jchar tch = *tptr++;
  701. jchar och = *optr++;
  702. if ((java::lang::Character::toLowerCase (tch)
  703. != java::lang::Character::toLowerCase (och))
  704. && (java::lang::Character::toUpperCase (tch)
  705. != java::lang::Character::toUpperCase (och)))
  706. return false;
  707. }
  708. return true;
  709. }
  710. return ! memcmp (tptr, optr, i * sizeof (jchar));
  711. }
  712. jboolean
  713. java::lang::String::startsWith (jstring prefix, jint toffset)
  714. {
  715. jint i = prefix->count;
  716. if (toffset < 0 || toffset > count - i)
  717. return false;
  718. jchar *xptr = JvGetStringChars (this) + toffset;
  719. jchar *yptr = JvGetStringChars (prefix);
  720. return ! memcmp (xptr, yptr, i * sizeof (jchar));
  721. }
  722. jint
  723. java::lang::String::indexOf (jint ch, jint fromIndex)
  724. {
  725. if (fromIndex < 0)
  726. fromIndex = 0;
  727. jchar *ptr = JvGetStringChars(this);
  728. for (;; ++fromIndex)
  729. {
  730. if (fromIndex >= count)
  731. return -1;
  732. if (ptr[fromIndex] == ch)
  733. return fromIndex;
  734. }
  735. }
  736. jint
  737. java::lang::String::indexOf (jstring s, jint fromIndex)
  738. {
  739. const jchar *const xchars = JvGetStringChars(s);
  740. const jchar *const ychars = JvGetStringChars(this) + fromIndex;
  741. const int xlength = s->length ();
  742. const int ylength = length () - fromIndex;
  743. int i = 0;
  744. int j = 0;
  745. while (i < ylength && j < xlength)
  746. {
  747. if (xchars[j] != ychars[i])
  748. {
  749. i = i - j + 1;
  750. j = 0;
  751. }
  752. else
  753. i++, j++;
  754. }
  755. if (j >= xlength)
  756. return fromIndex + i - xlength;
  757. else
  758. return -1;
  759. }
  760. jint
  761. java::lang::String::lastIndexOf (jint ch, jint fromIndex)
  762. {
  763. if (fromIndex >= count)
  764. fromIndex = count - 1;
  765. jchar *ptr = JvGetStringChars(this);
  766. for (;; --fromIndex)
  767. {
  768. if (fromIndex < 0)
  769. return -1;
  770. if (ptr[fromIndex] == ch)
  771. return fromIndex;
  772. }
  773. }
  774. jstring
  775. java::lang::String::substring (jint beginIndex, jint endIndex)
  776. {
  777. if (beginIndex < 0 || endIndex > count || beginIndex > endIndex)
  778. throw new StringIndexOutOfBoundsException;
  779. if (beginIndex == 0 && endIndex == count)
  780. return this;
  781. jint newCount = endIndex - beginIndex;
  782. // For very small strings, just allocate a new one. For other
  783. // substrings, allocate a new one unless the substring is over half
  784. // of the original string.
  785. if (newCount <= 8 || newCount < (count >> 1))
  786. return JvNewString(JvGetStringChars(this) + beginIndex, newCount);
  787. jstring s = new String();
  788. s->data = data;
  789. s->count = newCount;
  790. s->boffset = boffset + sizeof(jchar) * beginIndex;
  791. return s;
  792. }
  793. jstring
  794. java::lang::String::concat(jstring str)
  795. {
  796. jint str_count = str->count;
  797. if (str_count == 0)
  798. return this;
  799. jstring result = JvAllocString(count + str_count);
  800. jchar *dstPtr = JvGetStringChars(result);
  801. jchar *srcPtr = JvGetStringChars(this);
  802. jint i = count;
  803. memcpy (dstPtr, srcPtr, i * sizeof (jchar));
  804. dstPtr += i;
  805. srcPtr = JvGetStringChars(str);
  806. i = str->count;
  807. memcpy (dstPtr, srcPtr, i * sizeof (jchar));
  808. return result;
  809. }
  810. jstring
  811. java::lang::String::replace (jchar oldChar, jchar newChar)
  812. {
  813. jint i;
  814. jchar* chrs = JvGetStringChars (this);
  815. for (i = 0; ; i++)
  816. {
  817. if (i == count)
  818. return this;
  819. if (chrs[i] == oldChar)
  820. break;
  821. }
  822. jstring result = JvAllocString (count);
  823. jchar *dPtr = JvGetStringChars (result);
  824. for (int j = 0; j < i; j++)
  825. *dPtr++ = chrs[j];
  826. for (; i < count; i++)
  827. {
  828. jchar ch = chrs[i];
  829. if (ch == oldChar)
  830. ch = newChar;
  831. *dPtr++ = ch;
  832. }
  833. return result;
  834. }
  835. jstring
  836. java::lang::String::toLowerCase (java::util::Locale *locale)
  837. {
  838. jint i;
  839. jchar* chrs = JvGetStringChars(this);
  840. jchar ch = 0;
  841. bool handle_tr = false;
  842. if (locale != NULL)
  843. {
  844. String *lang = locale->getLanguage ();
  845. if (lang->length () == 2
  846. && lang->charAt (0) == 't'
  847. && lang->charAt (1) == 'r')
  848. handle_tr = true;
  849. }
  850. for (i = 0; ; i++)
  851. {
  852. if (i == count)
  853. return this;
  854. jchar origChar = chrs[i];
  855. if (handle_tr && (origChar == CAPITAL_I
  856. || origChar == CAPITAL_I_WITH_DOT))
  857. break;
  858. ch = java::lang::Character::toLowerCase(origChar);
  859. if (ch != origChar)
  860. break;
  861. }
  862. jstring result = JvAllocString(count);
  863. jchar *dPtr = JvGetStringChars (result);
  864. for (int j = 0; j < i; j++)
  865. *dPtr++ = chrs[j];
  866. *dPtr++ = ch; i++;
  867. for (; i < count; i++)
  868. {
  869. if (handle_tr && chrs[i] == CAPITAL_I)
  870. *dPtr++ = SMALL_DOTLESS_I;
  871. else if (handle_tr && chrs[i] == CAPITAL_I_WITH_DOT)
  872. *dPtr++ = SMALL_I;
  873. else
  874. *dPtr++ = java::lang::Character::toLowerCase(chrs[i]);
  875. }
  876. return result;
  877. }
  878. jstring
  879. java::lang::String::toUpperCase (java::util::Locale *locale)
  880. {
  881. jint i;
  882. jchar* chrs = JvGetStringChars(this);
  883. jchar ch;
  884. // When handling a specific locale there might be special rules.
  885. // Currently all existing rules are simply handled inline, as there
  886. // are only two and they are documented in the online 1.2 docs.
  887. bool handle_esset = locale != NULL;
  888. bool handle_tr = false;
  889. if (locale != NULL)
  890. {
  891. String *lang = locale->getLanguage ();
  892. if (lang->length () == 2
  893. && lang->charAt (0) == 't'
  894. && lang->charAt (1) == 'r')
  895. handle_tr = true;
  896. }
  897. int new_count = count;
  898. bool new_string = false;
  899. for (i = 0; ; i++)
  900. {
  901. if (i == count)
  902. break;
  903. jchar origChar = chrs[i];
  904. if (handle_esset && origChar == ESSET)
  905. {
  906. ++new_count;
  907. new_string = true;
  908. }
  909. else if (handle_tr && (origChar == SMALL_I
  910. || origChar == SMALL_DOTLESS_I))
  911. new_string = true;
  912. else
  913. {
  914. ch = java::lang::Character::toUpperCase(origChar);
  915. if (ch != origChar)
  916. new_string = true;
  917. }
  918. if (new_string && ! handle_esset)
  919. break;
  920. }
  921. if (! new_string)
  922. return this;
  923. jstring result = JvAllocString(new_count);
  924. jchar *dPtr = JvGetStringChars (result);
  925. for (i = 0; i < count; i++)
  926. {
  927. if (handle_esset && chrs[i] == ESSET)
  928. {
  929. *dPtr++ = CAPITAL_S;
  930. *dPtr++ = CAPITAL_S;
  931. }
  932. else if (handle_tr && chrs[i] == SMALL_I)
  933. *dPtr++ = CAPITAL_I_WITH_DOT;
  934. else if (handle_tr && chrs[i] == SMALL_DOTLESS_I)
  935. *dPtr++ = CAPITAL_I;
  936. else
  937. *dPtr++ = java::lang::Character::toUpperCase(chrs[i]);
  938. }
  939. return result;
  940. }
  941. jstring
  942. java::lang::String::trim ()
  943. {
  944. jchar* chrs = JvGetStringChars(this);
  945. if (count == 0 || (chrs[0] > ' ' && chrs[count-1] > ' '))
  946. return this;
  947. jint preTrim = 0;
  948. for (;; preTrim++)
  949. {
  950. if (preTrim == count)
  951. return new String();
  952. if (chrs[preTrim] > ' ')
  953. break;
  954. }
  955. jint endTrim = count;
  956. while (chrs[endTrim-1] <= ' ')
  957. endTrim--;
  958. return substring(preTrim, endTrim);
  959. }
  960. jstring
  961. java::lang::String::valueOf(jcharArray data, jint offset, jint count)
  962. {
  963. jint data_length = JvGetArrayLength (data);
  964. if (offset < 0 || count < 0 || offset > data_length - count)
  965. throw new ArrayIndexOutOfBoundsException;
  966. jstring result = JvAllocString(count);
  967. jchar *sPtr = elements (data) + offset;
  968. jchar *dPtr = JvGetStringChars(result);
  969. memcpy (dPtr, sPtr, count * sizeof (jchar));
  970. return result;
  971. }
  972. jstring
  973. java::lang::String::valueOf(jchar c)
  974. {
  975. jstring result = JvAllocString(1);
  976. JvGetStringChars (result)[0] = c;
  977. return result;
  978. }