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.

355 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. #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. NullCheckedInvocation::invoke (callback, String{});
  111. return;
  112. }
  113. const auto result = fc.getResult();
  114. auto resourceName = [safeThis, result, resourceToReplace]() -> String
  115. {
  116. if (result == File())
  117. return {};
  118. if (resourceToReplace.isEmpty())
  119. return safeThis->findUniqueName (result.getFileName());
  120. return resourceToReplace;
  121. }();
  122. if (resourceName.isNotEmpty())
  123. {
  124. if (! safeThis->add (resourceName, result))
  125. {
  126. auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon,
  127. TRANS ("Adding Resource"),
  128. TRANS ("Failed to load the file!"));
  129. safeThis->messageBox = AlertWindow::showScopedAsync (options, nullptr);
  130. resourceName.clear();
  131. }
  132. }
  133. NullCheckedInvocation::invoke (callback, resourceName);
  134. });
  135. }
  136. String BinaryResources::findUniqueName (const String& rootName) const
  137. {
  138. auto nameRoot = build_tools::makeValidIdentifier (rootName, true, true, false);
  139. auto name = nameRoot;
  140. auto names = getResourceNames();
  141. int suffix = 1;
  142. while (names.contains (name))
  143. name = nameRoot + String (++suffix);
  144. return name;
  145. }
  146. void BinaryResources::remove (int i)
  147. {
  148. if (resources[i] != nullptr)
  149. {
  150. resources.remove (i);
  151. changed();
  152. }
  153. }
  154. const Drawable* BinaryResources::getDrawable (const String& name) const
  155. {
  156. if (auto* res = const_cast<BinaryResources::BinaryResource*> (getResource (name)))
  157. {
  158. if (res->drawable == nullptr && res->data.getSize() > 0)
  159. res->drawable = Drawable::createFromImageData (res->data.getData(),
  160. res->data.getSize());
  161. return res->drawable.get();
  162. }
  163. return nullptr;
  164. }
  165. Image BinaryResources::getImageFromCache (const String& name) const
  166. {
  167. if (auto* res = getResource (name))
  168. if (res->data.getSize() > 0)
  169. return ImageCache::getFromMemory (res->data.getData(), (int) res->data.getSize());
  170. return {};
  171. }
  172. void BinaryResources::loadFromCpp (const File& cppFileLocation, const String& cppFile)
  173. {
  174. StringArray cpp;
  175. cpp.addLines (cppFile);
  176. clear();
  177. for (int i = 0; i < cpp.size(); ++i)
  178. {
  179. if (cpp[i].contains ("JUCER_RESOURCE:"))
  180. {
  181. StringArray tokens;
  182. tokens.addTokens (cpp[i].fromFirstOccurrenceOf (":", false, false), ",", "\"'");
  183. tokens.trim();
  184. tokens.removeEmptyStrings();
  185. auto resourceName = tokens[0];
  186. auto resourceSize = tokens[1].getIntValue();
  187. auto originalFileName = cppFileLocation.getSiblingFile (tokens[2].unquoted()).getFullPathName();
  188. jassert (resourceName.isNotEmpty() && resourceSize > 0);
  189. if (resourceName.isNotEmpty() && resourceSize > 0)
  190. {
  191. auto firstLine = i;
  192. while (i < cpp.size())
  193. if (cpp [i++].contains ("}"))
  194. break;
  195. auto dataString = cpp.joinIntoString (" ", firstLine, i - firstLine)
  196. .fromFirstOccurrenceOf ("{", false, false);
  197. MemoryOutputStream out;
  198. String::CharPointerType t (dataString.getCharPointer());
  199. int n = 0;
  200. while (! t.isEmpty())
  201. {
  202. auto c = t.getAndAdvance();
  203. if (c >= '0' && c <= '9')
  204. {
  205. n = n * 10 + (int) (c - '0');
  206. }
  207. else if (c == ',')
  208. {
  209. out.writeByte ((char) n);
  210. n = 0;
  211. }
  212. else if (c == '}')
  213. {
  214. break;
  215. }
  216. }
  217. jassert (resourceSize < (int) out.getDataSize() && resourceSize > (int) out.getDataSize() - 2);
  218. MemoryBlock mb (out.getData(), out.getDataSize());
  219. mb.setSize ((size_t) resourceSize);
  220. add (resourceName, originalFileName, mb);
  221. }
  222. }
  223. }
  224. }
  225. //==============================================================================
  226. void BinaryResources::fillInGeneratedCode (GeneratedCode& code) const
  227. {
  228. if (resources.size() > 0)
  229. {
  230. code.publicMemberDeclarations << "// Binary resources:\n";
  231. MemoryOutputStream defs;
  232. defs << "//==============================================================================\n";
  233. defs << "// Binary resources - be careful not to edit any of these sections!\n\n";
  234. for (auto* r : resources)
  235. {
  236. code.publicMemberDeclarations
  237. << "static const char* "
  238. << r->name
  239. << ";\nstatic const int "
  240. << r->name
  241. << "Size;\n";
  242. auto name = r->name;
  243. auto& mb = r->data;
  244. defs << "// JUCER_RESOURCE: " << name << ", " << (int) mb.getSize()
  245. << ", \""
  246. << File (r->originalFilename)
  247. .getRelativePathFrom (code.document->getCppFile())
  248. .replaceCharacter ('\\', '/')
  249. << "\"\n";
  250. String line1;
  251. line1 << "static const unsigned char resource_"
  252. << code.className << "_" << name << "[] = { ";
  253. defs << line1;
  254. int charsOnLine = line1.length();
  255. for (size_t j = 0; j < mb.getSize(); ++j)
  256. {
  257. auto num = (int) (unsigned char) mb[j];
  258. defs << num << ',';
  259. charsOnLine += 2;
  260. if (num >= 10) ++charsOnLine;
  261. if (num >= 100) ++charsOnLine;
  262. if (charsOnLine >= 200)
  263. {
  264. charsOnLine = 0;
  265. defs << '\n';
  266. }
  267. }
  268. defs
  269. << "0,0};\n\n"
  270. "const char* " << code.className << "::" << name
  271. << " = (const char*) resource_" << code.className << "_" << name
  272. << ";\nconst int "
  273. << code.className << "::" << name << "Size = "
  274. << (int) mb.getSize()
  275. << ";\n\n";
  276. }
  277. code.staticMemberDefinitions << defs.toString();
  278. }
  279. }