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.

288 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - 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 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-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
  19. {
  20. namespace build_tools
  21. {
  22. static const char* resourceFileIdentifierString = "JUCER_BINARY_RESOURCE";
  23. //==============================================================================
  24. void ResourceFile::setClassName (const String& name)
  25. {
  26. className = name;
  27. }
  28. void ResourceFile::addFile (const File& file)
  29. {
  30. files.add (file);
  31. auto variableNameRoot = makeBinaryDataIdentifierName (file);
  32. auto variableName = variableNameRoot;
  33. int suffix = 2;
  34. while (variableNames.contains (variableName))
  35. variableName = variableNameRoot + String (suffix++);
  36. variableNames.add (variableName);
  37. }
  38. String ResourceFile::getDataVariableFor (const File& file) const
  39. {
  40. const auto index = files.indexOf (file);
  41. jassert (index >= 0);
  42. return variableNames[index];
  43. }
  44. String ResourceFile::getSizeVariableFor (const File& file) const
  45. {
  46. return getDataVariableFor (file) + "Size";
  47. }
  48. int64 ResourceFile::getTotalDataSize() const
  49. {
  50. return std::accumulate (files.begin(),
  51. files.end(),
  52. int64 { 0 },
  53. [] (int64 acc, const File& f) { return acc + f.getSize(); });
  54. }
  55. static void writeComment (MemoryOutputStream& mo)
  56. {
  57. mo << newLine << newLine
  58. << " This is an auto-generated file: Any edits you make may be overwritten!" << newLine
  59. << newLine
  60. << "*/" << newLine
  61. << newLine;
  62. }
  63. Result ResourceFile::writeHeader (MemoryOutputStream& header)
  64. {
  65. header << "/* =========================================================================================";
  66. writeComment (header);
  67. header << "#pragma once" << newLine
  68. << newLine
  69. << "namespace " << className << newLine
  70. << "{" << newLine;
  71. for (int i = 0; i < files.size(); ++i)
  72. {
  73. auto& file = files.getReference(i);
  74. if (! file.existsAsFile())
  75. return Result::fail ("Can't open resource file: " + file.getFullPathName());
  76. auto dataSize = file.getSize();
  77. auto variableName = variableNames[i];
  78. FileInputStream fileStream (file);
  79. if (fileStream.openedOk())
  80. {
  81. header << " extern const char* " << variableName << ";" << newLine;
  82. header << " const int " << variableName << "Size = " << (int) dataSize << ";" << newLine << newLine;
  83. }
  84. }
  85. header << " // Number of elements in the namedResourceList and originalFileNames arrays." << newLine
  86. << " const int namedResourceListSize = " << files.size() << ";" << newLine
  87. << newLine
  88. << " // Points to the start of a list of resource names." << newLine
  89. << " extern const char* namedResourceList[];" << newLine
  90. << newLine
  91. << " // Points to the start of a list of resource filenames." << newLine
  92. << " extern const char* originalFilenames[];" << newLine
  93. << newLine
  94. << " // If you provide the name of one of the binary resource variables above, this function will" << newLine
  95. << " // return the corresponding data and its size (or a null pointer if the name isn't found)." << newLine
  96. << " const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes);" << newLine
  97. << newLine
  98. << " // If you provide the name of one of the binary resource variables above, this function will" << newLine
  99. << " // return the corresponding original, non-mangled filename (or a null pointer if the name isn't found)." << newLine
  100. << " const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8);" << newLine
  101. << "}" << newLine;
  102. return Result::ok();
  103. }
  104. Result ResourceFile::writeCpp (MemoryOutputStream& cpp, const File& headerFile, int& i, const int maxFileSize)
  105. {
  106. bool isFirstFile = (i == 0);
  107. cpp << "/* ==================================== " << resourceFileIdentifierString << " ====================================";
  108. writeComment (cpp);
  109. cpp << "namespace " << className << newLine
  110. << "{" << newLine;
  111. while (i < files.size())
  112. {
  113. auto& file = files.getReference(i);
  114. auto variableName = variableNames[i];
  115. FileInputStream fileStream (file);
  116. if (fileStream.openedOk())
  117. {
  118. auto tempVariable = "temp_binary_data_" + String (i);
  119. cpp << newLine << "//================== " << file.getFileName() << " ==================" << newLine
  120. << "static const unsigned char " << tempVariable << "[] =" << newLine;
  121. {
  122. MemoryBlock data;
  123. fileStream.readIntoMemoryBlock (data);
  124. writeDataAsCppLiteral (data, cpp, true, true);
  125. }
  126. cpp << newLine << newLine
  127. << "const char* " << variableName << " = (const char*) " << tempVariable << ";" << newLine;
  128. }
  129. ++i;
  130. if (cpp.getPosition() > maxFileSize)
  131. break;
  132. }
  133. if (isFirstFile)
  134. {
  135. if (i < files.size())
  136. {
  137. cpp << newLine
  138. << "}" << newLine
  139. << newLine
  140. << "#include \"" << headerFile.getFileName() << "\"" << newLine
  141. << newLine
  142. << "namespace " << className << newLine
  143. << "{";
  144. }
  145. cpp << newLine
  146. << newLine
  147. << "const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)" << newLine
  148. << "{" << newLine;
  149. StringArray returnCodes;
  150. for (auto& file : files)
  151. {
  152. auto dataSize = file.getSize();
  153. returnCodes.add ("numBytes = " + String (dataSize) + "; return " + variableNames[files.indexOf (file)] + ";");
  154. }
  155. createStringMatcher (cpp, "resourceNameUTF8", variableNames, returnCodes, 4);
  156. cpp << " numBytes = 0;" << newLine
  157. << " return nullptr;" << newLine
  158. << "}" << newLine
  159. << newLine;
  160. cpp << "const char* namedResourceList[] =" << newLine
  161. << "{" << newLine;
  162. for (int j = 0; j < files.size(); ++j)
  163. cpp << " " << variableNames[j].quoted() << (j < files.size() - 1 ? "," : "") << newLine;
  164. cpp << "};" << newLine << newLine;
  165. cpp << "const char* originalFilenames[] =" << newLine
  166. << "{" << newLine;
  167. for (auto& f : files)
  168. cpp << " " << f.getFileName().quoted() << (files.indexOf (f) < files.size() - 1 ? "," : "") << newLine;
  169. cpp << "};" << newLine << newLine;
  170. cpp << "const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8)" << newLine
  171. << "{" << newLine
  172. << " for (unsigned int i = 0; i < (sizeof (namedResourceList) / sizeof (namedResourceList[0])); ++i)" << newLine
  173. << " {" << newLine
  174. << " if (namedResourceList[i] == resourceNameUTF8)" << newLine
  175. << " return originalFilenames[i];" << newLine
  176. << " }" << newLine
  177. << newLine
  178. << " return nullptr;" << newLine
  179. << "}" << newLine
  180. << newLine;
  181. }
  182. cpp << "}" << newLine;
  183. return Result::ok();
  184. }
  185. ResourceFile::WriteResult ResourceFile::write (int maxFileSize,
  186. String projectLineFeed,
  187. File headerFile,
  188. std::function<File (int)> getCppFile)
  189. {
  190. Array<File> filesCreated;
  191. {
  192. MemoryOutputStream mo;
  193. mo.setNewLineString (projectLineFeed);
  194. auto r = writeHeader (mo);
  195. if (r.failed())
  196. return { r, {} };
  197. if (! overwriteFileWithNewDataIfDifferent (headerFile, mo))
  198. return { Result::fail ("Can't write to file: " + headerFile.getFullPathName()), {} };
  199. filesCreated.add (headerFile);
  200. }
  201. int i = 0;
  202. int fileIndex = 0;
  203. for (;;)
  204. {
  205. auto cpp = getCppFile (fileIndex);
  206. MemoryOutputStream mo;
  207. mo.setNewLineString (projectLineFeed);
  208. auto r = writeCpp (mo, headerFile, i, maxFileSize);
  209. if (r.failed())
  210. return { r, std::move (filesCreated) };
  211. if (! overwriteFileWithNewDataIfDifferent (cpp, mo))
  212. return { Result::fail ("Can't write to file: " + cpp.getFullPathName()), std::move (filesCreated) };
  213. filesCreated.add (cpp);
  214. ++fileIndex;
  215. if (i >= files.size())
  216. break;
  217. }
  218. return { Result::ok(), std::move (filesCreated) };
  219. }
  220. }
  221. }