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.

359 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce::build_tools
  19. {
  20. void overwriteFileIfDifferentOrThrow (const File& file, const MemoryOutputStream& newData)
  21. {
  22. if (! overwriteFileWithNewDataIfDifferent (file, newData))
  23. throw SaveError (file);
  24. }
  25. void overwriteFileIfDifferentOrThrow (const File& file, const String& newData)
  26. {
  27. if (! overwriteFileWithNewDataIfDifferent (file, newData))
  28. throw SaveError (file);
  29. }
  30. String replacePreprocessorDefs (const StringPairArray& definitions, String sourceString)
  31. {
  32. for (int i = 0; i < definitions.size(); ++i)
  33. {
  34. const String key (definitions.getAllKeys()[i]);
  35. const String value (definitions.getAllValues()[i]);
  36. sourceString = sourceString.replace ("${" + key + "}", value);
  37. }
  38. return sourceString;
  39. }
  40. String getXcodePackageType (ProjectType::Target::Type type)
  41. {
  42. using Type = ProjectType::Target::Type;
  43. switch (type)
  44. {
  45. case Type::GUIApp:
  46. case Type::StandalonePlugIn:
  47. return "APPL";
  48. case Type::VSTPlugIn:
  49. case Type::VST3PlugIn:
  50. case Type::AudioUnitPlugIn:
  51. case Type::UnityPlugIn:
  52. return "BNDL";
  53. case Type::AudioUnitv3PlugIn:
  54. return "XPC!";
  55. case Type::AAXPlugIn:
  56. return "TDMw";
  57. case Type::ConsoleApp:
  58. case Type::StaticLibrary:
  59. case Type::DynamicLibrary:
  60. case Type::LV2PlugIn:
  61. case Type::LV2Helper:
  62. case Type::VST3Helper:
  63. case Type::SharedCodeTarget:
  64. case Type::AggregateTarget:
  65. case Type::unspecified:
  66. default:
  67. return {};
  68. }
  69. }
  70. String getXcodeBundleSignature (ProjectType::Target::Type type)
  71. {
  72. using Type = ProjectType::Target::Type;
  73. switch (type)
  74. {
  75. case Type::GUIApp:
  76. case Type::VSTPlugIn:
  77. case Type::VST3PlugIn:
  78. case Type::AudioUnitPlugIn:
  79. case Type::StandalonePlugIn:
  80. case Type::AudioUnitv3PlugIn:
  81. case Type::UnityPlugIn:
  82. return "????";
  83. case Type::AAXPlugIn:
  84. return "PTul";
  85. case Type::ConsoleApp:
  86. case Type::StaticLibrary:
  87. case Type::DynamicLibrary:
  88. case Type::LV2PlugIn:
  89. case Type::LV2Helper:
  90. case Type::VST3Helper:
  91. case Type::SharedCodeTarget:
  92. case Type::AggregateTarget:
  93. case Type::unspecified:
  94. default:
  95. return {};
  96. }
  97. }
  98. static unsigned int calculateHash (const String& s, const unsigned int hashMultiplier)
  99. {
  100. auto t = s.toUTF8();
  101. unsigned int hash = 0;
  102. while (*t != 0)
  103. hash = hashMultiplier * hash + (unsigned int) *t++;
  104. return hash;
  105. }
  106. static unsigned int findBestHashMultiplier (const StringArray& strings)
  107. {
  108. unsigned int v = 31;
  109. for (;;)
  110. {
  111. SortedSet<unsigned int> hashes;
  112. bool collision = false;
  113. for (int i = strings.size(); --i >= 0;)
  114. {
  115. auto hash = calculateHash (strings[i], v);
  116. if (hashes.contains (hash))
  117. {
  118. collision = true;
  119. break;
  120. }
  121. hashes.add (hash);
  122. }
  123. if (! collision)
  124. break;
  125. v += 2;
  126. }
  127. return v;
  128. }
  129. String makeValidIdentifier (String s, bool makeCamelCase, bool removeColons, bool allowTemplates, bool allowAsterisks)
  130. {
  131. if (s.isEmpty())
  132. return "unknown";
  133. if (removeColons)
  134. s = s.replaceCharacters (".,;:/@", "______");
  135. else
  136. s = s.replaceCharacters (".,;/@", "_____");
  137. for (int i = s.length(); --i > 0;)
  138. if (CharacterFunctions::isLetter (s[i])
  139. && CharacterFunctions::isLetter (s[i - 1])
  140. && CharacterFunctions::isUpperCase (s[i])
  141. && ! CharacterFunctions::isUpperCase (s[i - 1]))
  142. s = s.substring (0, i) + " " + s.substring (i);
  143. String allowedChars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ 0123456789");
  144. if (allowTemplates)
  145. allowedChars += "<>";
  146. if (! removeColons)
  147. allowedChars += ":";
  148. if (allowAsterisks)
  149. allowedChars += "*";
  150. StringArray words;
  151. words.addTokens (s.retainCharacters (allowedChars), false);
  152. words.trim();
  153. auto n = words[0];
  154. if (makeCamelCase)
  155. n = n.toLowerCase();
  156. for (int i = 1; i < words.size(); ++i)
  157. {
  158. if (makeCamelCase && words[i].length() > 1)
  159. n << words[i].substring (0, 1).toUpperCase()
  160. << words[i].substring (1).toLowerCase();
  161. else
  162. n << words[i];
  163. }
  164. if (CharacterFunctions::isDigit (n[0]))
  165. n = "_" + n;
  166. if (isReservedKeyword (n))
  167. n << '_';
  168. return n;
  169. }
  170. String makeBinaryDataIdentifierName (const File& file)
  171. {
  172. return makeValidIdentifier (file.getFileName()
  173. .replaceCharacters (" .", "__")
  174. .retainCharacters ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"),
  175. false, true, false);
  176. }
  177. void writeDataAsCppLiteral (const MemoryBlock& mb, OutputStream& out,
  178. bool breakAtNewLines, bool allowStringBreaks)
  179. {
  180. const int maxCharsOnLine = 250;
  181. auto data = (const unsigned char*) mb.getData();
  182. int charsOnLine = 0;
  183. bool canUseStringLiteral = mb.getSize() < 32768; // MS compilers can't handle big string literals..
  184. if (canUseStringLiteral)
  185. {
  186. unsigned int numEscaped = 0;
  187. for (size_t i = 0; i < mb.getSize(); ++i)
  188. {
  189. auto num = (unsigned int) data[i];
  190. if (! ((num >= 32 && num < 127) || num == '\t' || num == '\r' || num == '\n'))
  191. {
  192. if (++numEscaped > mb.getSize() / 4)
  193. {
  194. canUseStringLiteral = false;
  195. break;
  196. }
  197. }
  198. }
  199. }
  200. if (! canUseStringLiteral)
  201. {
  202. out << "{ ";
  203. for (size_t i = 0; i < mb.getSize(); ++i)
  204. {
  205. auto num = (int) (unsigned int) data[i];
  206. out << num << ',';
  207. charsOnLine += 2;
  208. if (num >= 10)
  209. {
  210. ++charsOnLine;
  211. if (num >= 100)
  212. ++charsOnLine;
  213. }
  214. if (charsOnLine >= maxCharsOnLine)
  215. {
  216. charsOnLine = 0;
  217. out << newLine;
  218. }
  219. }
  220. out << "0,0 };";
  221. }
  222. else
  223. {
  224. out << "\"";
  225. writeEscapeChars (out, (const char*) data, (int) mb.getSize(),
  226. maxCharsOnLine, breakAtNewLines, false, allowStringBreaks);
  227. out << "\";";
  228. }
  229. }
  230. void createStringMatcher (OutputStream& out, const String& utf8PointerVariable,
  231. const StringArray& strings, const StringArray& codeToExecute, const int indentLevel)
  232. {
  233. jassert (strings.size() == codeToExecute.size());
  234. auto indent = String::repeatedString (" ", indentLevel);
  235. auto hashMultiplier = findBestHashMultiplier (strings);
  236. out << indent << "unsigned int hash = 0;" << newLine
  237. << newLine
  238. << indent << "if (" << utf8PointerVariable << " != nullptr)" << newLine
  239. << indent << " while (*" << utf8PointerVariable << " != 0)" << newLine
  240. << indent << " hash = " << (int) hashMultiplier << " * hash + (unsigned int) *" << utf8PointerVariable << "++;" << newLine
  241. << newLine
  242. << indent << "switch (hash)" << newLine
  243. << indent << "{" << newLine;
  244. for (int i = 0; i < strings.size(); ++i)
  245. {
  246. out << indent << " case 0x" << hexString8Digits ((int) calculateHash (strings[i], hashMultiplier))
  247. << ": " << codeToExecute[i] << newLine;
  248. }
  249. out << indent << " default: break;" << newLine
  250. << indent << "}" << newLine << newLine;
  251. }
  252. String unixStylePath (const String& path) { return path.replaceCharacter ('\\', '/'); }
  253. String windowsStylePath (const String& path) { return path.replaceCharacter ('/', '\\'); }
  254. String currentOSStylePath (const String& path)
  255. {
  256. #if JUCE_WINDOWS
  257. return windowsStylePath (path);
  258. #else
  259. return unixStylePath (path);
  260. #endif
  261. }
  262. bool isAbsolutePath (const String& path)
  263. {
  264. return File::isAbsolutePath (path)
  265. || path.startsWithChar ('/') // (needed because File::isAbsolutePath will ignore forward-slashes on Windows)
  266. || path.startsWithChar ('$')
  267. || path.startsWithChar ('~')
  268. || (CharacterFunctions::isLetter (path[0]) && path[1] == ':')
  269. || path.startsWithIgnoreCase ("smb:");
  270. }
  271. String getRelativePathFrom (const File& file, const File& sourceFolder)
  272. {
  273. #if ! JUCE_WINDOWS
  274. // On a non-windows machine, we can't know if a drive-letter path may be relative or not.
  275. if (CharacterFunctions::isLetter (file.getFullPathName()[0]) && file.getFullPathName()[1] == ':')
  276. return file.getFullPathName();
  277. #endif
  278. return file.getRelativePathFrom (sourceFolder);
  279. }
  280. void writeStreamToFile (const File& file, const std::function<void (MemoryOutputStream&)>& writer)
  281. {
  282. MemoryOutputStream mo;
  283. writer (mo);
  284. overwriteFileIfDifferentOrThrow (file, mo);
  285. }
  286. } // namespace juce::build_tools