The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

533 lines
17KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__
  19. #define __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__
  20. //==============================================================================
  21. #if JUCE_WINDOWS && ! DOXYGEN
  22. #define JUCE_NATIVE_WCHAR_IS_UTF8 0
  23. #define JUCE_NATIVE_WCHAR_IS_UTF16 1
  24. #define JUCE_NATIVE_WCHAR_IS_UTF32 0
  25. #else
  26. /** This macro will be set to 1 if the compiler's native wchar_t is an 8-bit type. */
  27. #define JUCE_NATIVE_WCHAR_IS_UTF8 0
  28. /** This macro will be set to 1 if the compiler's native wchar_t is a 16-bit type. */
  29. #define JUCE_NATIVE_WCHAR_IS_UTF16 0
  30. /** This macro will be set to 1 if the compiler's native wchar_t is a 32-bit type. */
  31. #define JUCE_NATIVE_WCHAR_IS_UTF32 1
  32. #endif
  33. #if JUCE_NATIVE_WCHAR_IS_UTF32 || DOXYGEN
  34. /** A platform-independent 32-bit unicode character type. */
  35. typedef wchar_t juce_wchar;
  36. #else
  37. typedef uint32 juce_wchar;
  38. #endif
  39. /** This macro is deprecated, but preserved for compatibility with old code. */
  40. #define JUCE_T(stringLiteral) (L##stringLiteral)
  41. #if JUCE_DEFINE_T_MACRO
  42. /** The 'T' macro is an alternative for using the "L" prefix in front of a string literal.
  43. This macro is deprecated, but available for compatibility with old code if you set
  44. JUCE_DEFINE_T_MACRO = 1. The fastest, most portable and best way to write your string
  45. literals is as standard char strings, using escaped utf-8 character sequences for extended
  46. characters, rather than trying to store them as wide-char strings.
  47. */
  48. #define T(stringLiteral) JUCE_T(stringLiteral)
  49. #endif
  50. #undef max
  51. #undef min
  52. //==============================================================================
  53. /**
  54. A set of methods for manipulating characters and character strings.
  55. These are defined as wrappers around the basic C string handlers, to provide
  56. a clean, cross-platform layer, (because various platforms differ in the
  57. range of C library calls that they provide).
  58. @see String
  59. */
  60. class JUCE_API CharacterFunctions
  61. {
  62. public:
  63. //==============================================================================
  64. static juce_wchar toUpperCase (juce_wchar character) noexcept;
  65. static juce_wchar toLowerCase (juce_wchar character) noexcept;
  66. static bool isUpperCase (juce_wchar character) noexcept;
  67. static bool isLowerCase (juce_wchar character) noexcept;
  68. static bool isWhitespace (char character) noexcept;
  69. static bool isWhitespace (juce_wchar character) noexcept;
  70. static bool isDigit (char character) noexcept;
  71. static bool isDigit (juce_wchar character) noexcept;
  72. static bool isLetter (char character) noexcept;
  73. static bool isLetter (juce_wchar character) noexcept;
  74. static bool isLetterOrDigit (char character) noexcept;
  75. static bool isLetterOrDigit (juce_wchar character) noexcept;
  76. /** Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit. */
  77. static int getHexDigitValue (juce_wchar digit) noexcept;
  78. //==============================================================================
  79. template <typename CharPointerType>
  80. static double readDoubleValue (CharPointerType& text) noexcept
  81. {
  82. double result[3] = { 0 }, accumulator[2] = { 0 };
  83. int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 };
  84. int exponent = 0, decPointIndex = 0, digit = 0;
  85. int lastDigit = 0, numSignificantDigits = 0;
  86. bool isNegative = false, digitsFound = false;
  87. const int maxSignificantDigits = 15 + 2;
  88. text = text.findEndOfWhitespace();
  89. juce_wchar c = *text;
  90. switch (c)
  91. {
  92. case '-': isNegative = true; // fall-through..
  93. case '+': c = *++text;
  94. }
  95. switch (c)
  96. {
  97. case 'n':
  98. case 'N':
  99. if ((text[1] == 'a' || text[1] == 'A') && (text[2] == 'n' || text[2] == 'N'))
  100. return std::numeric_limits<double>::quiet_NaN();
  101. break;
  102. case 'i':
  103. case 'I':
  104. if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F'))
  105. return std::numeric_limits<double>::infinity();
  106. break;
  107. }
  108. for (;;)
  109. {
  110. if (text.isDigit())
  111. {
  112. lastDigit = digit;
  113. digit = (int) text.getAndAdvance() - '0';
  114. digitsFound = true;
  115. if (decPointIndex != 0)
  116. exponentAdjustment[1]++;
  117. if (numSignificantDigits == 0 && digit == 0)
  118. continue;
  119. if (++numSignificantDigits > maxSignificantDigits)
  120. {
  121. if (digit > 5)
  122. ++accumulator [decPointIndex];
  123. else if (digit == 5 && (lastDigit & 1) != 0)
  124. ++accumulator [decPointIndex];
  125. if (decPointIndex > 0)
  126. exponentAdjustment[1]--;
  127. else
  128. exponentAdjustment[0]++;
  129. while (text.isDigit())
  130. {
  131. ++text;
  132. if (decPointIndex == 0)
  133. exponentAdjustment[0]++;
  134. }
  135. }
  136. else
  137. {
  138. const double maxAccumulatorValue = (double) ((std::numeric_limits<unsigned int>::max() - 9) / 10);
  139. if (accumulator [decPointIndex] > maxAccumulatorValue)
  140. {
  141. result [decPointIndex] = mulexp10 (result [decPointIndex], exponentAccumulator [decPointIndex])
  142. + accumulator [decPointIndex];
  143. accumulator [decPointIndex] = 0;
  144. exponentAccumulator [decPointIndex] = 0;
  145. }
  146. accumulator [decPointIndex] = accumulator[decPointIndex] * 10 + digit;
  147. exponentAccumulator [decPointIndex]++;
  148. }
  149. }
  150. else if (decPointIndex == 0 && *text == '.')
  151. {
  152. ++text;
  153. decPointIndex = 1;
  154. if (numSignificantDigits > maxSignificantDigits)
  155. {
  156. while (text.isDigit())
  157. ++text;
  158. break;
  159. }
  160. }
  161. else
  162. {
  163. break;
  164. }
  165. }
  166. result[0] = mulexp10 (result[0], exponentAccumulator[0]) + accumulator[0];
  167. if (decPointIndex != 0)
  168. result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1];
  169. c = *text;
  170. if ((c == 'e' || c == 'E') && digitsFound)
  171. {
  172. bool negativeExponent = false;
  173. switch (*++text)
  174. {
  175. case '-': negativeExponent = true; // fall-through..
  176. case '+': ++text;
  177. }
  178. while (text.isDigit())
  179. exponent = (exponent * 10) + ((int) text.getAndAdvance() - '0');
  180. if (negativeExponent)
  181. exponent = -exponent;
  182. }
  183. double r = mulexp10 (result[0], exponent + exponentAdjustment[0]);
  184. if (decPointIndex != 0)
  185. r += mulexp10 (result[1], exponent - exponentAdjustment[1]);
  186. return isNegative ? -r : r;
  187. }
  188. template <typename CharPointerType>
  189. static double getDoubleValue (const CharPointerType& text) noexcept
  190. {
  191. CharPointerType t (text);
  192. return readDoubleValue (t);
  193. }
  194. //==============================================================================
  195. template <typename IntType, typename CharPointerType>
  196. static IntType getIntValue (const CharPointerType& text) noexcept
  197. {
  198. IntType v = 0;
  199. CharPointerType s (text.findEndOfWhitespace());
  200. const bool isNeg = *s == '-';
  201. if (isNeg)
  202. ++s;
  203. for (;;)
  204. {
  205. const juce_wchar c = s.getAndAdvance();
  206. if (c >= '0' && c <= '9')
  207. v = v * 10 + (IntType) (c - '0');
  208. else
  209. break;
  210. }
  211. return isNeg ? -v : v;
  212. }
  213. //==============================================================================
  214. template <typename CharPointerType>
  215. static size_t lengthUpTo (CharPointerType text, const size_t maxCharsToCount) noexcept
  216. {
  217. size_t len = 0;
  218. while (len < maxCharsToCount && text.getAndAdvance() != 0)
  219. ++len;
  220. return len;
  221. }
  222. template <typename CharPointerType>
  223. static size_t lengthUpTo (CharPointerType start, const CharPointerType& end) noexcept
  224. {
  225. size_t len = 0;
  226. while (start < end && start.getAndAdvance() != 0)
  227. ++len;
  228. return len;
  229. }
  230. template <typename DestCharPointerType, typename SrcCharPointerType>
  231. static void copyAll (DestCharPointerType& dest, SrcCharPointerType src) noexcept
  232. {
  233. for (;;)
  234. {
  235. const juce_wchar c = src.getAndAdvance();
  236. if (c == 0)
  237. break;
  238. dest.write (c);
  239. }
  240. dest.writeNull();
  241. }
  242. template <typename DestCharPointerType, typename SrcCharPointerType>
  243. static int copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxBytes) noexcept
  244. {
  245. typename DestCharPointerType::CharType const* const startAddress = dest.getAddress();
  246. maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null)
  247. for (;;)
  248. {
  249. const juce_wchar c = src.getAndAdvance();
  250. const int bytesNeeded = (int) DestCharPointerType::getBytesRequiredFor (c);
  251. maxBytes -= bytesNeeded;
  252. if (c == 0 || maxBytes < 0)
  253. break;
  254. dest.write (c);
  255. }
  256. dest.writeNull();
  257. return (int) (getAddressDifference (dest.getAddress(), startAddress) + sizeof (typename DestCharPointerType::CharType));
  258. }
  259. template <typename DestCharPointerType, typename SrcCharPointerType>
  260. static void copyWithCharLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxChars) noexcept
  261. {
  262. while (--maxChars > 0)
  263. {
  264. const juce_wchar c = src.getAndAdvance();
  265. if (c == 0)
  266. break;
  267. dest.write (c);
  268. }
  269. dest.writeNull();
  270. }
  271. template <typename CharPointerType1, typename CharPointerType2>
  272. static int compare (CharPointerType1 s1, CharPointerType2 s2) noexcept
  273. {
  274. for (;;)
  275. {
  276. const int c1 = (int) s1.getAndAdvance();
  277. const int c2 = (int) s2.getAndAdvance();
  278. const int diff = c1 - c2;
  279. if (diff != 0)
  280. return diff < 0 ? -1 : 1;
  281. else if (c1 == 0)
  282. break;
  283. }
  284. return 0;
  285. }
  286. template <typename CharPointerType1, typename CharPointerType2>
  287. static int compareUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
  288. {
  289. while (--maxChars >= 0)
  290. {
  291. const int c1 = (int) s1.getAndAdvance();
  292. const int c2 = (int) s2.getAndAdvance();
  293. const int diff = c1 - c2;
  294. if (diff != 0)
  295. return diff < 0 ? -1 : 1;
  296. else if (c1 == 0)
  297. break;
  298. }
  299. return 0;
  300. }
  301. template <typename CharPointerType1, typename CharPointerType2>
  302. static int compareIgnoreCase (CharPointerType1 s1, CharPointerType2 s2) noexcept
  303. {
  304. for (;;)
  305. {
  306. int c1 = (int) s1.toUpperCase();
  307. int c2 = (int) s2.toUpperCase();
  308. ++s1;
  309. ++s2;
  310. const int diff = c1 - c2;
  311. if (diff != 0)
  312. return diff < 0 ? -1 : 1;
  313. else if (c1 == 0)
  314. break;
  315. }
  316. return 0;
  317. }
  318. template <typename CharPointerType1, typename CharPointerType2>
  319. static int compareIgnoreCaseUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
  320. {
  321. while (--maxChars >= 0)
  322. {
  323. int c1 = s1.toUpperCase();
  324. int c2 = s2.toUpperCase();
  325. ++s1;
  326. ++s2;
  327. const int diff = c1 - c2;
  328. if (diff != 0)
  329. return diff < 0 ? -1 : 1;
  330. else if (c1 == 0)
  331. break;
  332. }
  333. return 0;
  334. }
  335. template <typename CharPointerType1, typename CharPointerType2>
  336. static int indexOf (CharPointerType1 haystack, const CharPointerType2& needle) noexcept
  337. {
  338. int index = 0;
  339. const int needleLength = (int) needle.length();
  340. for (;;)
  341. {
  342. if (haystack.compareUpTo (needle, needleLength) == 0)
  343. return index;
  344. if (haystack.getAndAdvance() == 0)
  345. return -1;
  346. ++index;
  347. }
  348. }
  349. template <typename CharPointerType1, typename CharPointerType2>
  350. static int indexOfIgnoreCase (CharPointerType1 haystack, const CharPointerType2& needle) noexcept
  351. {
  352. int index = 0;
  353. const int needleLength = (int) needle.length();
  354. for (;;)
  355. {
  356. if (haystack.compareIgnoreCaseUpTo (needle, needleLength) == 0)
  357. return index;
  358. if (haystack.getAndAdvance() == 0)
  359. return -1;
  360. ++index;
  361. }
  362. }
  363. template <typename Type>
  364. static int indexOfChar (Type text, const juce_wchar charToFind) noexcept
  365. {
  366. int i = 0;
  367. while (! text.isEmpty())
  368. {
  369. if (text.getAndAdvance() == charToFind)
  370. return i;
  371. ++i;
  372. }
  373. return -1;
  374. }
  375. template <typename Type>
  376. static int indexOfCharIgnoreCase (Type text, juce_wchar charToFind) noexcept
  377. {
  378. charToFind = CharacterFunctions::toLowerCase (charToFind);
  379. int i = 0;
  380. while (! text.isEmpty())
  381. {
  382. if (text.toLowerCase() == charToFind)
  383. return i;
  384. ++text;
  385. ++i;
  386. }
  387. return -1;
  388. }
  389. template <typename Type>
  390. static Type findEndOfWhitespace (const Type& text) noexcept
  391. {
  392. Type p (text);
  393. while (p.isWhitespace())
  394. ++p;
  395. return p;
  396. }
  397. template <typename Type>
  398. static Type findEndOfToken (const Type& text, const Type& breakCharacters, const Type& quoteCharacters)
  399. {
  400. Type t (text);
  401. juce_wchar currentQuoteChar = 0;
  402. while (! t.isEmpty())
  403. {
  404. const juce_wchar c = t.getAndAdvance();
  405. if (currentQuoteChar == 0 && breakCharacters.indexOf (c) >= 0)
  406. {
  407. --t;
  408. break;
  409. }
  410. if (quoteCharacters.indexOf (c) >= 0)
  411. {
  412. if (currentQuoteChar == 0)
  413. currentQuoteChar = c;
  414. else if (currentQuoteChar == c)
  415. currentQuoteChar = 0;
  416. }
  417. }
  418. return t;
  419. }
  420. private:
  421. static double mulexp10 (const double value, int exponent) noexcept;
  422. };
  423. #endif // __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__