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.

344 lines
9.7KB

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