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.

357 lines
10KB

  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. #include "../Application/jucer_Headers.h"
  19. #include "jucer_JucerDocument.h"
  20. //==============================================================================
  21. BinaryResources& BinaryResources::operator= (const BinaryResources& other)
  22. {
  23. for (auto* r : other.resources)
  24. add (r->name, r->originalFilename, r->data);
  25. return *this;
  26. }
  27. void BinaryResources::changed()
  28. {
  29. if (document != nullptr)
  30. {
  31. document->changed();
  32. document->refreshAllPropertyComps();
  33. }
  34. }
  35. //==============================================================================
  36. void BinaryResources::clear()
  37. {
  38. if (resources.size() > 0)
  39. {
  40. resources.clear();
  41. changed();
  42. }
  43. }
  44. StringArray BinaryResources::getResourceNames() const
  45. {
  46. StringArray s;
  47. for (auto* r : resources)
  48. s.add (r->name);
  49. return s;
  50. }
  51. BinaryResources::BinaryResource* BinaryResources::findResource (const String& name) const noexcept
  52. {
  53. for (auto* r : resources)
  54. if (r->name == name)
  55. return r;
  56. return nullptr;
  57. }
  58. const BinaryResources::BinaryResource* BinaryResources::getResource (const String& name) const
  59. {
  60. return findResource (name);
  61. }
  62. const BinaryResources::BinaryResource* BinaryResources::getResourceForFile (const File& file) const
  63. {
  64. for (auto* r : resources)
  65. if (r->originalFilename == file.getFullPathName())
  66. return r;
  67. return nullptr;
  68. }
  69. bool BinaryResources::add (const String& name, const File& file)
  70. {
  71. MemoryBlock mb;
  72. if (! file.loadFileAsData (mb))
  73. return false;
  74. add (name, file.getFullPathName(), mb);
  75. return true;
  76. }
  77. void BinaryResources::add (const String& name, const String& originalFileName, const MemoryBlock& data)
  78. {
  79. auto* r = findResource (name);
  80. if (r == nullptr)
  81. {
  82. resources.add (r = new BinaryResource());
  83. r->name = name;
  84. }
  85. r->originalFilename = originalFileName;
  86. r->data = data;
  87. r->drawable.reset();
  88. changed();
  89. }
  90. bool BinaryResources::reload (const int index)
  91. {
  92. return resources[index] != nullptr
  93. && add (resources [index]->name,
  94. File (resources [index]->originalFilename));
  95. }
  96. void BinaryResources::browseForResource (const String& title,
  97. const String& wildcard,
  98. const File& fileToStartFrom,
  99. const String& resourceToReplace,
  100. std::function<void (String)> callback)
  101. {
  102. chooser = std::make_unique<FileChooser> (title, fileToStartFrom, wildcard);
  103. auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles;
  104. chooser->launchAsync (flags, [safeThis = WeakReference<BinaryResources> { this },
  105. resourceToReplace,
  106. callback] (const FileChooser& fc)
  107. {
  108. if (safeThis == nullptr)
  109. {
  110. if (callback != nullptr)
  111. callback ({});
  112. return;
  113. }
  114. const auto result = fc.getResult();
  115. auto resourceName = [safeThis, result, resourceToReplace]() -> String
  116. {
  117. if (result == File())
  118. return {};
  119. if (resourceToReplace.isEmpty())
  120. return safeThis->findUniqueName (result.getFileName());
  121. return resourceToReplace;
  122. }();
  123. if (resourceName.isNotEmpty())
  124. {
  125. if (! safeThis->add (resourceName, result))
  126. {
  127. AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
  128. TRANS("Adding Resource"),
  129. TRANS("Failed to load the file!"));
  130. resourceName.clear();
  131. }
  132. }
  133. if (callback != nullptr)
  134. callback (resourceName);
  135. });
  136. }
  137. String BinaryResources::findUniqueName (const String& rootName) const
  138. {
  139. auto nameRoot = build_tools::makeValidIdentifier (rootName, true, true, false);
  140. auto name = nameRoot;
  141. auto names = getResourceNames();
  142. int suffix = 1;
  143. while (names.contains (name))
  144. name = nameRoot + String (++suffix);
  145. return name;
  146. }
  147. void BinaryResources::remove (int i)
  148. {
  149. if (resources[i] != nullptr)
  150. {
  151. resources.remove (i);
  152. changed();
  153. }
  154. }
  155. const Drawable* BinaryResources::getDrawable (const String& name) const
  156. {
  157. if (auto* res = const_cast<BinaryResources::BinaryResource*> (getResource (name)))
  158. {
  159. if (res->drawable == nullptr && res->data.getSize() > 0)
  160. res->drawable = Drawable::createFromImageData (res->data.getData(),
  161. res->data.getSize());
  162. return res->drawable.get();
  163. }
  164. return nullptr;
  165. }
  166. Image BinaryResources::getImageFromCache (const String& name) const
  167. {
  168. if (auto* res = getResource (name))
  169. if (res->data.getSize() > 0)
  170. return ImageCache::getFromMemory (res->data.getData(), (int) res->data.getSize());
  171. return {};
  172. }
  173. void BinaryResources::loadFromCpp (const File& cppFileLocation, const String& cppFile)
  174. {
  175. StringArray cpp;
  176. cpp.addLines (cppFile);
  177. clear();
  178. for (int i = 0; i < cpp.size(); ++i)
  179. {
  180. if (cpp[i].contains ("JUCER_RESOURCE:"))
  181. {
  182. StringArray tokens;
  183. tokens.addTokens (cpp[i].fromFirstOccurrenceOf (":", false, false), ",", "\"'");
  184. tokens.trim();
  185. tokens.removeEmptyStrings();
  186. auto resourceName = tokens[0];
  187. auto resourceSize = tokens[1].getIntValue();
  188. auto originalFileName = cppFileLocation.getSiblingFile (tokens[2].unquoted()).getFullPathName();
  189. jassert (resourceName.isNotEmpty() && resourceSize > 0);
  190. if (resourceName.isNotEmpty() && resourceSize > 0)
  191. {
  192. auto firstLine = i;
  193. while (i < cpp.size())
  194. if (cpp [i++].contains ("}"))
  195. break;
  196. auto dataString = cpp.joinIntoString (" ", firstLine, i - firstLine)
  197. .fromFirstOccurrenceOf ("{", false, false);
  198. MemoryOutputStream out;
  199. String::CharPointerType t (dataString.getCharPointer());
  200. int n = 0;
  201. while (! t.isEmpty())
  202. {
  203. auto c = t.getAndAdvance();
  204. if (c >= '0' && c <= '9')
  205. {
  206. n = n * 10 + (int) (c - '0');
  207. }
  208. else if (c == ',')
  209. {
  210. out.writeByte ((char) n);
  211. n = 0;
  212. }
  213. else if (c == '}')
  214. {
  215. break;
  216. }
  217. }
  218. jassert (resourceSize < (int) out.getDataSize() && resourceSize > (int) out.getDataSize() - 2);
  219. MemoryBlock mb (out.getData(), out.getDataSize());
  220. mb.setSize ((size_t) resourceSize);
  221. add (resourceName, originalFileName, mb);
  222. }
  223. }
  224. }
  225. }
  226. //==============================================================================
  227. void BinaryResources::fillInGeneratedCode (GeneratedCode& code) const
  228. {
  229. if (resources.size() > 0)
  230. {
  231. code.publicMemberDeclarations << "// Binary resources:\n";
  232. MemoryOutputStream defs;
  233. defs << "//==============================================================================\n";
  234. defs << "// Binary resources - be careful not to edit any of these sections!\n\n";
  235. for (auto* r : resources)
  236. {
  237. code.publicMemberDeclarations
  238. << "static const char* "
  239. << r->name
  240. << ";\nstatic const int "
  241. << r->name
  242. << "Size;\n";
  243. auto name = r->name;
  244. auto& mb = r->data;
  245. defs << "// JUCER_RESOURCE: " << name << ", " << (int) mb.getSize()
  246. << ", \""
  247. << File (r->originalFilename)
  248. .getRelativePathFrom (code.document->getCppFile())
  249. .replaceCharacter ('\\', '/')
  250. << "\"\n";
  251. String line1;
  252. line1 << "static const unsigned char resource_"
  253. << code.className << "_" << name << "[] = { ";
  254. defs << line1;
  255. int charsOnLine = line1.length();
  256. for (size_t j = 0; j < mb.getSize(); ++j)
  257. {
  258. auto num = (int) (unsigned char) mb[j];
  259. defs << num << ',';
  260. charsOnLine += 2;
  261. if (num >= 10) ++charsOnLine;
  262. if (num >= 100) ++charsOnLine;
  263. if (charsOnLine >= 200)
  264. {
  265. charsOnLine = 0;
  266. defs << '\n';
  267. }
  268. }
  269. defs
  270. << "0,0};\n\n"
  271. "const char* " << code.className << "::" << name
  272. << " = (const char*) resource_" << code.className << "_" << name
  273. << ";\nconst int "
  274. << code.className << "::" << name << "Size = "
  275. << (int) mb.getSize()
  276. << ";\n\n";
  277. }
  278. code.staticMemberDefinitions << defs.toString();
  279. }
  280. }