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
10KB

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