nsTStringObsolete.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsTArray.h"
  6. /**
  7. * nsTString::Find
  8. *
  9. * aOffset specifies starting index
  10. * aCount specifies number of string compares (iterations)
  11. */
  12. int32_t
  13. nsTString_CharT::Find( const nsCString& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const
  14. {
  15. // this method changes the meaning of aOffset and aCount:
  16. Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
  17. int32_t result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase);
  18. if (result != kNotFound)
  19. result += aOffset;
  20. return result;
  21. }
  22. int32_t
  23. nsTString_CharT::Find( const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const
  24. {
  25. return Find(nsDependentCString(aString), aIgnoreCase, aOffset, aCount);
  26. }
  27. /**
  28. * nsTString::RFind
  29. *
  30. * aOffset specifies starting index
  31. * aCount specifies number of string compares (iterations)
  32. */
  33. int32_t
  34. nsTString_CharT::RFind( const nsCString& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const
  35. {
  36. // this method changes the meaning of aOffset and aCount:
  37. RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
  38. int32_t result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase);
  39. if (result != kNotFound)
  40. result += aOffset;
  41. return result;
  42. }
  43. int32_t
  44. nsTString_CharT::RFind( const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const
  45. {
  46. return RFind(nsDependentCString(aString), aIgnoreCase, aOffset, aCount);
  47. }
  48. /**
  49. * nsTString::RFindChar
  50. */
  51. int32_t
  52. nsTString_CharT::RFindChar( char16_t aChar, int32_t aOffset, int32_t aCount) const
  53. {
  54. return nsBufferRoutines<CharT>::rfind_char(mData, mLength, aOffset, aChar, aCount);
  55. }
  56. /**
  57. * nsTString::FindCharInSet
  58. */
  59. int32_t
  60. nsTString_CharT::FindCharInSet( const char* aSet, int32_t aOffset ) const
  61. {
  62. if (aOffset < 0)
  63. aOffset = 0;
  64. else if (aOffset >= int32_t(mLength))
  65. return kNotFound;
  66. int32_t result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet);
  67. if (result != kNotFound)
  68. result += aOffset;
  69. return result;
  70. }
  71. /**
  72. * nsTString::RFindCharInSet
  73. */
  74. int32_t
  75. nsTString_CharT::RFindCharInSet( const CharT* aSet, int32_t aOffset ) const
  76. {
  77. // We want to pass a "data length" to ::RFindCharInSet
  78. if (aOffset < 0 || aOffset > int32_t(mLength))
  79. aOffset = mLength;
  80. else
  81. ++aOffset;
  82. return ::RFindCharInSet(mData, aOffset, aSet);
  83. }
  84. // it's a shame to replicate this code. it was done this way in the past
  85. // to help performance. this function also gets to keep the rickg style
  86. // indentation :-/
  87. int32_t
  88. nsTString_CharT::ToInteger( nsresult* aErrorCode, uint32_t aRadix ) const
  89. {
  90. CharT* cp=mData;
  91. int32_t theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect)
  92. int32_t result=0;
  93. bool negate=false;
  94. CharT theChar=0;
  95. //initial value, override if we find an integer
  96. *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
  97. if(cp) {
  98. //begin by skipping over leading chars that shouldn't be part of the number...
  99. CharT* endcp=cp+mLength;
  100. bool done=false;
  101. while((cp<endcp) && (!done)){
  102. switch(*cp++) {
  103. case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  104. case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  105. theRadix=16;
  106. done=true;
  107. break;
  108. case '0': case '1': case '2': case '3': case '4':
  109. case '5': case '6': case '7': case '8': case '9':
  110. done=true;
  111. break;
  112. case '-':
  113. negate=true; //fall through...
  114. break;
  115. case 'X': case 'x':
  116. theRadix=16;
  117. break;
  118. default:
  119. break;
  120. } //switch
  121. }
  122. if (done) {
  123. //integer found
  124. *aErrorCode = NS_OK;
  125. if (aRadix!=kAutoDetect) theRadix = aRadix; // override
  126. //now iterate the numeric chars and build our result
  127. CharT* first=--cp; //in case we have to back up.
  128. bool haveValue = false;
  129. while(cp<endcp){
  130. int32_t oldresult = result;
  131. theChar=*cp++;
  132. if(('0'<=theChar) && (theChar<='9')){
  133. result = (theRadix * result) + (theChar-'0');
  134. haveValue = true;
  135. }
  136. else if((theChar>='A') && (theChar<='F')) {
  137. if(10==theRadix) {
  138. if(kAutoDetect==aRadix){
  139. theRadix=16;
  140. cp=first; //backup
  141. result=0;
  142. haveValue = false;
  143. }
  144. else {
  145. *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
  146. result=0;
  147. break;
  148. }
  149. }
  150. else {
  151. result = (theRadix * result) + ((theChar-'A')+10);
  152. haveValue = true;
  153. }
  154. }
  155. else if((theChar>='a') && (theChar<='f')) {
  156. if(10==theRadix) {
  157. if(kAutoDetect==aRadix){
  158. theRadix=16;
  159. cp=first; //backup
  160. result=0;
  161. haveValue = false;
  162. }
  163. else {
  164. *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
  165. result=0;
  166. break;
  167. }
  168. }
  169. else {
  170. result = (theRadix * result) + ((theChar-'a')+10);
  171. haveValue = true;
  172. }
  173. }
  174. else if((('X'==theChar) || ('x'==theChar)) && (!haveValue || result == 0)) {
  175. continue;
  176. }
  177. else if((('#'==theChar) || ('+'==theChar)) && !haveValue) {
  178. continue;
  179. }
  180. else {
  181. //we've encountered a char that's not a legal number or sign
  182. break;
  183. }
  184. if (result < oldresult) {
  185. // overflow!
  186. *aErrorCode = NS_ERROR_ILLEGAL_VALUE;
  187. result = 0;
  188. break;
  189. }
  190. } //while
  191. if(negate)
  192. result=-result;
  193. } //if
  194. }
  195. return result;
  196. }
  197. /**
  198. * nsTString::ToInteger64
  199. */
  200. int64_t
  201. nsTString_CharT::ToInteger64( nsresult* aErrorCode, uint32_t aRadix ) const
  202. {
  203. CharT* cp=mData;
  204. int32_t theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect)
  205. int64_t result=0;
  206. bool negate=false;
  207. CharT theChar=0;
  208. //initial value, override if we find an integer
  209. *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
  210. if(cp) {
  211. //begin by skipping over leading chars that shouldn't be part of the number...
  212. CharT* endcp=cp+mLength;
  213. bool done=false;
  214. while((cp<endcp) && (!done)){
  215. switch(*cp++) {
  216. case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  217. case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  218. theRadix=16;
  219. done=true;
  220. break;
  221. case '0': case '1': case '2': case '3': case '4':
  222. case '5': case '6': case '7': case '8': case '9':
  223. done=true;
  224. break;
  225. case '-':
  226. negate=true; //fall through...
  227. break;
  228. case 'X': case 'x':
  229. theRadix=16;
  230. break;
  231. default:
  232. break;
  233. } //switch
  234. }
  235. if (done) {
  236. //integer found
  237. *aErrorCode = NS_OK;
  238. if (aRadix!=kAutoDetect) theRadix = aRadix; // override
  239. //now iterate the numeric chars and build our result
  240. CharT* first=--cp; //in case we have to back up.
  241. bool haveValue = false;
  242. while(cp<endcp){
  243. int64_t oldresult = result;
  244. theChar=*cp++;
  245. if(('0'<=theChar) && (theChar<='9')){
  246. result = (theRadix * result) + (theChar-'0');
  247. haveValue = true;
  248. }
  249. else if((theChar>='A') && (theChar<='F')) {
  250. if(10==theRadix) {
  251. if(kAutoDetect==aRadix){
  252. theRadix=16;
  253. cp=first; //backup
  254. result=0;
  255. haveValue = false;
  256. }
  257. else {
  258. *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
  259. result=0;
  260. break;
  261. }
  262. }
  263. else {
  264. result = (theRadix * result) + ((theChar-'A')+10);
  265. haveValue = true;
  266. }
  267. }
  268. else if((theChar>='a') && (theChar<='f')) {
  269. if(10==theRadix) {
  270. if(kAutoDetect==aRadix){
  271. theRadix=16;
  272. cp=first; //backup
  273. result=0;
  274. haveValue = false;
  275. }
  276. else {
  277. *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
  278. result=0;
  279. break;
  280. }
  281. }
  282. else {
  283. result = (theRadix * result) + ((theChar-'a')+10);
  284. haveValue = true;
  285. }
  286. }
  287. else if((('X'==theChar) || ('x'==theChar)) && (!haveValue || result == 0)) {
  288. continue;
  289. }
  290. else if((('#'==theChar) || ('+'==theChar)) && !haveValue) {
  291. continue;
  292. }
  293. else {
  294. //we've encountered a char that's not a legal number or sign
  295. break;
  296. }
  297. if (result < oldresult) {
  298. // overflow!
  299. *aErrorCode = NS_ERROR_ILLEGAL_VALUE;
  300. result = 0;
  301. break;
  302. }
  303. } //while
  304. if(negate)
  305. result=-result;
  306. } //if
  307. }
  308. return result;
  309. }
  310. /**
  311. * nsTString::Mid
  312. */
  313. uint32_t
  314. nsTString_CharT::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const
  315. {
  316. if (aStartPos == 0 && aLengthToCopy >= mLength)
  317. aResult = *this;
  318. else
  319. aResult = Substring(*this, aStartPos, aLengthToCopy);
  320. return aResult.mLength;
  321. }
  322. /**
  323. * nsTString::SetCharAt
  324. */
  325. bool
  326. nsTString_CharT::SetCharAt( char16_t aChar, uint32_t aIndex )
  327. {
  328. if (aIndex >= mLength)
  329. return false;
  330. if (!EnsureMutable())
  331. AllocFailed(mLength);
  332. mData[aIndex] = CharT(aChar);
  333. return true;
  334. }
  335. /**
  336. * nsTString::StripChars,StripChar,StripWhitespace
  337. */
  338. void
  339. nsTString_CharT::StripChars( const char* aSet )
  340. {
  341. if (!EnsureMutable())
  342. AllocFailed(mLength);
  343. mLength = nsBufferRoutines<CharT>::strip_chars(mData, mLength, aSet);
  344. }
  345. bool
  346. nsTString_CharT::StripChars( const char* aSet, const fallible_t& )
  347. {
  348. if (!EnsureMutable()) {
  349. return false;
  350. }
  351. mLength = nsBufferRoutines<CharT>::strip_chars(mData, mLength, aSet);
  352. return true;
  353. }
  354. void
  355. nsTString_CharT::StripWhitespace()
  356. {
  357. StripChars(kWhitespace);
  358. }
  359. bool
  360. nsTString_CharT::StripWhitespace(const fallible_t& aFallible)
  361. {
  362. return StripChars(kWhitespace, aFallible);
  363. }
  364. /**
  365. * nsTString::ReplaceChar,ReplaceSubstring
  366. */
  367. void
  368. nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar )
  369. {
  370. if (!EnsureMutable()) // XXX do this lazily?
  371. AllocFailed(mLength);
  372. for (uint32_t i=0; i<mLength; ++i)
  373. {
  374. if (mData[i] == aOldChar)
  375. mData[i] = aNewChar;
  376. }
  377. }
  378. void
  379. nsTString_CharT::ReplaceChar( const char* aSet, char_type aNewChar )
  380. {
  381. if (!EnsureMutable()) // XXX do this lazily?
  382. AllocFailed(mLength);
  383. char_type* data = mData;
  384. uint32_t lenRemaining = mLength;
  385. while (lenRemaining)
  386. {
  387. int32_t i = ::FindCharInSet(data, lenRemaining, aSet);
  388. if (i == kNotFound)
  389. break;
  390. data[i++] = aNewChar;
  391. data += i;
  392. lenRemaining -= i;
  393. }
  394. }
  395. void ReleaseData(void* aData, uint32_t aFlags);
  396. void
  397. nsTString_CharT::ReplaceSubstring(const char_type* aTarget,
  398. const char_type* aNewValue)
  399. {
  400. ReplaceSubstring(nsTDependentString_CharT(aTarget),
  401. nsTDependentString_CharT(aNewValue));
  402. }
  403. bool
  404. nsTString_CharT::ReplaceSubstring(const char_type* aTarget,
  405. const char_type* aNewValue,
  406. const fallible_t& aFallible)
  407. {
  408. return ReplaceSubstring(nsTDependentString_CharT(aTarget),
  409. nsTDependentString_CharT(aNewValue),
  410. aFallible);
  411. }
  412. void
  413. nsTString_CharT::ReplaceSubstring(const self_type& aTarget,
  414. const self_type& aNewValue)
  415. {
  416. if (!ReplaceSubstring(aTarget, aNewValue, mozilla::fallible)) {
  417. // Note that this may wildly underestimate the allocation that failed, as
  418. // we could have been replacing multiple copies of aTarget.
  419. AllocFailed(mLength + (aNewValue.Length() - aTarget.Length()));
  420. }
  421. }
  422. bool
  423. nsTString_CharT::ReplaceSubstring(const self_type& aTarget,
  424. const self_type& aNewValue,
  425. const fallible_t&)
  426. {
  427. if (aTarget.Length() == 0)
  428. return true;
  429. // Remember all of the non-matching parts.
  430. AutoTArray<Segment, 16> nonMatching;
  431. uint32_t i = 0;
  432. uint32_t newLength = 0;
  433. while (true)
  434. {
  435. int32_t r = FindSubstring(mData + i, mLength - i, static_cast<const char_type*>(aTarget.Data()), aTarget.Length(), false);
  436. int32_t until = (r == kNotFound) ? mLength - i : r;
  437. nonMatching.AppendElement(Segment(i, until));
  438. newLength += until;
  439. if (r == kNotFound) {
  440. break;
  441. }
  442. newLength += aNewValue.Length();
  443. i += r + aTarget.Length();
  444. if (i >= mLength) {
  445. // Add an auxiliary entry at the end of the list to help as an edge case
  446. // for the algorithms below.
  447. nonMatching.AppendElement(Segment(mLength, 0));
  448. break;
  449. }
  450. }
  451. // If there's only one non-matching segment, then the target string was not
  452. // found, and there's nothing to do.
  453. if (nonMatching.Length() == 1) {
  454. MOZ_ASSERT(nonMatching[0].mBegin == 0 && nonMatching[0].mLength == mLength,
  455. "We should have the correct non-matching segment.");
  456. return true;
  457. }
  458. // Make sure that we can mutate our buffer.
  459. // Note that we always allocate at least an mLength sized buffer, because the
  460. // rest of the algorithm relies on having access to all of the original
  461. // string. In other words, we over-allocate in the shrinking case.
  462. char_type* oldData;
  463. uint32_t oldFlags;
  464. if (!MutatePrep(XPCOM_MAX(mLength, newLength), &oldData, &oldFlags))
  465. return false;
  466. if (oldData) {
  467. // Copy all of the old data to the new buffer.
  468. char_traits::copy(mData, oldData, mLength);
  469. ::ReleaseData(oldData, oldFlags);
  470. }
  471. if (aTarget.Length() >= aNewValue.Length()) {
  472. // In the shrinking case, start filling the buffer from the beginning.
  473. const uint32_t delta = (aTarget.Length() - aNewValue.Length());
  474. for (i = 1; i < nonMatching.Length(); ++i) {
  475. // When we move the i'th non-matching segment into position, we need to
  476. // account for the characters deleted by the previous |i| replacements by
  477. // subtracting |i * delta|.
  478. const char_type* sourceSegmentPtr = mData + nonMatching[i].mBegin;
  479. char_type* destinationSegmentPtr = mData + nonMatching[i].mBegin - i * delta;
  480. // Write the i'th replacement immediately before the new i'th non-matching
  481. // segment.
  482. char_traits::copy(destinationSegmentPtr - aNewValue.Length(),
  483. aNewValue.Data(), aNewValue.Length());
  484. char_traits::move(destinationSegmentPtr, sourceSegmentPtr,
  485. nonMatching[i].mLength);
  486. }
  487. } else {
  488. // In the growing case, start filling the buffer from the end.
  489. const uint32_t delta = (aNewValue.Length() - aTarget.Length());
  490. for (i = nonMatching.Length() - 1; i > 0; --i) {
  491. // When we move the i'th non-matching segment into position, we need to
  492. // account for the characters added by the previous |i| replacements by
  493. // adding |i * delta|.
  494. const char_type* sourceSegmentPtr = mData + nonMatching[i].mBegin;
  495. char_type* destinationSegmentPtr = mData + nonMatching[i].mBegin + i * delta;
  496. char_traits::move(destinationSegmentPtr, sourceSegmentPtr,
  497. nonMatching[i].mLength);
  498. // Write the i'th replacement immediately before the new i'th non-matching
  499. // segment.
  500. char_traits::copy(destinationSegmentPtr - aNewValue.Length(),
  501. aNewValue.Data(), aNewValue.Length());
  502. }
  503. }
  504. // Adjust the length and make sure the string is null terminated.
  505. mLength = newLength;
  506. mData[mLength] = char_type(0);
  507. return true;
  508. }
  509. /**
  510. * nsTString::Trim
  511. */
  512. void
  513. nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, bool aIgnoreQuotes )
  514. {
  515. // the old implementation worried about aSet being null :-/
  516. if (!aSet)
  517. return;
  518. char_type* start = mData;
  519. char_type* end = mData + mLength;
  520. // skip over quotes if requested
  521. if (aIgnoreQuotes && mLength > 2 && mData[0] == mData[mLength - 1] &&
  522. (mData[0] == '\'' || mData[0] == '"'))
  523. {
  524. ++start;
  525. --end;
  526. }
  527. uint32_t setLen = nsCharTraits<char>::length(aSet);
  528. if (aTrimLeading)
  529. {
  530. uint32_t cutStart = start - mData;
  531. uint32_t cutLength = 0;
  532. // walk forward from start to end
  533. for (; start != end; ++start, ++cutLength)
  534. {
  535. int32_t pos = FindChar1(aSet, setLen, 0, *start, setLen);
  536. if (pos == kNotFound)
  537. break;
  538. }
  539. if (cutLength)
  540. {
  541. Cut(cutStart, cutLength);
  542. // reset iterators
  543. start = mData + cutStart;
  544. end = mData + mLength - cutStart;
  545. }
  546. }
  547. if (aTrimTrailing)
  548. {
  549. uint32_t cutEnd = end - mData;
  550. uint32_t cutLength = 0;
  551. // walk backward from end to start
  552. --end;
  553. for (; end >= start; --end, ++cutLength)
  554. {
  555. int32_t pos = FindChar1(aSet, setLen, 0, *end, setLen);
  556. if (pos == kNotFound)
  557. break;
  558. }
  559. if (cutLength)
  560. Cut(cutEnd - cutLength, cutLength);
  561. }
  562. }
  563. /**
  564. * nsTString::CompressWhitespace
  565. */
  566. void
  567. nsTString_CharT::CompressWhitespace( bool aTrimLeading, bool aTrimTrailing )
  568. {
  569. const char* set = kWhitespace;
  570. ReplaceChar(set, ' ');
  571. Trim(set, aTrimLeading, aTrimTrailing);
  572. // this one does some questionable fu... just copying the old code!
  573. mLength = nsBufferRoutines<char_type>::compress_chars(mData, mLength, set);
  574. }
  575. /**
  576. * nsTString::AssignWithConversion
  577. */
  578. void
  579. nsTString_CharT::AssignWithConversion( const incompatible_char_type* aData, int32_t aLength )
  580. {
  581. // for compatibility with the old string implementation, we need to allow
  582. // for a nullptr input buffer :-(
  583. if (!aData)
  584. {
  585. Truncate();
  586. }
  587. else
  588. {
  589. if (aLength < 0)
  590. aLength = nsCharTraits<incompatible_char_type>::length(aData);
  591. AssignWithConversion(Substring(aData, aLength));
  592. }
  593. }