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.

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