migrating to the latest JUCE version

This commit is contained in:
2022-11-04 23:11:33 +01:00
committed by Nikolai Rodionov
parent 4257a0f8ba
commit faf8f18333
2796 changed files with 888518 additions and 784244 deletions

View File

@ -1,289 +1,289 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
static const char* resourceFileIdentifierString = "JUCER_BINARY_RESOURCE";
//==============================================================================
void ResourceFile::setClassName (const String& name)
{
className = name;
}
void ResourceFile::addFile (const File& file)
{
files.add (file);
auto variableNameRoot = makeBinaryDataIdentifierName (file);
auto variableName = variableNameRoot;
int suffix = 2;
while (variableNames.contains (variableName))
variableName = variableNameRoot + String (suffix++);
variableNames.add (variableName);
}
String ResourceFile::getDataVariableFor (const File& file) const
{
const auto index = files.indexOf (file);
jassert (index >= 0);
return variableNames[index];
}
String ResourceFile::getSizeVariableFor (const File& file) const
{
return getDataVariableFor (file) + "Size";
}
int64 ResourceFile::getTotalDataSize() const
{
return std::accumulate (files.begin(),
files.end(),
int64 { 0 },
[] (int64 acc, const File& f) { return acc + f.getSize(); });
}
static void writeComment (MemoryOutputStream& mo)
{
mo << newLine << newLine
<< " This is an auto-generated file: Any edits you make may be overwritten!" << newLine
<< newLine
<< "*/" << newLine
<< newLine;
}
Result ResourceFile::writeHeader (MemoryOutputStream& header)
{
header << "/* =========================================================================================";
writeComment (header);
header << "#pragma once" << newLine
<< newLine
<< "namespace " << className << newLine
<< "{" << newLine;
for (int i = 0; i < files.size(); ++i)
{
auto& file = files.getReference(i);
if (! file.existsAsFile())
return Result::fail ("Can't open resource file: " + file.getFullPathName());
auto dataSize = file.getSize();
auto variableName = variableNames[i];
FileInputStream fileStream (file);
if (fileStream.openedOk())
{
header << " extern const char* " << variableName << ";" << newLine;
header << " const int " << variableName << "Size = " << (int) dataSize << ";" << newLine << newLine;
}
}
header << " // Number of elements in the namedResourceList and originalFileNames arrays." << newLine
<< " const int namedResourceListSize = " << files.size() << ";" << newLine
<< newLine
<< " // Points to the start of a list of resource names." << newLine
<< " extern const char* namedResourceList[];" << newLine
<< newLine
<< " // Points to the start of a list of resource filenames." << newLine
<< " extern const char* originalFilenames[];" << newLine
<< newLine
<< " // If you provide the name of one of the binary resource variables above, this function will" << newLine
<< " // return the corresponding data and its size (or a null pointer if the name isn't found)." << newLine
<< " const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes);" << newLine
<< newLine
<< " // If you provide the name of one of the binary resource variables above, this function will" << newLine
<< " // return the corresponding original, non-mangled filename (or a null pointer if the name isn't found)." << newLine
<< " const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8);" << newLine
<< "}" << newLine;
return Result::ok();
}
Result ResourceFile::writeCpp (MemoryOutputStream& cpp, const File& headerFile, int& i, const int maxFileSize)
{
bool isFirstFile = (i == 0);
cpp << "/* ==================================== " << resourceFileIdentifierString << " ====================================";
writeComment (cpp);
cpp << "namespace " << className << newLine
<< "{" << newLine;
while (i < files.size())
{
auto& file = files.getReference(i);
auto variableName = variableNames[i];
FileInputStream fileStream (file);
if (fileStream.openedOk())
{
auto tempVariable = "temp_binary_data_" + String (i);
cpp << newLine << "//================== " << file.getFileName() << " ==================" << newLine
<< "static const unsigned char " << tempVariable << "[] =" << newLine;
{
MemoryBlock data;
fileStream.readIntoMemoryBlock (data);
writeDataAsCppLiteral (data, cpp, true, true);
}
cpp << newLine << newLine
<< "const char* " << variableName << " = (const char*) " << tempVariable << ";" << newLine;
}
++i;
if (cpp.getPosition() > maxFileSize)
break;
}
if (isFirstFile)
{
if (i < files.size())
{
cpp << newLine
<< "}" << newLine
<< newLine
<< "#include \"" << headerFile.getFileName() << "\"" << newLine
<< newLine
<< "namespace " << className << newLine
<< "{";
}
cpp << newLine
<< newLine
<< "const char* getNamedResource (const char* resourceNameUTF8, int& numBytes);" << newLine
<< "const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)" << newLine
<< "{" << newLine;
StringArray returnCodes;
for (auto& file : files)
{
auto dataSize = file.getSize();
returnCodes.add ("numBytes = " + String (dataSize) + "; return " + variableNames[files.indexOf (file)] + ";");
}
createStringMatcher (cpp, "resourceNameUTF8", variableNames, returnCodes, 4);
cpp << " numBytes = 0;" << newLine
<< " return nullptr;" << newLine
<< "}" << newLine
<< newLine;
cpp << "const char* namedResourceList[] =" << newLine
<< "{" << newLine;
for (int j = 0; j < files.size(); ++j)
cpp << " " << variableNames[j].quoted() << (j < files.size() - 1 ? "," : "") << newLine;
cpp << "};" << newLine << newLine;
cpp << "const char* originalFilenames[] =" << newLine
<< "{" << newLine;
for (auto& f : files)
cpp << " " << f.getFileName().quoted() << (files.indexOf (f) < files.size() - 1 ? "," : "") << newLine;
cpp << "};" << newLine << newLine;
cpp << "const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8);" << newLine
<< "const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8)" << newLine
<< "{" << newLine
<< " for (unsigned int i = 0; i < (sizeof (namedResourceList) / sizeof (namedResourceList[0])); ++i)" << newLine
<< " {" << newLine
<< " if (namedResourceList[i] == resourceNameUTF8)" << newLine
<< " return originalFilenames[i];" << newLine
<< " }" << newLine
<< newLine
<< " return nullptr;" << newLine
<< "}" << newLine
<< newLine;
}
cpp << "}" << newLine;
return Result::ok();
}
ResourceFile::WriteResult ResourceFile::write (int maxFileSize,
String projectLineFeed,
File headerFile,
std::function<File (int)> getCppFile)
{
Array<File> filesCreated;
{
MemoryOutputStream mo;
mo.setNewLineString (projectLineFeed);
auto r = writeHeader (mo);
if (r.failed())
return { r, {} };
if (! overwriteFileWithNewDataIfDifferent (headerFile, mo))
return { Result::fail ("Can't write to file: " + headerFile.getFullPathName()), {} };
filesCreated.add (headerFile);
}
int i = 0;
int fileIndex = 0;
for (;;)
{
auto cpp = getCppFile (fileIndex);
MemoryOutputStream mo;
mo.setNewLineString (projectLineFeed);
auto r = writeCpp (mo, headerFile, i, maxFileSize);
if (r.failed())
return { r, std::move (filesCreated) };
if (! overwriteFileWithNewDataIfDifferent (cpp, mo))
return { Result::fail ("Can't write to file: " + cpp.getFullPathName()), std::move (filesCreated) };
filesCreated.add (cpp);
++fileIndex;
if (i >= files.size())
break;
}
return { Result::ok(), std::move (filesCreated) };
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
static const char* resourceFileIdentifierString = "JUCER_BINARY_RESOURCE";
//==============================================================================
void ResourceFile::setClassName (const String& name)
{
className = name;
}
void ResourceFile::addFile (const File& file)
{
files.add (file);
auto variableNameRoot = makeBinaryDataIdentifierName (file);
auto variableName = variableNameRoot;
int suffix = 2;
while (variableNames.contains (variableName))
variableName = variableNameRoot + String (suffix++);
variableNames.add (variableName);
}
String ResourceFile::getDataVariableFor (const File& file) const
{
const auto index = files.indexOf (file);
jassert (index >= 0);
return variableNames[index];
}
String ResourceFile::getSizeVariableFor (const File& file) const
{
return getDataVariableFor (file) + "Size";
}
int64 ResourceFile::getTotalDataSize() const
{
return std::accumulate (files.begin(),
files.end(),
int64 { 0 },
[] (int64 acc, const File& f) { return acc + f.getSize(); });
}
static void writeComment (MemoryOutputStream& mo)
{
mo << newLine << newLine
<< " This is an auto-generated file: Any edits you make may be overwritten!" << newLine
<< newLine
<< "*/" << newLine
<< newLine;
}
Result ResourceFile::writeHeader (MemoryOutputStream& header)
{
header << "/* =========================================================================================";
writeComment (header);
header << "#pragma once" << newLine
<< newLine
<< "namespace " << className << newLine
<< "{" << newLine;
for (int i = 0; i < files.size(); ++i)
{
auto& file = files.getReference(i);
if (! file.existsAsFile())
return Result::fail ("Can't open resource file: " + file.getFullPathName());
auto dataSize = file.getSize();
auto variableName = variableNames[i];
FileInputStream fileStream (file);
if (fileStream.openedOk())
{
header << " extern const char* " << variableName << ";" << newLine;
header << " const int " << variableName << "Size = " << (int) dataSize << ";" << newLine << newLine;
}
}
header << " // Number of elements in the namedResourceList and originalFileNames arrays." << newLine
<< " const int namedResourceListSize = " << files.size() << ";" << newLine
<< newLine
<< " // Points to the start of a list of resource names." << newLine
<< " extern const char* namedResourceList[];" << newLine
<< newLine
<< " // Points to the start of a list of resource filenames." << newLine
<< " extern const char* originalFilenames[];" << newLine
<< newLine
<< " // If you provide the name of one of the binary resource variables above, this function will" << newLine
<< " // return the corresponding data and its size (or a null pointer if the name isn't found)." << newLine
<< " const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes);" << newLine
<< newLine
<< " // If you provide the name of one of the binary resource variables above, this function will" << newLine
<< " // return the corresponding original, non-mangled filename (or a null pointer if the name isn't found)." << newLine
<< " const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8);" << newLine
<< "}" << newLine;
return Result::ok();
}
Result ResourceFile::writeCpp (MemoryOutputStream& cpp, const File& headerFile, int& i, const int maxFileSize)
{
bool isFirstFile = (i == 0);
cpp << "/* ==================================== " << resourceFileIdentifierString << " ====================================";
writeComment (cpp);
cpp << "#include <cstring>" << newLine
<< newLine
<< "namespace " << className << newLine
<< "{" << newLine;
while (i < files.size())
{
auto& file = files.getReference(i);
auto variableName = variableNames[i];
FileInputStream fileStream (file);
if (fileStream.openedOk())
{
auto tempVariable = "temp_binary_data_" + String (i);
cpp << newLine << "//================== " << file.getFileName() << " ==================" << newLine
<< "static const unsigned char " << tempVariable << "[] =" << newLine;
{
MemoryBlock data;
fileStream.readIntoMemoryBlock (data);
writeDataAsCppLiteral (data, cpp, true, true);
}
cpp << newLine << newLine
<< "const char* " << variableName << " = (const char*) " << tempVariable << ";" << newLine;
}
++i;
if (cpp.getPosition() > maxFileSize)
break;
}
if (isFirstFile)
{
if (i < files.size())
{
cpp << newLine
<< "}" << newLine
<< newLine
<< "#include \"" << headerFile.getFileName() << "\"" << newLine
<< newLine
<< "namespace " << className << newLine
<< "{";
}
cpp << newLine
<< newLine
<< "const char* getNamedResource (const char* resourceNameUTF8, int& numBytes);" << newLine
<< "const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)" << newLine
<< "{" << newLine;
StringArray returnCodes;
for (auto& file : files)
{
auto dataSize = file.getSize();
returnCodes.add ("numBytes = " + String (dataSize) + "; return " + variableNames[files.indexOf (file)] + ";");
}
createStringMatcher (cpp, "resourceNameUTF8", variableNames, returnCodes, 4);
cpp << " numBytes = 0;" << newLine
<< " return nullptr;" << newLine
<< "}" << newLine
<< newLine;
cpp << "const char* namedResourceList[] =" << newLine
<< "{" << newLine;
for (int j = 0; j < files.size(); ++j)
cpp << " " << variableNames[j].quoted() << (j < files.size() - 1 ? "," : "") << newLine;
cpp << "};" << newLine << newLine;
cpp << "const char* originalFilenames[] =" << newLine
<< "{" << newLine;
for (auto& f : files)
cpp << " " << f.getFileName().quoted() << (files.indexOf (f) < files.size() - 1 ? "," : "") << newLine;
cpp << "};" << newLine << newLine;
cpp << "const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8);" << newLine
<< "const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8)" << newLine
<< "{" << newLine
<< " for (unsigned int i = 0; i < (sizeof (namedResourceList) / sizeof (namedResourceList[0])); ++i)" << newLine
<< " if (strcmp (namedResourceList[i], resourceNameUTF8) == 0)" << newLine
<< " return originalFilenames[i];" << newLine
<< newLine
<< " return nullptr;" << newLine
<< "}" << newLine
<< newLine;
}
cpp << "}" << newLine;
return Result::ok();
}
ResourceFile::WriteResult ResourceFile::write (int maxFileSize,
String projectLineFeed,
File headerFile,
std::function<File (int)> getCppFile)
{
Array<File> filesCreated;
{
MemoryOutputStream mo;
mo.setNewLineString (projectLineFeed);
auto r = writeHeader (mo);
if (r.failed())
return { r, {} };
if (! overwriteFileWithNewDataIfDifferent (headerFile, mo))
return { Result::fail ("Can't write to file: " + headerFile.getFullPathName()), {} };
filesCreated.add (headerFile);
}
int i = 0;
int fileIndex = 0;
for (;;)
{
auto cpp = getCppFile (fileIndex);
MemoryOutputStream mo;
mo.setNewLineString (projectLineFeed);
auto r = writeCpp (mo, headerFile, i, maxFileSize);
if (r.failed())
return { r, std::move (filesCreated) };
if (! overwriteFileWithNewDataIfDifferent (cpp, mo))
return { Result::fail ("Can't write to file: " + cpp.getFullPathName()), std::move (filesCreated) };
filesCreated.add (cpp);
++fileIndex;
if (i >= files.size())
break;
}
return { Result::ok(), std::move (filesCreated) };
}
}
}

View File

@ -1,74 +1,74 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
class ResourceFile
{
public:
ResourceFile() = default;
void setClassName (const String& className);
String getClassName() const { return className; }
void addFile (const File& file);
String getDataVariableFor (const File& file) const;
String getSizeVariableFor (const File& file) const;
int getNumFiles() const { return files.size (); }
const File& getFile (int index) const { return files.getReference (index); }
int64 getTotalDataSize() const;
struct WriteResult
{
Result result;
Array<File> filesCreated;
};
WriteResult write (int maxFileSize,
String projectLineFeed,
File headerFile,
std::function<File (int)> getCppFile);
private:
Array<File> files;
StringArray variableNames;
String className { "BinaryData" };
Result writeHeader (MemoryOutputStream&);
Result writeCpp (MemoryOutputStream&, const File&, int&, int);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResourceFile)
};
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
class ResourceFile
{
public:
ResourceFile() = default;
void setClassName (const String& className);
String getClassName() const { return className; }
void addFile (const File& file);
String getDataVariableFor (const File& file) const;
String getSizeVariableFor (const File& file) const;
int getNumFiles() const { return files.size (); }
const File& getFile (int index) const { return files.getReference (index); }
int64 getTotalDataSize() const;
struct WriteResult
{
Result result;
Array<File> filesCreated;
};
WriteResult write (int maxFileSize,
String projectLineFeed,
File headerFile,
std::function<File (int)> getCppFile);
private:
Array<File> files;
StringArray variableNames;
String className { "BinaryData" };
Result writeHeader (MemoryOutputStream&);
Result writeCpp (MemoryOutputStream&, const File&, int&, int);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResourceFile)
};
}
}

View File

@ -1,355 +1,357 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
void overwriteFileIfDifferentOrThrow (const File& file, const MemoryOutputStream& newData)
{
if (! overwriteFileWithNewDataIfDifferent (file, newData))
throw SaveError (file);
}
void overwriteFileIfDifferentOrThrow (const File& file, const String& newData)
{
if (! overwriteFileWithNewDataIfDifferent (file, newData))
throw SaveError (file);
}
String replacePreprocessorDefs (const StringPairArray& definitions, String sourceString)
{
for (int i = 0; i < definitions.size(); ++i)
{
const String key (definitions.getAllKeys()[i]);
const String value (definitions.getAllValues()[i]);
sourceString = sourceString.replace ("${" + key + "}", value);
}
return sourceString;
}
String getXcodePackageType (ProjectType::Target::Type type)
{
using Type = ProjectType::Target::Type;
switch (type)
{
case Type::GUIApp:
case Type::StandalonePlugIn:
return "APPL";
case Type::VSTPlugIn:
case Type::VST3PlugIn:
case Type::AudioUnitPlugIn:
case Type::UnityPlugIn:
return "BNDL";
case Type::AudioUnitv3PlugIn:
return "XPC!";
case Type::AAXPlugIn:
case Type::RTASPlugIn:
return "TDMw";
case Type::ConsoleApp:
case Type::StaticLibrary:
case Type::DynamicLibrary:
case Type::SharedCodeTarget:
case Type::AggregateTarget:
case Type::unspecified:
default:
return {};
}
}
String getXcodeBundleSignature (ProjectType::Target::Type type)
{
using Type = ProjectType::Target::Type;
switch (type)
{
case Type::GUIApp:
case Type::VSTPlugIn:
case Type::VST3PlugIn:
case Type::AudioUnitPlugIn:
case Type::StandalonePlugIn:
case Type::AudioUnitv3PlugIn:
case Type::UnityPlugIn:
return "????";
case Type::AAXPlugIn:
case Type::RTASPlugIn:
return "PTul";
case Type::ConsoleApp:
case Type::StaticLibrary:
case Type::DynamicLibrary:
case Type::SharedCodeTarget:
case Type::AggregateTarget:
case Type::unspecified:
default:
return {};
}
}
static unsigned int calculateHash (const String& s, const unsigned int hashMultiplier)
{
auto t = s.toUTF8();
unsigned int hash = 0;
while (*t != 0)
hash = hashMultiplier * hash + (unsigned int) *t++;
return hash;
}
static unsigned int findBestHashMultiplier (const StringArray& strings)
{
unsigned int v = 31;
for (;;)
{
SortedSet<unsigned int> hashes;
bool collision = false;
for (int i = strings.size(); --i >= 0;)
{
auto hash = calculateHash (strings[i], v);
if (hashes.contains (hash))
{
collision = true;
break;
}
hashes.add (hash);
}
if (! collision)
break;
v += 2;
}
return v;
}
String makeValidIdentifier (String s, bool makeCamelCase, bool removeColons, bool allowTemplates, bool allowAsterisks)
{
if (s.isEmpty())
return "unknown";
if (removeColons)
s = s.replaceCharacters (".,;:/@", "______");
else
s = s.replaceCharacters (".,;/@", "_____");
for (int i = s.length(); --i > 0;)
if (CharacterFunctions::isLetter (s[i])
&& CharacterFunctions::isLetter (s[i - 1])
&& CharacterFunctions::isUpperCase (s[i])
&& ! CharacterFunctions::isUpperCase (s[i - 1]))
s = s.substring (0, i) + " " + s.substring (i);
String allowedChars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ 0123456789");
if (allowTemplates)
allowedChars += "<>";
if (! removeColons)
allowedChars += ":";
if (allowAsterisks)
allowedChars += "*";
StringArray words;
words.addTokens (s.retainCharacters (allowedChars), false);
words.trim();
auto n = words[0];
if (makeCamelCase)
n = n.toLowerCase();
for (int i = 1; i < words.size(); ++i)
{
if (makeCamelCase && words[i].length() > 1)
n << words[i].substring (0, 1).toUpperCase()
<< words[i].substring (1).toLowerCase();
else
n << words[i];
}
if (CharacterFunctions::isDigit (n[0]))
n = "_" + n;
if (isReservedKeyword (n))
n << '_';
return n;
}
String makeBinaryDataIdentifierName (const File& file)
{
return makeValidIdentifier (file.getFileName()
.replaceCharacters (" .", "__")
.retainCharacters ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"),
false, true, false);
}
void writeDataAsCppLiteral (const MemoryBlock& mb, OutputStream& out,
bool breakAtNewLines, bool allowStringBreaks)
{
const int maxCharsOnLine = 250;
auto data = (const unsigned char*) mb.getData();
int charsOnLine = 0;
bool canUseStringLiteral = mb.getSize() < 32768; // MS compilers can't handle big string literals..
if (canUseStringLiteral)
{
unsigned int numEscaped = 0;
for (size_t i = 0; i < mb.getSize(); ++i)
{
auto num = (unsigned int) data[i];
if (! ((num >= 32 && num < 127) || num == '\t' || num == '\r' || num == '\n'))
{
if (++numEscaped > mb.getSize() / 4)
{
canUseStringLiteral = false;
break;
}
}
}
}
if (! canUseStringLiteral)
{
out << "{ ";
for (size_t i = 0; i < mb.getSize(); ++i)
{
auto num = (int) (unsigned int) data[i];
out << num << ',';
charsOnLine += 2;
if (num >= 10)
{
++charsOnLine;
if (num >= 100)
++charsOnLine;
}
if (charsOnLine >= maxCharsOnLine)
{
charsOnLine = 0;
out << newLine;
}
}
out << "0,0 };";
}
else
{
out << "\"";
writeEscapeChars (out, (const char*) data, (int) mb.getSize(),
maxCharsOnLine, breakAtNewLines, false, allowStringBreaks);
out << "\";";
}
}
void createStringMatcher (OutputStream& out, const String& utf8PointerVariable,
const StringArray& strings, const StringArray& codeToExecute, const int indentLevel)
{
jassert (strings.size() == codeToExecute.size());
auto indent = String::repeatedString (" ", indentLevel);
auto hashMultiplier = findBestHashMultiplier (strings);
out << indent << "unsigned int hash = 0;" << newLine
<< newLine
<< indent << "if (" << utf8PointerVariable << " != nullptr)" << newLine
<< indent << " while (*" << utf8PointerVariable << " != 0)" << newLine
<< indent << " hash = " << (int) hashMultiplier << " * hash + (unsigned int) *" << utf8PointerVariable << "++;" << newLine
<< newLine
<< indent << "switch (hash)" << newLine
<< indent << "{" << newLine;
for (int i = 0; i < strings.size(); ++i)
{
out << indent << " case 0x" << hexString8Digits ((int) calculateHash (strings[i], hashMultiplier))
<< ": " << codeToExecute[i] << newLine;
}
out << indent << " default: break;" << newLine
<< indent << "}" << newLine << newLine;
}
String unixStylePath (const String& path) { return path.replaceCharacter ('\\', '/'); }
String windowsStylePath (const String& path) { return path.replaceCharacter ('/', '\\'); }
String currentOSStylePath (const String& path)
{
#if JUCE_WINDOWS
return windowsStylePath (path);
#else
return unixStylePath (path);
#endif
}
bool isAbsolutePath (const String& path)
{
return File::isAbsolutePath (path)
|| path.startsWithChar ('/') // (needed because File::isAbsolutePath will ignore forward-slashes on Windows)
|| path.startsWithChar ('$')
|| path.startsWithChar ('~')
|| (CharacterFunctions::isLetter (path[0]) && path[1] == ':')
|| path.startsWithIgnoreCase ("smb:");
}
String getRelativePathFrom (const File& file, const File& sourceFolder)
{
#if ! JUCE_WINDOWS
// On a non-windows machine, we can't know if a drive-letter path may be relative or not.
if (CharacterFunctions::isLetter (file.getFullPathName()[0]) && file.getFullPathName()[1] == ':')
return file.getFullPathName();
#endif
return file.getRelativePathFrom (sourceFolder);
}
void writeStreamToFile (const File& file, const std::function<void (MemoryOutputStream&)>& writer)
{
MemoryOutputStream mo;
writer (mo);
overwriteFileIfDifferentOrThrow (file, mo);
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
void overwriteFileIfDifferentOrThrow (const File& file, const MemoryOutputStream& newData)
{
if (! overwriteFileWithNewDataIfDifferent (file, newData))
throw SaveError (file);
}
void overwriteFileIfDifferentOrThrow (const File& file, const String& newData)
{
if (! overwriteFileWithNewDataIfDifferent (file, newData))
throw SaveError (file);
}
String replacePreprocessorDefs (const StringPairArray& definitions, String sourceString)
{
for (int i = 0; i < definitions.size(); ++i)
{
const String key (definitions.getAllKeys()[i]);
const String value (definitions.getAllValues()[i]);
sourceString = sourceString.replace ("${" + key + "}", value);
}
return sourceString;
}
String getXcodePackageType (ProjectType::Target::Type type)
{
using Type = ProjectType::Target::Type;
switch (type)
{
case Type::GUIApp:
case Type::StandalonePlugIn:
return "APPL";
case Type::VSTPlugIn:
case Type::VST3PlugIn:
case Type::AudioUnitPlugIn:
case Type::UnityPlugIn:
return "BNDL";
case Type::AudioUnitv3PlugIn:
return "XPC!";
case Type::AAXPlugIn:
return "TDMw";
case Type::ConsoleApp:
case Type::StaticLibrary:
case Type::DynamicLibrary:
case Type::LV2PlugIn:
case Type::LV2TurtleProgram:
case Type::SharedCodeTarget:
case Type::AggregateTarget:
case Type::unspecified:
default:
return {};
}
}
String getXcodeBundleSignature (ProjectType::Target::Type type)
{
using Type = ProjectType::Target::Type;
switch (type)
{
case Type::GUIApp:
case Type::VSTPlugIn:
case Type::VST3PlugIn:
case Type::AudioUnitPlugIn:
case Type::StandalonePlugIn:
case Type::AudioUnitv3PlugIn:
case Type::UnityPlugIn:
return "????";
case Type::AAXPlugIn:
return "PTul";
case Type::ConsoleApp:
case Type::StaticLibrary:
case Type::DynamicLibrary:
case Type::LV2PlugIn:
case Type::LV2TurtleProgram:
case Type::SharedCodeTarget:
case Type::AggregateTarget:
case Type::unspecified:
default:
return {};
}
}
static unsigned int calculateHash (const String& s, const unsigned int hashMultiplier)
{
auto t = s.toUTF8();
unsigned int hash = 0;
while (*t != 0)
hash = hashMultiplier * hash + (unsigned int) *t++;
return hash;
}
static unsigned int findBestHashMultiplier (const StringArray& strings)
{
unsigned int v = 31;
for (;;)
{
SortedSet<unsigned int> hashes;
bool collision = false;
for (int i = strings.size(); --i >= 0;)
{
auto hash = calculateHash (strings[i], v);
if (hashes.contains (hash))
{
collision = true;
break;
}
hashes.add (hash);
}
if (! collision)
break;
v += 2;
}
return v;
}
String makeValidIdentifier (String s, bool makeCamelCase, bool removeColons, bool allowTemplates, bool allowAsterisks)
{
if (s.isEmpty())
return "unknown";
if (removeColons)
s = s.replaceCharacters (".,;:/@", "______");
else
s = s.replaceCharacters (".,;/@", "_____");
for (int i = s.length(); --i > 0;)
if (CharacterFunctions::isLetter (s[i])
&& CharacterFunctions::isLetter (s[i - 1])
&& CharacterFunctions::isUpperCase (s[i])
&& ! CharacterFunctions::isUpperCase (s[i - 1]))
s = s.substring (0, i) + " " + s.substring (i);
String allowedChars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ 0123456789");
if (allowTemplates)
allowedChars += "<>";
if (! removeColons)
allowedChars += ":";
if (allowAsterisks)
allowedChars += "*";
StringArray words;
words.addTokens (s.retainCharacters (allowedChars), false);
words.trim();
auto n = words[0];
if (makeCamelCase)
n = n.toLowerCase();
for (int i = 1; i < words.size(); ++i)
{
if (makeCamelCase && words[i].length() > 1)
n << words[i].substring (0, 1).toUpperCase()
<< words[i].substring (1).toLowerCase();
else
n << words[i];
}
if (CharacterFunctions::isDigit (n[0]))
n = "_" + n;
if (isReservedKeyword (n))
n << '_';
return n;
}
String makeBinaryDataIdentifierName (const File& file)
{
return makeValidIdentifier (file.getFileName()
.replaceCharacters (" .", "__")
.retainCharacters ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"),
false, true, false);
}
void writeDataAsCppLiteral (const MemoryBlock& mb, OutputStream& out,
bool breakAtNewLines, bool allowStringBreaks)
{
const int maxCharsOnLine = 250;
auto data = (const unsigned char*) mb.getData();
int charsOnLine = 0;
bool canUseStringLiteral = mb.getSize() < 32768; // MS compilers can't handle big string literals..
if (canUseStringLiteral)
{
unsigned int numEscaped = 0;
for (size_t i = 0; i < mb.getSize(); ++i)
{
auto num = (unsigned int) data[i];
if (! ((num >= 32 && num < 127) || num == '\t' || num == '\r' || num == '\n'))
{
if (++numEscaped > mb.getSize() / 4)
{
canUseStringLiteral = false;
break;
}
}
}
}
if (! canUseStringLiteral)
{
out << "{ ";
for (size_t i = 0; i < mb.getSize(); ++i)
{
auto num = (int) (unsigned int) data[i];
out << num << ',';
charsOnLine += 2;
if (num >= 10)
{
++charsOnLine;
if (num >= 100)
++charsOnLine;
}
if (charsOnLine >= maxCharsOnLine)
{
charsOnLine = 0;
out << newLine;
}
}
out << "0,0 };";
}
else
{
out << "\"";
writeEscapeChars (out, (const char*) data, (int) mb.getSize(),
maxCharsOnLine, breakAtNewLines, false, allowStringBreaks);
out << "\";";
}
}
void createStringMatcher (OutputStream& out, const String& utf8PointerVariable,
const StringArray& strings, const StringArray& codeToExecute, const int indentLevel)
{
jassert (strings.size() == codeToExecute.size());
auto indent = String::repeatedString (" ", indentLevel);
auto hashMultiplier = findBestHashMultiplier (strings);
out << indent << "unsigned int hash = 0;" << newLine
<< newLine
<< indent << "if (" << utf8PointerVariable << " != nullptr)" << newLine
<< indent << " while (*" << utf8PointerVariable << " != 0)" << newLine
<< indent << " hash = " << (int) hashMultiplier << " * hash + (unsigned int) *" << utf8PointerVariable << "++;" << newLine
<< newLine
<< indent << "switch (hash)" << newLine
<< indent << "{" << newLine;
for (int i = 0; i < strings.size(); ++i)
{
out << indent << " case 0x" << hexString8Digits ((int) calculateHash (strings[i], hashMultiplier))
<< ": " << codeToExecute[i] << newLine;
}
out << indent << " default: break;" << newLine
<< indent << "}" << newLine << newLine;
}
String unixStylePath (const String& path) { return path.replaceCharacter ('\\', '/'); }
String windowsStylePath (const String& path) { return path.replaceCharacter ('/', '\\'); }
String currentOSStylePath (const String& path)
{
#if JUCE_WINDOWS
return windowsStylePath (path);
#else
return unixStylePath (path);
#endif
}
bool isAbsolutePath (const String& path)
{
return File::isAbsolutePath (path)
|| path.startsWithChar ('/') // (needed because File::isAbsolutePath will ignore forward-slashes on Windows)
|| path.startsWithChar ('$')
|| path.startsWithChar ('~')
|| (CharacterFunctions::isLetter (path[0]) && path[1] == ':')
|| path.startsWithIgnoreCase ("smb:");
}
String getRelativePathFrom (const File& file, const File& sourceFolder)
{
#if ! JUCE_WINDOWS
// On a non-windows machine, we can't know if a drive-letter path may be relative or not.
if (CharacterFunctions::isLetter (file.getFullPathName()[0]) && file.getFullPathName()[1] == ':')
return file.getFullPathName();
#endif
return file.getRelativePathFrom (sourceFolder);
}
void writeStreamToFile (const File& file, const std::function<void (MemoryOutputStream&)>& writer)
{
MemoryOutputStream mo;
writer (mo);
overwriteFileIfDifferentOrThrow (file, mo);
}
}
}

View File

@ -1,86 +1,86 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
void overwriteFileIfDifferentOrThrow (const File& file, const MemoryOutputStream& newData);
void overwriteFileIfDifferentOrThrow (const File& file, const String& newData);
class SaveError
{
public:
SaveError (const String& error) : message (error)
{}
SaveError (const File& fileThatFailedToWrite)
: message ("Can't write to the file: " + fileThatFailedToWrite.getFullPathName())
{}
String message;
};
String replacePreprocessorDefs (const StringPairArray& definitions, String sourceString);
String getXcodePackageType (ProjectType::Target::Type);
String getXcodeBundleSignature (ProjectType::Target::Type);
inline String hexString8Digits (int value)
{
return String::toHexString (value).paddedLeft ('0', 8);
}
String makeValidIdentifier (String s,
bool makeCamelCase,
bool removeColons,
bool allowTemplates,
bool allowAsterisks = false);
String makeBinaryDataIdentifierName (const File& file);
void writeDataAsCppLiteral (const MemoryBlock& mb,
OutputStream& out,
bool breakAtNewLines,
bool allowStringBreaks);
void createStringMatcher (OutputStream& out,
const String& utf8PointerVariable,
const StringArray& strings,
const StringArray& codeToExecute,
const int indentLevel);
String unixStylePath (const String& path);
String windowsStylePath (const String& path);
String currentOSStylePath (const String& path);
bool isAbsolutePath (const String& path);
// A windows-aware version of File::getRelativePath()
String getRelativePathFrom (const File& file, const File& sourceFolder);
void writeStreamToFile (const File& file, const std::function<void (MemoryOutputStream&)>& writer);
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
void overwriteFileIfDifferentOrThrow (const File& file, const MemoryOutputStream& newData);
void overwriteFileIfDifferentOrThrow (const File& file, const String& newData);
class SaveError
{
public:
SaveError (const String& error) : message (error)
{}
SaveError (const File& fileThatFailedToWrite)
: message ("Can't write to the file: " + fileThatFailedToWrite.getFullPathName())
{}
String message;
};
String replacePreprocessorDefs (const StringPairArray& definitions, String sourceString);
String getXcodePackageType (ProjectType::Target::Type);
String getXcodeBundleSignature (ProjectType::Target::Type);
inline String hexString8Digits (int value)
{
return String::toHexString (value).paddedLeft ('0', 8);
}
String makeValidIdentifier (String s,
bool makeCamelCase,
bool removeColons,
bool allowTemplates,
bool allowAsterisks = false);
String makeBinaryDataIdentifierName (const File& file);
void writeDataAsCppLiteral (const MemoryBlock& mb,
OutputStream& out,
bool breakAtNewLines,
bool allowStringBreaks);
void createStringMatcher (OutputStream& out,
const String& utf8PointerVariable,
const StringArray& strings,
const StringArray& codeToExecute,
const int indentLevel);
String unixStylePath (const String& path);
String windowsStylePath (const String& path);
String currentOSStylePath (const String& path);
bool isAbsolutePath (const String& path);
// A windows-aware version of File::getRelativePath()
String getRelativePathFrom (const File& file, const File& sourceFolder);
void writeStreamToFile (const File& file, const std::function<void (MemoryOutputStream&)>& writer);
}
}

View File

@ -1,206 +1,206 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
{
static const char* const keywords2Char[] =
{ "do", "if", "or", nullptr };
static const char* const keywords3Char[] =
{ "and", "asm", "for", "int", "new", "not", "try", "xor", nullptr };
static const char* const keywords4Char[] =
{ "auto", "bool", "case", "char", "else", "enum", "goto",
"long", "this", "true", "void", nullptr };
static const char* const keywords5Char[] =
{ "bitor", "break", "catch", "class", "compl", "const", "false", "final",
"float", "or_eq", "short", "throw", "union", "using", "while", nullptr };
static const char* const keywords6Char[] =
{ "and_eq", "bitand", "delete", "double", "export", "extern", "friend",
"import", "inline", "module", "not_eq", "public", "return", "signed",
"sizeof", "static", "struct", "switch", "typeid", "xor_eq", nullptr };
static const char* const keywords7Char[] =
{ "__cdecl", "_Pragma", "alignas", "alignof", "concept", "default",
"mutable", "nullptr", "private", "typedef", "uint8_t", "virtual",
"wchar_t", nullptr };
static const char* const keywordsOther[] =
{ "@class", "@dynamic", "@end", "@implementation", "@interface", "@public",
"@private", "@protected", "@property", "@synthesize", "__fastcall", "__stdcall",
"atomic_cancel", "atomic_commit", "atomic_noexcept", "char16_t", "char32_t",
"co_await", "co_return", "co_yield", "const_cast", "constexpr", "continue",
"decltype", "dynamic_cast", "explicit", "namespace", "noexcept", "operator", "override",
"protected", "register", "reinterpret_cast", "requires", "static_assert",
"static_cast", "synchronized", "template", "thread_local", "typename", "unsigned",
"volatile", nullptr };
const char* const* k;
switch (tokenLength)
{
case 2: k = keywords2Char; break;
case 3: k = keywords3Char; break;
case 4: k = keywords4Char; break;
case 5: k = keywords5Char; break;
case 6: k = keywords6Char; break;
case 7: k = keywords7Char; break;
default:
if (tokenLength < 2 || tokenLength > 16)
return false;
k = keywordsOther;
break;
}
for (int i = 0; k[i] != nullptr; ++i)
if (token.compare (CharPointer_ASCII (k[i])) == 0)
return true;
return false;
}
static bool isReservedKeyword (const String& token) noexcept
{
return isReservedKeyword (token.getCharPointer(), token.length());
}
//==============================================================================
/** Takes a UTF8 string and writes it to a stream using standard C++ escape sequences for any
non-ascii bytes.
Although not strictly a tokenising function, this is still a function that often comes in
handy when working with C++ code!
Note that addEscapeChars() is easier to use than this function if you're working with Strings.
@see addEscapeChars
*/
static void writeEscapeChars (OutputStream& out, const char* utf8, const int numBytesToRead,
const int maxCharsOnLine, const bool breakAtNewLines,
const bool replaceSingleQuotes, const bool allowStringBreaks)
{
int charsOnLine = 0;
bool lastWasHexEscapeCode = false;
bool trigraphDetected = false;
for (int i = 0; i < numBytesToRead || numBytesToRead < 0; ++i)
{
auto c = (unsigned char) utf8[i];
bool startNewLine = false;
switch (c)
{
case '\t': out << "\\t"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
case '\r': out << "\\r"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
case '\n': out << "\\n"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; startNewLine = breakAtNewLines; break;
case '\\': out << "\\\\"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
case '\"': out << "\\\""; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
case '?':
if (trigraphDetected)
{
out << "\\?";
charsOnLine++;
trigraphDetected = false;
}
else
{
out << "?";
trigraphDetected = true;
}
lastWasHexEscapeCode = false;
charsOnLine++;
break;
case 0:
if (numBytesToRead < 0)
return;
out << "\\0";
lastWasHexEscapeCode = true;
trigraphDetected = false;
charsOnLine += 2;
break;
case '\'':
if (replaceSingleQuotes)
{
out << "\\\'";
lastWasHexEscapeCode = false;
trigraphDetected = false;
charsOnLine += 2;
break;
}
// deliberate fall-through...
default:
if (c >= 32 && c < 127 && ! (lastWasHexEscapeCode // (have to avoid following a hex escape sequence with a valid hex digit)
&& CharacterFunctions::getHexDigitValue (c) >= 0))
{
out << (char) c;
lastWasHexEscapeCode = false;
trigraphDetected = false;
++charsOnLine;
}
else if (allowStringBreaks && lastWasHexEscapeCode && c >= 32 && c < 127)
{
out << "\"\"" << (char) c;
lastWasHexEscapeCode = false;
trigraphDetected = false;
charsOnLine += 3;
}
else
{
out << (c < 16 ? "\\x0" : "\\x") << String::toHexString ((int) c);
lastWasHexEscapeCode = true;
trigraphDetected = false;
charsOnLine += 4;
}
break;
}
if ((startNewLine || (maxCharsOnLine > 0 && charsOnLine >= maxCharsOnLine))
&& (numBytesToRead < 0 || i < numBytesToRead - 1))
{
charsOnLine = 0;
out << "\"" << newLine << "\"";
lastWasHexEscapeCode = false;
}
}
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
{
static const char* const keywords2Char[] =
{ "do", "if", "or", nullptr };
static const char* const keywords3Char[] =
{ "and", "asm", "for", "int", "new", "not", "try", "xor", nullptr };
static const char* const keywords4Char[] =
{ "auto", "bool", "case", "char", "else", "enum", "goto",
"long", "this", "true", "void", nullptr };
static const char* const keywords5Char[] =
{ "bitor", "break", "catch", "class", "compl", "const", "false", "final",
"float", "or_eq", "short", "throw", "union", "using", "while", nullptr };
static const char* const keywords6Char[] =
{ "and_eq", "bitand", "delete", "double", "export", "extern", "friend",
"import", "inline", "module", "not_eq", "public", "return", "signed",
"sizeof", "static", "struct", "switch", "typeid", "xor_eq", nullptr };
static const char* const keywords7Char[] =
{ "__cdecl", "_Pragma", "alignas", "alignof", "concept", "default",
"mutable", "nullptr", "private", "typedef", "uint8_t", "virtual",
"wchar_t", nullptr };
static const char* const keywordsOther[] =
{ "@class", "@dynamic", "@end", "@implementation", "@interface", "@public",
"@private", "@protected", "@property", "@synthesize", "__fastcall", "__stdcall",
"atomic_cancel", "atomic_commit", "atomic_noexcept", "char16_t", "char32_t",
"co_await", "co_return", "co_yield", "const_cast", "constexpr", "continue",
"decltype", "dynamic_cast", "explicit", "namespace", "noexcept", "operator", "override",
"protected", "register", "reinterpret_cast", "requires", "static_assert",
"static_cast", "synchronized", "template", "thread_local", "typename", "unsigned",
"volatile", nullptr };
const char* const* k;
switch (tokenLength)
{
case 2: k = keywords2Char; break;
case 3: k = keywords3Char; break;
case 4: k = keywords4Char; break;
case 5: k = keywords5Char; break;
case 6: k = keywords6Char; break;
case 7: k = keywords7Char; break;
default:
if (tokenLength < 2 || tokenLength > 16)
return false;
k = keywordsOther;
break;
}
for (int i = 0; k[i] != nullptr; ++i)
if (token.compare (CharPointer_ASCII (k[i])) == 0)
return true;
return false;
}
static bool isReservedKeyword (const String& token) noexcept
{
return isReservedKeyword (token.getCharPointer(), token.length());
}
//==============================================================================
/** Takes a UTF8 string and writes it to a stream using standard C++ escape sequences for any
non-ascii bytes.
Although not strictly a tokenising function, this is still a function that often comes in
handy when working with C++ code!
Note that addEscapeChars() is easier to use than this function if you're working with Strings.
@see addEscapeChars
*/
static void writeEscapeChars (OutputStream& out, const char* utf8, const int numBytesToRead,
const int maxCharsOnLine, const bool breakAtNewLines,
const bool replaceSingleQuotes, const bool allowStringBreaks)
{
int charsOnLine = 0;
bool lastWasHexEscapeCode = false;
bool trigraphDetected = false;
for (int i = 0; i < numBytesToRead || numBytesToRead < 0; ++i)
{
auto c = (unsigned char) utf8[i];
bool startNewLine = false;
switch (c)
{
case '\t': out << "\\t"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
case '\r': out << "\\r"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
case '\n': out << "\\n"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; startNewLine = breakAtNewLines; break;
case '\\': out << "\\\\"; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
case '\"': out << "\\\""; trigraphDetected = false; lastWasHexEscapeCode = false; charsOnLine += 2; break;
case '?':
if (trigraphDetected)
{
out << "\\?";
charsOnLine++;
trigraphDetected = false;
}
else
{
out << "?";
trigraphDetected = true;
}
lastWasHexEscapeCode = false;
charsOnLine++;
break;
case 0:
if (numBytesToRead < 0)
return;
out << "\\0";
lastWasHexEscapeCode = true;
trigraphDetected = false;
charsOnLine += 2;
break;
case '\'':
if (replaceSingleQuotes)
{
out << "\\\'";
lastWasHexEscapeCode = false;
trigraphDetected = false;
charsOnLine += 2;
break;
}
// deliberate fall-through...
default:
if (c >= 32 && c < 127 && ! (lastWasHexEscapeCode // (have to avoid following a hex escape sequence with a valid hex digit)
&& CharacterFunctions::getHexDigitValue (c) >= 0))
{
out << (char) c;
lastWasHexEscapeCode = false;
trigraphDetected = false;
++charsOnLine;
}
else if (allowStringBreaks && lastWasHexEscapeCode && c >= 32 && c < 127)
{
out << "\"\"" << (char) c;
lastWasHexEscapeCode = false;
trigraphDetected = false;
charsOnLine += 3;
}
else
{
out << (c < 16 ? "\\x0" : "\\x") << String::toHexString ((int) c);
lastWasHexEscapeCode = true;
trigraphDetected = false;
charsOnLine += 4;
}
break;
}
if ((startNewLine || (maxCharsOnLine > 0 && charsOnLine >= maxCharsOnLine))
&& (numBytesToRead < 0 || i < numBytesToRead - 1))
{
charsOnLine = 0;
out << "\"" << newLine << "\"";
lastWasHexEscapeCode = false;
}
}
}
}
}

View File

@ -1,119 +1,133 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
String EntitlementOptions::getEntitlementsFileContent() const
{
String content =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n"
"<dict>\n";
const auto entitlements = getEntitlements();
for (auto& key : entitlements.getAllKeys())
content += "\t<key>" + key + "</key>\n\t" + entitlements[key] + "\n";
return content + "</dict>\n</plist>\n";
}
StringPairArray EntitlementOptions::getEntitlements() const
{
StringPairArray entitlements;
if (isiOS)
{
if (isAudioPluginProject && shouldEnableIAA)
entitlements.set ("inter-app-audio", "<true/>");
if (isiCloudPermissionsEnabled)
{
entitlements.set ("com.apple.developer.icloud-container-identifiers",
"<array>\n"
" <string>iCloud.$(CFBundleIdentifier)</string>\n"
" </array>");
entitlements.set ("com.apple.developer.icloud-services",
"<array>\n"
" <string>CloudDocuments</string>\n"
" </array>");
entitlements.set ("com.apple.developer.ubiquity-container-identifiers",
"<array>\n"
" <string>iCloud.$(CFBundleIdentifier)</string>\n"
" </array>");
}
}
if (isPushNotificationsEnabled)
entitlements.set (isiOS ? "aps-environment"
: "com.apple.developer.aps-environment",
"<string>development</string>");
if (isAppGroupsEnabled)
{
auto appGroups = StringArray::fromTokens (appGroupIdString, ";", {});
auto groups = String ("<array>");
for (auto group : appGroups)
groups += "\n\t\t<string>" + group.trim() + "</string>";
groups += "\n\t</array>";
entitlements.set ("com.apple.security.application-groups", groups);
}
if (isHardenedRuntimeEnabled)
for (auto& option : hardenedRuntimeOptions)
entitlements.set (option, "<true/>");
if (isAppSandboxEnabled || (! isiOS && isAudioPluginProject && type == ProjectType::Target::AudioUnitv3PlugIn))
{
entitlements.set ("com.apple.security.app-sandbox", "<true/>");
if (isAppSandboxInhertianceEnabled)
{
// no other sandbox options can be specified if sandbox inheritance is enabled!
jassert (appSandboxOptions.isEmpty());
entitlements.set ("com.apple.security.inherit", "<true/>");
}
if (isAppSandboxEnabled)
for (auto& option : appSandboxOptions)
entitlements.set (option, "<true/>");
}
if (isNetworkingMulticastEnabled)
entitlements.set ("com.apple.developer.networking.multicast", "<true/>");
return entitlements;
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
String EntitlementOptions::getEntitlementsFileContent() const
{
String content =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n"
"<dict>\n";
const auto entitlements = getEntitlements();
for (auto& key : entitlements.getAllKeys())
content += "\t<key>" + key + "</key>\n\t" + entitlements[key] + "\n";
return content + "</dict>\n</plist>\n";
}
StringPairArray EntitlementOptions::getEntitlements() const
{
StringPairArray entitlements;
if (isiOS)
{
if (isAudioPluginProject && shouldEnableIAA)
entitlements.set ("inter-app-audio", "<true/>");
if (isiCloudPermissionsEnabled)
{
entitlements.set ("com.apple.developer.icloud-container-identifiers",
"<array>\n"
" <string>iCloud.$(CFBundleIdentifier)</string>\n"
" </array>");
entitlements.set ("com.apple.developer.icloud-services",
"<array>\n"
" <string>CloudDocuments</string>\n"
" </array>");
entitlements.set ("com.apple.developer.ubiquity-container-identifiers",
"<array>\n"
" <string>iCloud.$(CFBundleIdentifier)</string>\n"
" </array>");
}
}
if (isPushNotificationsEnabled)
entitlements.set (isiOS ? "aps-environment"
: "com.apple.developer.aps-environment",
"<string>development</string>");
if (isAppGroupsEnabled)
{
auto appGroups = StringArray::fromTokens (appGroupIdString, ";", {});
String groups = "<array>";
for (auto group : appGroups)
groups += "\n\t\t<string>" + group.trim() + "</string>";
groups += "\n\t</array>";
entitlements.set ("com.apple.security.application-groups", groups);
}
if (isHardenedRuntimeEnabled)
for (auto& option : hardenedRuntimeOptions)
entitlements.set (option, "<true/>");
if (isAppSandboxEnabled || (! isiOS && isAudioPluginProject && type == ProjectType::Target::AudioUnitv3PlugIn))
{
entitlements.set ("com.apple.security.app-sandbox", "<true/>");
if (isAppSandboxInhertianceEnabled)
{
// no other sandbox options can be specified if sandbox inheritance is enabled!
jassert (appSandboxOptions.isEmpty());
jassert (appSandboxTemporaryPaths.empty());
entitlements.set ("com.apple.security.inherit", "<true/>");
}
if (isAppSandboxEnabled)
{
for (auto& option : appSandboxOptions)
entitlements.set (option, "<true/>");
for (auto& option : appSandboxTemporaryPaths)
{
String paths = "<array>";
for (const auto& path : option.values)
paths += "\n\t\t<string>" + path + "</string>";
paths += "\n\t</array>";
entitlements.set (option.key, paths);
}
}
}
if (isNetworkingMulticastEnabled)
entitlements.set ("com.apple.developer.networking.multicast", "<true/>");
return entitlements;
}
}
}

View File

@ -1,56 +1,64 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
struct EntitlementOptions final
{
String getEntitlementsFileContent() const;
ProjectType::Target::Type type = ProjectType::Target::GUIApp;
bool isiOS = false;
bool isAudioPluginProject = false;
bool shouldEnableIAA = false;
bool isiCloudPermissionsEnabled = false;
bool isPushNotificationsEnabled = false;
bool isAppGroupsEnabled = false;
bool isHardenedRuntimeEnabled = false;
bool isAppSandboxEnabled = false;
bool isAppSandboxInhertianceEnabled = false;
bool isNetworkingMulticastEnabled = false;
String appGroupIdString;
StringArray hardenedRuntimeOptions;
StringArray appSandboxOptions;
private:
StringPairArray getEntitlements() const;
};
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
struct EntitlementOptions final
{
String getEntitlementsFileContent() const;
ProjectType::Target::Type type = ProjectType::Target::GUIApp;
bool isiOS = false;
bool isAudioPluginProject = false;
bool shouldEnableIAA = false;
bool isiCloudPermissionsEnabled = false;
bool isPushNotificationsEnabled = false;
bool isAppGroupsEnabled = false;
bool isHardenedRuntimeEnabled = false;
bool isAppSandboxEnabled = false;
bool isAppSandboxInhertianceEnabled = false;
bool isNetworkingMulticastEnabled = false;
String appGroupIdString;
StringArray hardenedRuntimeOptions;
StringArray appSandboxOptions;
struct KeyAndStringArray
{
String key;
StringArray values;
};
std::vector<KeyAndStringArray> appSandboxTemporaryPaths;
private:
StringPairArray getEntitlements() const;
};
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,49 +1,49 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
struct Icons
{
std::unique_ptr<Drawable> small;
std::unique_ptr<Drawable> big;
};
Array<Drawable*> asArray (const Icons&);
void writeMacIcon (const Icons&, const File&);
void writeWinIcon (const Icons&, const File&);
Image getBestIconForSize (const Icons& icons,
int size,
bool returnNullIfNothingBigEnough);
Image rescaleImageForIcon (Drawable& d, const int size);
RelativePath createXcassetsFolderFromIcons (const Icons& icons,
const File& targetFolder,
String projectFilenameRootString);
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
struct Icons
{
std::unique_ptr<Drawable> small;
std::unique_ptr<Drawable> big;
};
Array<Drawable*> asArray (const Icons&);
void writeMacIcon (const Icons&, const File&);
void writeWinIcon (const Icons&, const File&);
Image getBestIconForSize (const Icons& icons,
int size,
bool returnNullIfNothingBigEnough);
Image rescaleImageForIcon (Drawable& d, const int size);
RelativePath createXcassetsFolderFromIcons (const Icons& icons,
const File& targetFolder,
String projectFilenameRootString);
}
}

View File

@ -1,370 +1,378 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
//==============================================================================
static XmlElement* getKeyWithName (XmlElement& xml, const String& key)
{
for (auto* element : xml.getChildWithTagNameIterator ("key"))
if (element->getAllSubText().trim().equalsIgnoreCase (key))
return element;
return nullptr;
}
static bool keyFoundAndNotSequentialDuplicate (XmlElement& xml, const String& key)
{
if (auto* element = getKeyWithName (xml, key))
{
if (element->getNextElement() != nullptr && element->getNextElement()->hasTagName ("key"))
{
// found broken plist format (sequential duplicate), fix by removing
xml.removeChildElement (element, true);
return false;
}
// key found (not sequential duplicate)
return true;
}
// key not found
return false;
}
static bool addKeyIfNotFound (XmlElement& xml, const String& key)
{
if (! keyFoundAndNotSequentialDuplicate (xml, key))
{
xml.createNewChildElement ("key")->addTextElement (key);
return true;
}
return false;
}
static void addPlistDictionaryKey (XmlElement& xml, const String& key, const String& value)
{
if (addKeyIfNotFound (xml, key))
xml.createNewChildElement ("string")->addTextElement (value);
}
template <size_t N>
static void addPlistDictionaryKey (XmlElement& xml, const String& key, const char (&value) [N])
{
addPlistDictionaryKey (xml, key, String { value });
}
static void addPlistDictionaryKey (XmlElement& xml, const String& key, const bool value)
{
if (addKeyIfNotFound (xml, key))
xml.createNewChildElement (value ? "true" : "false");
}
static void addPlistDictionaryKey (XmlElement& xml, const String& key, int value)
{
if (addKeyIfNotFound (xml, key))
xml.createNewChildElement ("integer")->addTextElement (String (value));
}
static void addArrayToPlist (XmlElement& dict, String arrayKey, const StringArray& arrayElements)
{
if (getKeyWithName (dict, arrayKey) != nullptr)
return;
dict.createNewChildElement ("key")->addTextElement (arrayKey);
auto* plistStringArray = dict.createNewChildElement ("array");
for (auto& e : arrayElements)
plistStringArray->createNewChildElement ("string")->addTextElement (e);
}
static int getAUVersionAsHexInteger (const PlistOptions& opts)
{
const auto segments = getVersionSegments (opts.marketingVersion);
const StringArray trimmed (segments.strings.getRawDataPointer(), jmin (segments.size(), 3));
return getVersionAsHexIntegerFromParts (trimmed);
}
//==============================================================================
void PlistOptions::write (const File& infoPlistFile) const
{
writeStreamToFile (infoPlistFile, [&] (MemoryOutputStream& mo) { write (mo); });
}
void PlistOptions::write (MemoryOutputStream& mo) const
{
XmlElement::TextFormat format;
format.dtd = "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
createXML()->writeTo (mo, format);
}
std::unique_ptr<XmlElement> PlistOptions::createXML() const
{
auto plist = parseXML (plistToMerge);
if (plist == nullptr || ! plist->hasTagName ("plist"))
plist.reset (new XmlElement ("plist"));
auto* dict = plist->getChildByName ("dict");
if (dict == nullptr)
dict = plist->createNewChildElement ("dict");
if (microphonePermissionEnabled)
addPlistDictionaryKey (*dict, "NSMicrophoneUsageDescription", microphonePermissionText);
if (cameraPermissionEnabled)
addPlistDictionaryKey (*dict, "NSCameraUsageDescription", cameraPermissionText);
if (bluetoothPermissionEnabled)
addPlistDictionaryKey (*dict, "NSBluetoothAlwaysUsageDescription", bluetoothPermissionText);
if (iOS)
{
if (bluetoothPermissionEnabled)
addPlistDictionaryKey (*dict, "NSBluetoothPeripheralUsageDescription", bluetoothPermissionText); // needed for pre iOS 13.0
addPlistDictionaryKey (*dict, "LSRequiresIPhoneOS", true);
addPlistDictionaryKey (*dict, "UIViewControllerBasedStatusBarAppearance", true);
if (shouldAddStoryboardToProject)
addPlistDictionaryKey (*dict, "UILaunchStoryboardName", storyboardName);
}
else
{
if (sendAppleEventsPermissionEnabled)
addPlistDictionaryKey (*dict, "NSAppleEventsUsageDescription", sendAppleEventsPermissionText);
}
addPlistDictionaryKey (*dict, "CFBundleExecutable", executableName);
if (! iOS) // (NB: on iOS this causes error ITMS-90032 during publishing)
addPlistDictionaryKey (*dict, "CFBundleIconFile", iconFile.exists() ? iconFile.getFileName() : String());
addPlistDictionaryKey (*dict, "CFBundleIdentifier", bundleIdentifier);
addPlistDictionaryKey (*dict, "CFBundleName", projectName);
// needed by NSExtension on iOS
addPlistDictionaryKey (*dict, "CFBundleDisplayName", projectName);
addPlistDictionaryKey (*dict, "CFBundlePackageType", getXcodePackageType (type));
addPlistDictionaryKey (*dict, "CFBundleSignature", getXcodeBundleSignature (type));
addPlistDictionaryKey (*dict, "CFBundleShortVersionString", marketingVersion);
addPlistDictionaryKey (*dict, "CFBundleVersion", currentProjectVersion);
addPlistDictionaryKey (*dict, "NSHumanReadableCopyright", companyCopyright);
addPlistDictionaryKey (*dict, "NSHighResolutionCapable", true);
if (applicationCategory.isNotEmpty())
addPlistDictionaryKey (*dict, "LSApplicationCategoryType", applicationCategory);
auto replacedDocExtensions = StringArray::fromTokens (replacePreprocessorDefs (allPreprocessorDefs,
documentExtensions), ",", {});
replacedDocExtensions.trim();
replacedDocExtensions.removeEmptyStrings (true);
if (! replacedDocExtensions.isEmpty() && type != ProjectType::Target::AudioUnitv3PlugIn)
{
dict->createNewChildElement ("key")->addTextElement ("CFBundleDocumentTypes");
auto* dict2 = dict->createNewChildElement ("array")->createNewChildElement ("dict");
XmlElement* arrayTag = nullptr;
for (auto ex : replacedDocExtensions)
{
if (ex.startsWithChar ('.'))
ex = ex.substring (1);
if (arrayTag == nullptr)
{
dict2->createNewChildElement ("key")->addTextElement ("CFBundleTypeExtensions");
arrayTag = dict2->createNewChildElement ("array");
addPlistDictionaryKey (*dict2, "CFBundleTypeName", ex);
addPlistDictionaryKey (*dict2, "CFBundleTypeRole", "Editor");
addPlistDictionaryKey (*dict2, "CFBundleTypeIconFile", "Icon");
addPlistDictionaryKey (*dict2, "NSPersistentStoreTypeKey", "XML");
}
arrayTag->createNewChildElement ("string")->addTextElement (ex);
}
}
if (fileSharingEnabled && type != ProjectType::Target::AudioUnitv3PlugIn)
addPlistDictionaryKey (*dict, "UIFileSharingEnabled", true);
if (documentBrowserEnabled)
addPlistDictionaryKey (*dict, "UISupportsDocumentBrowser", true);
if (iOS)
{
if (type != ProjectType::Target::AudioUnitv3PlugIn)
{
if (statusBarHidden)
addPlistDictionaryKey (*dict, "UIStatusBarHidden", true);
addPlistDictionaryKey (*dict, "UIRequiresFullScreen", requiresFullScreen);
addIosScreenOrientations (*dict);
addIosBackgroundModes (*dict);
}
if (type == ProjectType::Target::StandalonePlugIn && enableIAA)
{
XmlElement audioComponentsPlistKey ("key");
audioComponentsPlistKey.addTextElement ("AudioComponents");
dict->addChildElement (new XmlElement (audioComponentsPlistKey));
XmlElement audioComponentsPlistEntry ("array");
auto* audioComponentsDict = audioComponentsPlistEntry.createNewChildElement ("dict");
addPlistDictionaryKey (*audioComponentsDict, "name", IAAPluginName);
addPlistDictionaryKey (*audioComponentsDict, "manufacturer", pluginManufacturerCode.substring (0, 4));
addPlistDictionaryKey (*audioComponentsDict, "type", IAATypeCode);
addPlistDictionaryKey (*audioComponentsDict, "subtype", pluginCode.substring (0, 4));
addPlistDictionaryKey (*audioComponentsDict, "version", getVersionAsHexInteger (marketingVersion));
dict->addChildElement (new XmlElement (audioComponentsPlistEntry));
}
}
const auto extraOptions = [&]() -> Array<XmlElement>
{
if (type == ProjectType::Target::Type::AudioUnitPlugIn)
return createExtraAudioUnitTargetPlistOptions();
if (type == ProjectType::Target::Type::AudioUnitv3PlugIn)
return createExtraAudioUnitV3TargetPlistOptions();
return {};
}();
for (auto& e : extraOptions)
dict->addChildElement (new XmlElement (e));
return plist;
}
void PlistOptions::addIosScreenOrientations (XmlElement& dict) const
{
addArrayToPlist (dict, "UISupportedInterfaceOrientations", iPhoneScreenOrientations);
if (iPadScreenOrientations != iPhoneScreenOrientations)
addArrayToPlist (dict, "UISupportedInterfaceOrientations~ipad", iPadScreenOrientations);
}
void PlistOptions::addIosBackgroundModes (XmlElement& dict) const
{
StringArray iosBackgroundModes;
if (backgroundAudioEnabled) iosBackgroundModes.add ("audio");
if (backgroundBleEnabled) iosBackgroundModes.add ("bluetooth-central");
if (pushNotificationsEnabled) iosBackgroundModes.add ("remote-notification");
addArrayToPlist (dict, "UIBackgroundModes", iosBackgroundModes);
}
Array<XmlElement> PlistOptions::createExtraAudioUnitTargetPlistOptions() const
{
XmlElement plistKey ("key");
plistKey.addTextElement ("AudioComponents");
XmlElement plistEntry ("array");
auto* dict = plistEntry.createNewChildElement ("dict");
auto truncatedCode = pluginManufacturerCode.substring (0, 4);
auto pluginSubType = pluginCode.substring (0, 4);
if (truncatedCode.toLowerCase() == truncatedCode)
{
throw SaveError ("AudioUnit plugin code identifiers invalid!\n\n"
"You have used only lower case letters in your AU plugin manufacturer identifier. "
"You must have at least one uppercase letter in your AU plugin manufacturer "
"identifier code.");
}
addPlistDictionaryKey (*dict, "name", pluginManufacturer + ": " + pluginName);
addPlistDictionaryKey (*dict, "description", pluginDescription);
addPlistDictionaryKey (*dict, "factoryFunction", pluginAUExportPrefix + "Factory");
addPlistDictionaryKey (*dict, "manufacturer", truncatedCode);
addPlistDictionaryKey (*dict, "type", auMainType.removeCharacters ("'"));
addPlistDictionaryKey (*dict, "subtype", pluginSubType);
addPlistDictionaryKey (*dict, "version", getAUVersionAsHexInteger (*this));
if (isAuSandboxSafe)
{
addPlistDictionaryKey (*dict, "sandboxSafe", true);
}
else if (! suppressResourceUsage)
{
dict->createNewChildElement ("key")->addTextElement ("resourceUsage");
auto* resourceUsageDict = dict->createNewChildElement ("dict");
addPlistDictionaryKey (*resourceUsageDict, "network.client", true);
addPlistDictionaryKey (*resourceUsageDict, "temporary-exception.files.all.read-write", true);
}
return { plistKey, plistEntry };
}
Array<XmlElement> PlistOptions::createExtraAudioUnitV3TargetPlistOptions() const
{
XmlElement plistKey ("key");
plistKey.addTextElement ("NSExtension");
XmlElement plistEntry ("dict");
addPlistDictionaryKey (plistEntry, "NSExtensionPrincipalClass", pluginAUExportPrefix + "FactoryAUv3");
addPlistDictionaryKey (plistEntry, "NSExtensionPointIdentifier", "com.apple.AudioUnit-UI");
plistEntry.createNewChildElement ("key")->addTextElement ("NSExtensionAttributes");
auto* dict = plistEntry.createNewChildElement ("dict");
dict->createNewChildElement ("key")->addTextElement ("AudioComponents");
auto* componentArray = dict->createNewChildElement ("array");
auto* componentDict = componentArray->createNewChildElement ("dict");
addPlistDictionaryKey (*componentDict, "name", pluginManufacturer + ": " + pluginName);
addPlistDictionaryKey (*componentDict, "description", pluginDescription);
addPlistDictionaryKey (*componentDict, "factoryFunction", pluginAUExportPrefix + "FactoryAUv3");
addPlistDictionaryKey (*componentDict, "manufacturer", pluginManufacturerCode.substring (0, 4));
addPlistDictionaryKey (*componentDict, "type", auMainType.removeCharacters ("'"));
addPlistDictionaryKey (*componentDict, "subtype", pluginCode.substring (0, 4));
addPlistDictionaryKey (*componentDict, "version", getAUVersionAsHexInteger (*this));
addPlistDictionaryKey (*componentDict, "sandboxSafe", true);
componentDict->createNewChildElement ("key")->addTextElement ("tags");
auto* tagsArray = componentDict->createNewChildElement ("array");
tagsArray->createNewChildElement ("string")
->addTextElement (isPluginSynth ? "Synth" : "Effects");
if (auMainType.removeCharacters ("'") == "aumi")
tagsArray->createNewChildElement ("string")->addTextElement ("MIDI");
return { plistKey, plistEntry };
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
//==============================================================================
static XmlElement* getKeyWithName (XmlElement& xml, const String& key)
{
for (auto* element : xml.getChildWithTagNameIterator ("key"))
if (element->getAllSubText().trim().equalsIgnoreCase (key))
return element;
return nullptr;
}
static bool keyFoundAndNotSequentialDuplicate (XmlElement& xml, const String& key)
{
if (auto* element = getKeyWithName (xml, key))
{
if (element->getNextElement() != nullptr && element->getNextElement()->hasTagName ("key"))
{
// found broken plist format (sequential duplicate), fix by removing
xml.removeChildElement (element, true);
return false;
}
// key found (not sequential duplicate)
return true;
}
// key not found
return false;
}
static bool addKeyIfNotFound (XmlElement& xml, const String& key)
{
if (! keyFoundAndNotSequentialDuplicate (xml, key))
{
xml.createNewChildElement ("key")->addTextElement (key);
return true;
}
return false;
}
static void addPlistDictionaryKey (XmlElement& xml, const String& key, const String& value)
{
if (addKeyIfNotFound (xml, key))
xml.createNewChildElement ("string")->addTextElement (value);
}
template <size_t N>
static void addPlistDictionaryKey (XmlElement& xml, const String& key, const char (&value) [N])
{
addPlistDictionaryKey (xml, key, String { value });
}
static void addPlistDictionaryKey (XmlElement& xml, const String& key, const bool value)
{
if (addKeyIfNotFound (xml, key))
xml.createNewChildElement (value ? "true" : "false");
}
static void addPlistDictionaryKey (XmlElement& xml, const String& key, int value)
{
if (addKeyIfNotFound (xml, key))
xml.createNewChildElement ("integer")->addTextElement (String (value));
}
static void addArrayToPlist (XmlElement& dict, String arrayKey, const StringArray& arrayElements)
{
if (getKeyWithName (dict, arrayKey) != nullptr)
return;
dict.createNewChildElement ("key")->addTextElement (arrayKey);
auto* plistStringArray = dict.createNewChildElement ("array");
for (auto& e : arrayElements)
plistStringArray->createNewChildElement ("string")->addTextElement (e);
}
static int getAUVersionAsHexInteger (const PlistOptions& opts)
{
const auto segments = getVersionSegments (opts.marketingVersion);
const StringArray trimmed (segments.strings.getRawDataPointer(), jmin (segments.size(), 3));
return getVersionAsHexIntegerFromParts (trimmed);
}
//==============================================================================
void PlistOptions::write (const File& infoPlistFile) const
{
writeStreamToFile (infoPlistFile, [&] (MemoryOutputStream& mo) { write (mo); });
}
void PlistOptions::write (MemoryOutputStream& mo) const
{
XmlElement::TextFormat format;
format.dtd = "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
createXML()->writeTo (mo, format);
}
std::unique_ptr<XmlElement> PlistOptions::createXML() const
{
auto plist = parseXML (plistToMerge);
if (plist == nullptr || ! plist->hasTagName ("plist"))
plist.reset (new XmlElement ("plist"));
auto* dict = plist->getChildByName ("dict");
if (dict == nullptr)
dict = plist->createNewChildElement ("dict");
if (microphonePermissionEnabled)
addPlistDictionaryKey (*dict, "NSMicrophoneUsageDescription", microphonePermissionText);
if (cameraPermissionEnabled)
addPlistDictionaryKey (*dict, "NSCameraUsageDescription", cameraPermissionText);
if (bluetoothPermissionEnabled)
addPlistDictionaryKey (*dict, "NSBluetoothAlwaysUsageDescription", bluetoothPermissionText);
if (iOS)
{
if (bluetoothPermissionEnabled)
addPlistDictionaryKey (*dict, "NSBluetoothPeripheralUsageDescription", bluetoothPermissionText); // needed for pre iOS 13.0
addPlistDictionaryKey (*dict, "LSRequiresIPhoneOS", true);
addPlistDictionaryKey (*dict, "UIViewControllerBasedStatusBarAppearance", true);
if (shouldAddStoryboardToProject)
addPlistDictionaryKey (*dict, "UILaunchStoryboardName", storyboardName);
}
else
{
if (sendAppleEventsPermissionEnabled)
addPlistDictionaryKey (*dict, "NSAppleEventsUsageDescription", sendAppleEventsPermissionText);
}
addPlistDictionaryKey (*dict, "CFBundleExecutable", executableName);
if (! iOS) // (NB: on iOS this causes error ITMS-90032 during publishing)
addPlistDictionaryKey (*dict, "CFBundleIconFile", iconFile.exists() ? iconFile.getFileName() : String());
addPlistDictionaryKey (*dict, "CFBundleIdentifier", bundleIdentifier);
addPlistDictionaryKey (*dict, "CFBundleName", projectName);
// needed by NSExtension on iOS
addPlistDictionaryKey (*dict, "CFBundleDisplayName", projectName);
addPlistDictionaryKey (*dict, "CFBundlePackageType", getXcodePackageType (type));
addPlistDictionaryKey (*dict, "CFBundleSignature", getXcodeBundleSignature (type));
addPlistDictionaryKey (*dict, "CFBundleShortVersionString", marketingVersion);
addPlistDictionaryKey (*dict, "CFBundleVersion", currentProjectVersion);
addPlistDictionaryKey (*dict, "NSHumanReadableCopyright", companyCopyright);
addPlistDictionaryKey (*dict, "NSHighResolutionCapable", true);
if (applicationCategory.isNotEmpty())
addPlistDictionaryKey (*dict, "LSApplicationCategoryType", applicationCategory);
auto replacedDocExtensions = StringArray::fromTokens (replacePreprocessorDefs (allPreprocessorDefs,
documentExtensions), ",", {});
replacedDocExtensions.trim();
replacedDocExtensions.removeEmptyStrings (true);
if (! replacedDocExtensions.isEmpty() && type != ProjectType::Target::AudioUnitv3PlugIn)
{
dict->createNewChildElement ("key")->addTextElement ("CFBundleDocumentTypes");
auto* dict2 = dict->createNewChildElement ("array")->createNewChildElement ("dict");
XmlElement* arrayTag = nullptr;
for (auto ex : replacedDocExtensions)
{
if (ex.startsWithChar ('.'))
ex = ex.substring (1);
if (arrayTag == nullptr)
{
dict2->createNewChildElement ("key")->addTextElement ("CFBundleTypeExtensions");
arrayTag = dict2->createNewChildElement ("array");
addPlistDictionaryKey (*dict2, "CFBundleTypeName", ex);
addPlistDictionaryKey (*dict2, "CFBundleTypeRole", "Editor");
addPlistDictionaryKey (*dict2, "CFBundleTypeIconFile", "Icon");
addPlistDictionaryKey (*dict2, "NSPersistentStoreTypeKey", "XML");
addPlistDictionaryKey (*dict2, "LSHandlerRank", "Default");
}
arrayTag->createNewChildElement ("string")->addTextElement (ex);
}
}
if (fileSharingEnabled && type != ProjectType::Target::AudioUnitv3PlugIn)
addPlistDictionaryKey (*dict, "UIFileSharingEnabled", true);
if (documentBrowserEnabled)
addPlistDictionaryKey (*dict, "UISupportsDocumentBrowser", true);
if (iOS)
{
if (type != ProjectType::Target::AudioUnitv3PlugIn)
{
if (statusBarHidden)
addPlistDictionaryKey (*dict, "UIStatusBarHidden", true);
addPlistDictionaryKey (*dict, "UIRequiresFullScreen", requiresFullScreen);
addIosScreenOrientations (*dict);
addIosBackgroundModes (*dict);
}
if (type == ProjectType::Target::StandalonePlugIn && enableIAA)
{
XmlElement audioComponentsPlistKey ("key");
audioComponentsPlistKey.addTextElement ("AudioComponents");
dict->addChildElement (new XmlElement (audioComponentsPlistKey));
XmlElement audioComponentsPlistEntry ("array");
auto* audioComponentsDict = audioComponentsPlistEntry.createNewChildElement ("dict");
addPlistDictionaryKey (*audioComponentsDict, "name", IAAPluginName);
addPlistDictionaryKey (*audioComponentsDict, "manufacturer", pluginManufacturerCode.substring (0, 4));
addPlistDictionaryKey (*audioComponentsDict, "type", IAATypeCode);
addPlistDictionaryKey (*audioComponentsDict, "subtype", pluginCode.substring (0, 4));
addPlistDictionaryKey (*audioComponentsDict, "version", getVersionAsHexInteger (marketingVersion));
dict->addChildElement (new XmlElement (audioComponentsPlistEntry));
}
}
const auto extraOptions = [&]() -> Array<XmlElement>
{
if (type == ProjectType::Target::Type::AudioUnitPlugIn)
return createExtraAudioUnitTargetPlistOptions();
if (type == ProjectType::Target::Type::AudioUnitv3PlugIn)
return createExtraAudioUnitV3TargetPlistOptions();
return {};
}();
for (auto& e : extraOptions)
dict->addChildElement (new XmlElement (e));
return plist;
}
void PlistOptions::addIosScreenOrientations (XmlElement& dict) const
{
addArrayToPlist (dict, "UISupportedInterfaceOrientations", iPhoneScreenOrientations);
if (iPadScreenOrientations != iPhoneScreenOrientations)
addArrayToPlist (dict, "UISupportedInterfaceOrientations~ipad", iPadScreenOrientations);
}
void PlistOptions::addIosBackgroundModes (XmlElement& dict) const
{
StringArray iosBackgroundModes;
if (backgroundAudioEnabled) iosBackgroundModes.add ("audio");
if (backgroundBleEnabled) iosBackgroundModes.add ("bluetooth-central");
if (pushNotificationsEnabled) iosBackgroundModes.add ("remote-notification");
addArrayToPlist (dict, "UIBackgroundModes", iosBackgroundModes);
}
Array<XmlElement> PlistOptions::createExtraAudioUnitTargetPlistOptions() const
{
XmlElement plistKey ("key");
plistKey.addTextElement ("AudioComponents");
XmlElement plistEntry ("array");
auto* dict = plistEntry.createNewChildElement ("dict");
auto truncatedCode = pluginManufacturerCode.substring (0, 4);
auto pluginSubType = pluginCode.substring (0, 4);
if (truncatedCode.toLowerCase() == truncatedCode)
{
throw SaveError ("AudioUnit plugin code identifiers invalid!\n\n"
"You have used only lower case letters in your AU plugin manufacturer identifier. "
"You must have at least one uppercase letter in your AU plugin manufacturer "
"identifier code.");
}
addPlistDictionaryKey (*dict, "name", pluginManufacturer + ": " + pluginName);
addPlistDictionaryKey (*dict, "description", pluginDescription);
addPlistDictionaryKey (*dict, "factoryFunction", pluginAUExportPrefix + "Factory");
addPlistDictionaryKey (*dict, "manufacturer", truncatedCode);
addPlistDictionaryKey (*dict, "type", auMainType.removeCharacters ("'"));
addPlistDictionaryKey (*dict, "subtype", pluginSubType);
addPlistDictionaryKey (*dict, "version", getAUVersionAsHexInteger (*this));
if (isAuSandboxSafe)
{
addPlistDictionaryKey (*dict, "sandboxSafe", true);
}
else if (! suppressResourceUsage)
{
dict->createNewChildElement ("key")->addTextElement ("resourceUsage");
auto* resourceUsageDict = dict->createNewChildElement ("dict");
addPlistDictionaryKey (*resourceUsageDict, "network.client", true);
addPlistDictionaryKey (*resourceUsageDict, "temporary-exception.files.all.read-write", true);
}
if (isPluginARAEffect)
{
dict->createNewChildElement ("key")->addTextElement ("tags");
auto* tagsArray = dict->createNewChildElement ("array");
tagsArray->createNewChildElement ("string")->addTextElement ("ARA");
}
return { plistKey, plistEntry };
}
Array<XmlElement> PlistOptions::createExtraAudioUnitV3TargetPlistOptions() const
{
XmlElement plistKey ("key");
plistKey.addTextElement ("NSExtension");
XmlElement plistEntry ("dict");
addPlistDictionaryKey (plistEntry, "NSExtensionPrincipalClass", pluginAUExportPrefix + "FactoryAUv3");
addPlistDictionaryKey (plistEntry, "NSExtensionPointIdentifier", "com.apple.AudioUnit-UI");
plistEntry.createNewChildElement ("key")->addTextElement ("NSExtensionAttributes");
auto* dict = plistEntry.createNewChildElement ("dict");
dict->createNewChildElement ("key")->addTextElement ("AudioComponents");
auto* componentArray = dict->createNewChildElement ("array");
auto* componentDict = componentArray->createNewChildElement ("dict");
addPlistDictionaryKey (*componentDict, "name", pluginManufacturer + ": " + pluginName);
addPlistDictionaryKey (*componentDict, "description", pluginDescription);
addPlistDictionaryKey (*componentDict, "factoryFunction", pluginAUExportPrefix + "FactoryAUv3");
addPlistDictionaryKey (*componentDict, "manufacturer", pluginManufacturerCode.substring (0, 4));
addPlistDictionaryKey (*componentDict, "type", auMainType.removeCharacters ("'"));
addPlistDictionaryKey (*componentDict, "subtype", pluginCode.substring (0, 4));
addPlistDictionaryKey (*componentDict, "version", getAUVersionAsHexInteger (*this));
addPlistDictionaryKey (*componentDict, "sandboxSafe", true);
componentDict->createNewChildElement ("key")->addTextElement ("tags");
auto* tagsArray = componentDict->createNewChildElement ("array");
tagsArray->createNewChildElement ("string")
->addTextElement (isPluginSynth ? "Synth" : "Effects");
if (auMainType.removeCharacters ("'") == "aumi")
tagsArray->createNewChildElement ("string")->addTextElement ("MIDI");
return { plistKey, plistEntry };
}
}
}

View File

@ -1,106 +1,107 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
class PlistOptions final
{
public:
void write (const File& infoPlistFile) const;
//==============================================================================
ProjectType::Target::Type type = ProjectType::Target::Type::GUIApp;
String executableName;
String bundleIdentifier;
String plistToMerge;
bool iOS = false;
bool microphonePermissionEnabled = false;
String microphonePermissionText;
bool cameraPermissionEnabled = false;
String cameraPermissionText;
bool bluetoothPermissionEnabled = false;
String bluetoothPermissionText;
bool sendAppleEventsPermissionEnabled = false;
String sendAppleEventsPermissionText;
bool shouldAddStoryboardToProject = false;
String storyboardName;
File iconFile;
String projectName;
String marketingVersion;
String currentProjectVersion;
String companyCopyright;
String applicationCategory;
StringPairArray allPreprocessorDefs;
String documentExtensions;
bool fileSharingEnabled = false;
bool documentBrowserEnabled = false;
bool statusBarHidden = false;
bool requiresFullScreen = false;
bool backgroundAudioEnabled = false;
bool backgroundBleEnabled = false;
bool pushNotificationsEnabled = false;
bool enableIAA = false;
String IAAPluginName;
String pluginManufacturerCode;
String IAATypeCode;
String pluginCode;
StringArray iPhoneScreenOrientations;
StringArray iPadScreenOrientations;
String pluginName;
String pluginManufacturer;
String pluginDescription;
String pluginAUExportPrefix;
String auMainType;
bool isAuSandboxSafe = false;
bool isPluginSynth = false;
bool suppressResourceUsage = false;
private:
void write (MemoryOutputStream&) const;
std::unique_ptr<XmlElement> createXML() const;
void addIosScreenOrientations (XmlElement&) const;
void addIosBackgroundModes (XmlElement&) const;
Array<XmlElement> createExtraAudioUnitTargetPlistOptions() const;
Array<XmlElement> createExtraAudioUnitV3TargetPlistOptions() const;
};
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
class PlistOptions final
{
public:
void write (const File& infoPlistFile) const;
//==============================================================================
ProjectType::Target::Type type = ProjectType::Target::Type::GUIApp;
String executableName;
String bundleIdentifier;
String plistToMerge;
bool iOS = false;
bool microphonePermissionEnabled = false;
String microphonePermissionText;
bool cameraPermissionEnabled = false;
String cameraPermissionText;
bool bluetoothPermissionEnabled = false;
String bluetoothPermissionText;
bool sendAppleEventsPermissionEnabled = false;
String sendAppleEventsPermissionText;
bool shouldAddStoryboardToProject = false;
String storyboardName;
File iconFile;
String projectName;
String marketingVersion;
String currentProjectVersion;
String companyCopyright;
String applicationCategory;
StringPairArray allPreprocessorDefs;
String documentExtensions;
bool fileSharingEnabled = false;
bool documentBrowserEnabled = false;
bool statusBarHidden = false;
bool requiresFullScreen = false;
bool backgroundAudioEnabled = false;
bool backgroundBleEnabled = false;
bool pushNotificationsEnabled = false;
bool enableIAA = false;
String IAAPluginName;
String pluginManufacturerCode;
String IAATypeCode;
String pluginCode;
StringArray iPhoneScreenOrientations;
StringArray iPadScreenOrientations;
String pluginName;
String pluginManufacturer;
String pluginDescription;
String pluginAUExportPrefix;
String auMainType;
bool isAuSandboxSafe = false;
bool isPluginSynth = false;
bool suppressResourceUsage = false;
bool isPluginARAEffect = false;
private:
void write (MemoryOutputStream&) const;
std::unique_ptr<XmlElement> createXML() const;
void addIosScreenOrientations (XmlElement&) const;
void addIosBackgroundModes (XmlElement&) const;
Array<XmlElement> createExtraAudioUnitTargetPlistOptions() const;
Array<XmlElement> createExtraAudioUnitV3TargetPlistOptions() const;
};
}
}

View File

@ -1,275 +1,319 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
//==============================================================================
class ProjectType
{
public:
//==============================================================================
virtual ~ProjectType() { getAllTypes().removeFirstMatchingValue (this); }
const String& getType() const noexcept { return type; }
const String& getDescription() const noexcept { return desc; }
//==============================================================================
static Array<ProjectType*> getAllTypes();
static const ProjectType* findType (const String& typeCode)
{
const auto& types = getAllTypes();
for (auto i = types.size(); --i >= 0;)
if (types.getUnchecked(i)->getType() == typeCode)
return types.getUnchecked(i);
jassertfalse;
return nullptr;
}
//==============================================================================
virtual bool isStaticLibrary() const { return false; }
virtual bool isDynamicLibrary() const { return false; }
virtual bool isGUIApplication() const { return false; }
virtual bool isCommandLineApp() const { return false; }
virtual bool isAudioPlugin() const { return false; }
//==============================================================================
struct Target
{
enum Type
{
GUIApp = 0,
ConsoleApp = 1,
StaticLibrary = 2,
DynamicLibrary = 3,
VSTPlugIn = 10,
VST3PlugIn = 11,
AAXPlugIn = 12,
RTASPlugIn = 13,
AudioUnitPlugIn = 14,
AudioUnitv3PlugIn = 15,
StandalonePlugIn = 16,
UnityPlugIn = 17,
SharedCodeTarget = 20, // internal
AggregateTarget = 21,
unspecified = 30
};
enum TargetFileType
{
executable = 0,
staticLibrary = 1,
sharedLibraryOrDLL = 2,
pluginBundle = 3,
macOSAppex = 4,
unknown = 5
};
//==============================================================================
explicit Target (Type targetType) : type (targetType) {}
const char* getName() const noexcept
{
switch (type)
{
case GUIApp: return "App";
case ConsoleApp: return "ConsoleApp";
case StaticLibrary: return "Static Library";
case DynamicLibrary: return "Dynamic Library";
case VSTPlugIn: return "VST";
case VST3PlugIn: return "VST3";
case AudioUnitPlugIn: return "AU";
case StandalonePlugIn: return "Standalone Plugin";
case AudioUnitv3PlugIn: return "AUv3 AppExtension";
case AAXPlugIn: return "AAX";
case RTASPlugIn: return "RTAS";
case UnityPlugIn: return "Unity Plugin";
case SharedCodeTarget: return "Shared Code";
case AggregateTarget: return "All";
case unspecified:
default: break;
}
return "undefined";
}
static Type typeFromName (const String& name)
{
if (name == "App") return Type::GUIApp;
if (name == "ConsoleApp") return Type::ConsoleApp;
if (name == "Static Library") return Type::StaticLibrary;
if (name == "Dynamic Library") return Type::DynamicLibrary;
if (name == "VST") return Type::VSTPlugIn;
if (name == "VST3") return Type::VST3PlugIn;
if (name == "AU") return Type::AudioUnitPlugIn;
if (name == "Standalone Plugin") return Type::StandalonePlugIn;
if (name == "AUv3 AppExtension") return Type::AudioUnitv3PlugIn;
if (name == "AAX") return Type::AAXPlugIn;
if (name == "RTAS") return Type::RTASPlugIn;
if (name == "Unity Plugin") return Type::UnityPlugIn;
if (name == "Shared Code") return Type::SharedCodeTarget;
if (name == "All") return Type::AggregateTarget;
jassertfalse;
return Type::ConsoleApp;
}
TargetFileType getTargetFileType() const noexcept
{
switch (type)
{
case GUIApp: return executable;
case ConsoleApp: return executable;
case StaticLibrary: return staticLibrary;
case DynamicLibrary: return sharedLibraryOrDLL;
case VSTPlugIn: return pluginBundle;
case VST3PlugIn: return pluginBundle;
case AudioUnitPlugIn: return pluginBundle;
case StandalonePlugIn: return executable;
case AudioUnitv3PlugIn: return macOSAppex;
case AAXPlugIn: return pluginBundle;
case RTASPlugIn: return pluginBundle;
case UnityPlugIn: return pluginBundle;
case SharedCodeTarget: return staticLibrary;
case AggregateTarget:
case unspecified:
default: break;
}
return unknown;
}
const Type type;
private:
//==============================================================================
Target& operator= (const Target&) = delete;
};
virtual bool supportsTargetType (Target::Type /*targetType*/) const { return false; }
protected:
ProjectType (const String& t, const String& d)
: type (t), desc (d)
{}
private:
const String type, desc;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectType)
};
//==============================================================================
struct ProjectType_GUIApp : public ProjectType
{
ProjectType_GUIApp() : ProjectType (getTypeName(), "GUI Application") {}
static const char* getTypeName() noexcept { return "guiapp"; }
bool isGUIApplication() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::GUIApp); }
};
struct ProjectType_ConsoleApp : public ProjectType
{
ProjectType_ConsoleApp() : ProjectType (getTypeName(), "Console Application") {}
static const char* getTypeName() noexcept { return "consoleapp"; }
bool isCommandLineApp() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::ConsoleApp); }
};
struct ProjectType_StaticLibrary : public ProjectType
{
ProjectType_StaticLibrary() : ProjectType (getTypeName(), "Static Library") {}
static const char* getTypeName() noexcept { return "library"; }
bool isStaticLibrary() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::StaticLibrary); }
};
struct ProjectType_DLL : public ProjectType
{
ProjectType_DLL() : ProjectType (getTypeName(), "Dynamic Library") {}
static const char* getTypeName() noexcept { return "dll"; }
bool isDynamicLibrary() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::DynamicLibrary); }
};
struct ProjectType_AudioPlugin : public ProjectType
{
ProjectType_AudioPlugin() : ProjectType (getTypeName(), "Audio Plug-in") {}
static const char* getTypeName() noexcept { return "audioplug"; }
bool isAudioPlugin() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override
{
switch (targetType)
{
case Target::VSTPlugIn:
case Target::VST3PlugIn:
case Target::AAXPlugIn:
case Target::RTASPlugIn:
case Target::AudioUnitPlugIn:
case Target::AudioUnitv3PlugIn:
case Target::StandalonePlugIn:
case Target::UnityPlugIn:
case Target::SharedCodeTarget:
case Target::AggregateTarget:
return true;
case Target::GUIApp:
case Target::ConsoleApp:
case Target::StaticLibrary:
case Target::DynamicLibrary:
case Target::unspecified:
default:
break;
}
return false;
}
};
//==============================================================================
inline Array<ProjectType*> ProjectType::getAllTypes()
{
static ProjectType_GUIApp guiApp;
static ProjectType_ConsoleApp consoleApp;
static ProjectType_StaticLibrary staticLib;
static ProjectType_DLL dll;
static ProjectType_AudioPlugin plugin;
return Array<ProjectType*>(&guiApp, &consoleApp, &staticLib, &dll, &plugin);
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
//==============================================================================
class ProjectType
{
public:
//==============================================================================
virtual ~ProjectType() { getAllTypes().removeFirstMatchingValue (this); }
const String& getType() const noexcept { return type; }
const String& getDescription() const noexcept { return desc; }
//==============================================================================
static Array<ProjectType*> getAllTypes();
static const ProjectType* findType (const String& typeCode)
{
const auto& types = getAllTypes();
for (auto i = types.size(); --i >= 0;)
if (types.getUnchecked(i)->getType() == typeCode)
return types.getUnchecked(i);
jassertfalse;
return nullptr;
}
//==============================================================================
virtual bool isStaticLibrary() const { return false; }
virtual bool isDynamicLibrary() const { return false; }
virtual bool isGUIApplication() const { return false; }
virtual bool isCommandLineApp() const { return false; }
virtual bool isAudioPlugin() const { return false; }
virtual bool isARAAudioPlugin() const { return false; }
//==============================================================================
struct Target
{
enum Type
{
GUIApp = 0,
ConsoleApp = 1,
StaticLibrary = 2,
DynamicLibrary = 3,
VSTPlugIn = 10,
VST3PlugIn = 11,
AAXPlugIn = 12,
AudioUnitPlugIn = 14,
AudioUnitv3PlugIn = 15,
StandalonePlugIn = 16,
UnityPlugIn = 17,
LV2PlugIn = 18,
SharedCodeTarget = 20, // internal
AggregateTarget = 21,
LV2TurtleProgram = 25, // internal
unspecified = 30
};
enum TargetFileType
{
executable = 0,
staticLibrary = 1,
sharedLibraryOrDLL = 2,
pluginBundle = 3,
macOSAppex = 4,
unknown = 5
};
//==============================================================================
explicit Target (Type targetType) : type (targetType) {}
const char* getName() const noexcept
{
switch (type)
{
case GUIApp: return "App";
case ConsoleApp: return "ConsoleApp";
case StaticLibrary: return "Static Library";
case DynamicLibrary: return "Dynamic Library";
case VSTPlugIn: return "VST";
case VST3PlugIn: return "VST3";
case AudioUnitPlugIn: return "AU";
case StandalonePlugIn: return "Standalone Plugin";
case AudioUnitv3PlugIn: return "AUv3 AppExtension";
case AAXPlugIn: return "AAX";
case UnityPlugIn: return "Unity Plugin";
case LV2PlugIn: return "LV2 Plugin";
case SharedCodeTarget: return "Shared Code";
case AggregateTarget: return "All";
case LV2TurtleProgram: return "LV2 Manifest Helper";
case unspecified: break;
}
return "undefined";
}
static Type typeFromName (const String& name)
{
if (name == "App") return Type::GUIApp;
if (name == "ConsoleApp") return Type::ConsoleApp;
if (name == "Static Library") return Type::StaticLibrary;
if (name == "Dynamic Library") return Type::DynamicLibrary;
if (name == "VST") return Type::VSTPlugIn;
if (name == "VST3") return Type::VST3PlugIn;
if (name == "AU") return Type::AudioUnitPlugIn;
if (name == "Standalone Plugin") return Type::StandalonePlugIn;
if (name == "AUv3 AppExtension") return Type::AudioUnitv3PlugIn;
if (name == "AAX") return Type::AAXPlugIn;
if (name == "Unity Plugin") return Type::UnityPlugIn;
if (name == "LV2 Plugin") return Type::LV2PlugIn;
if (name == "Shared Code") return Type::SharedCodeTarget;
if (name == "All") return Type::AggregateTarget;
if (name == "LV2 Manifest Helper") return Type::LV2TurtleProgram;
jassertfalse;
return Type::ConsoleApp;
}
TargetFileType getTargetFileType() const noexcept
{
switch (type)
{
case GUIApp: return executable;
case ConsoleApp: return executable;
case StaticLibrary: return staticLibrary;
case DynamicLibrary: return sharedLibraryOrDLL;
case VSTPlugIn: return pluginBundle;
case VST3PlugIn: return pluginBundle;
case AudioUnitPlugIn: return pluginBundle;
case StandalonePlugIn: return executable;
case AudioUnitv3PlugIn: return macOSAppex;
case AAXPlugIn: return pluginBundle;
case UnityPlugIn: return pluginBundle;
case LV2PlugIn: return pluginBundle;
case SharedCodeTarget: return staticLibrary;
case LV2TurtleProgram: return executable;
case AggregateTarget:
case unspecified:
break;
}
return unknown;
}
const Type type;
private:
//==============================================================================
Target& operator= (const Target&) = delete;
};
virtual bool supportsTargetType (Target::Type /*targetType*/) const { return false; }
protected:
ProjectType (const String& t, const String& d)
: type (t), desc (d)
{}
private:
const String type, desc;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectType)
};
//==============================================================================
struct ProjectType_GUIApp : public ProjectType
{
ProjectType_GUIApp() : ProjectType (getTypeName(), "GUI Application") {}
static const char* getTypeName() noexcept { return "guiapp"; }
bool isGUIApplication() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::GUIApp); }
};
struct ProjectType_ConsoleApp : public ProjectType
{
ProjectType_ConsoleApp() : ProjectType (getTypeName(), "Console Application") {}
static const char* getTypeName() noexcept { return "consoleapp"; }
bool isCommandLineApp() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::ConsoleApp); }
};
struct ProjectType_StaticLibrary : public ProjectType
{
ProjectType_StaticLibrary() : ProjectType (getTypeName(), "Static Library") {}
static const char* getTypeName() noexcept { return "library"; }
bool isStaticLibrary() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::StaticLibrary); }
};
struct ProjectType_DLL : public ProjectType
{
ProjectType_DLL() : ProjectType (getTypeName(), "Dynamic Library") {}
static const char* getTypeName() noexcept { return "dll"; }
bool isDynamicLibrary() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::DynamicLibrary); }
};
struct ProjectType_AudioPlugin : public ProjectType
{
ProjectType_AudioPlugin() : ProjectType (getTypeName(), "Audio Plug-in") {}
static const char* getTypeName() noexcept { return "audioplug"; }
bool isAudioPlugin() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override
{
switch (targetType)
{
case Target::VSTPlugIn:
case Target::VST3PlugIn:
case Target::AAXPlugIn:
case Target::AudioUnitPlugIn:
case Target::AudioUnitv3PlugIn:
case Target::StandalonePlugIn:
case Target::UnityPlugIn:
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
case Target::SharedCodeTarget:
case Target::AggregateTarget:
return true;
case Target::GUIApp:
case Target::ConsoleApp:
case Target::StaticLibrary:
case Target::DynamicLibrary:
case Target::unspecified:
break;
}
return false;
}
};
struct ProjectType_ARAAudioPlugin : public ProjectType
{
ProjectType_ARAAudioPlugin() : ProjectType (getTypeName(), "ARA Audio Plug-in") {}
static const char* getTypeName() noexcept { return "araaudioplug"; }
bool isAudioPlugin() const override { return true; }
bool isARAAudioPlugin() const override { return true; }
bool supportsTargetType (Target::Type targetType) const override
{
switch (targetType)
{
case Target::VSTPlugIn:
case Target::VST3PlugIn:
case Target::AAXPlugIn:
case Target::AudioUnitPlugIn:
case Target::AudioUnitv3PlugIn:
case Target::StandalonePlugIn:
case Target::UnityPlugIn:
case Target::SharedCodeTarget:
case Target::AggregateTarget:
return true;
case Target::GUIApp:
case Target::ConsoleApp:
case Target::StaticLibrary:
case Target::DynamicLibrary:
case Target::unspecified:
case Target::LV2PlugIn:
case Target::LV2TurtleProgram:
break;
}
return false;
}
};
//==============================================================================
inline Array<ProjectType*> ProjectType::getAllTypes()
{
static ProjectType_GUIApp guiApp;
static ProjectType_ConsoleApp consoleApp;
static ProjectType_StaticLibrary staticLib;
static ProjectType_DLL dll;
static ProjectType_AudioPlugin plugin;
static ProjectType_ARAAudioPlugin araplugin;
return Array<ProjectType*>(&guiApp, &consoleApp, &staticLib, &dll, &plugin, &araplugin);
}
}
}

View File

@ -1,129 +1,129 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
//==============================================================================
/** Manipulates a cross-platform partial file path. (Needed because File is designed
for absolute paths on the active OS)
*/
class RelativePath
{
public:
//==============================================================================
enum RootFolder
{
unknown,
projectFolder,
buildTargetFolder
};
//==============================================================================
RelativePath()
: root (unknown)
{}
RelativePath (const String& relPath, const RootFolder rootType)
: path (unixStylePath (relPath)), root (rootType)
{}
RelativePath (const File& file, const File& rootFolder, const RootFolder rootType)
: path (unixStylePath (getRelativePathFrom (file, rootFolder))), root (rootType)
{}
RootFolder getRoot() const { return root; }
String toUnixStyle() const { return unixStylePath (path); }
String toWindowsStyle() const { return windowsStylePath (path); }
String getFileName() const { return getFakeFile().getFileName(); }
String getFileNameWithoutExtension() const { return getFakeFile().getFileNameWithoutExtension(); }
String getFileExtension() const { return getFakeFile().getFileExtension(); }
bool hasFileExtension (StringRef extension) const { return getFakeFile().hasFileExtension (extension); }
bool isAbsolute() const { return isAbsolutePath (path); }
RelativePath withFileExtension (const String& extension) const
{
return RelativePath (path.upToLastOccurrenceOf (".", ! extension.startsWithChar ('.'), false) + extension, root);
}
RelativePath getParentDirectory() const
{
String p (path);
if (path.endsWithChar ('/'))
p = p.dropLastCharacters (1);
return RelativePath (p.upToLastOccurrenceOf ("/", false, false), root);
}
RelativePath getChildFile (const String& subpath) const
{
if (isAbsolutePath (subpath))
return RelativePath (subpath, root);
String p (toUnixStyle());
if (! p.endsWithChar ('/'))
p << '/';
return RelativePath (p + subpath, root);
}
RelativePath rebased (const File& originalRoot, const File& newRoot, const RootFolder newRootType) const
{
if (isAbsolute())
return RelativePath (path, newRootType);
return RelativePath (getRelativePathFrom (originalRoot.getChildFile (toUnixStyle()), newRoot), newRootType);
}
private:
//==============================================================================
String path;
RootFolder root;
File getFakeFile() const
{
#if JUCE_WINDOWS
if (isAbsolutePath (path))
{
// This is a hack to convert unix-style absolute paths into valid absolute Windows paths to avoid hitting
// an assertion in File::parseAbsolutePath().
if (path.startsWithChar (L'/') || path.startsWithChar (L'$') || path.startsWithChar (L'~'))
return File (String ("C:\\") + windowsStylePath (path.substring (1)));
return File (path);
}
#endif
// This method gets called very often, so we'll cache this directory.
static const File currentWorkingDirectory (File::getCurrentWorkingDirectory());
return currentWorkingDirectory.getChildFile (path);
}
};
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
//==============================================================================
/** Manipulates a cross-platform partial file path. (Needed because File is designed
for absolute paths on the active OS)
*/
class RelativePath
{
public:
//==============================================================================
enum RootFolder
{
unknown,
projectFolder,
buildTargetFolder
};
//==============================================================================
RelativePath()
: root (unknown)
{}
RelativePath (const String& relPath, const RootFolder rootType)
: path (unixStylePath (relPath)), root (rootType)
{}
RelativePath (const File& file, const File& rootFolder, const RootFolder rootType)
: path (unixStylePath (getRelativePathFrom (file, rootFolder))), root (rootType)
{}
RootFolder getRoot() const { return root; }
String toUnixStyle() const { return unixStylePath (path); }
String toWindowsStyle() const { return windowsStylePath (path); }
String getFileName() const { return getFakeFile().getFileName(); }
String getFileNameWithoutExtension() const { return getFakeFile().getFileNameWithoutExtension(); }
String getFileExtension() const { return getFakeFile().getFileExtension(); }
bool hasFileExtension (StringRef extension) const { return getFakeFile().hasFileExtension (extension); }
bool isAbsolute() const { return isAbsolutePath (path); }
RelativePath withFileExtension (const String& extension) const
{
return RelativePath (path.upToLastOccurrenceOf (".", ! extension.startsWithChar ('.'), false) + extension, root);
}
RelativePath getParentDirectory() const
{
String p (path);
if (path.endsWithChar ('/'))
p = p.dropLastCharacters (1);
return RelativePath (p.upToLastOccurrenceOf ("/", false, false), root);
}
RelativePath getChildFile (const String& subpath) const
{
if (isAbsolutePath (subpath))
return RelativePath (subpath, root);
String p (toUnixStyle());
if (! p.endsWithChar ('/'))
p << '/';
return RelativePath (p + subpath, root);
}
RelativePath rebased (const File& originalRoot, const File& newRoot, const RootFolder newRootType) const
{
if (isAbsolute())
return RelativePath (path, newRootType);
return RelativePath (getRelativePathFrom (originalRoot.getChildFile (toUnixStyle()), newRoot), newRootType);
}
private:
//==============================================================================
String path;
RootFolder root;
File getFakeFile() const
{
#if JUCE_WINDOWS
if (isAbsolutePath (path))
{
// This is a hack to convert unix-style absolute paths into valid absolute Windows paths to avoid hitting
// an assertion in File::parseAbsolutePath().
if (path.startsWithChar (L'/') || path.startsWithChar (L'$') || path.startsWithChar (L'~'))
return File (String ("C:\\") + windowsStylePath (path.substring (1)));
return File (path);
}
#endif
// This method gets called very often, so we'll cache this directory.
static const File currentWorkingDirectory (File::getCurrentWorkingDirectory());
return currentWorkingDirectory.getChildFile (path);
}
};
}
}

View File

@ -1,91 +1,91 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
uint64 calculateStreamHashCode (InputStream& in)
{
uint64 t = 0;
const int bufferSize = 4096;
HeapBlock<uint8> buffer;
buffer.malloc (bufferSize);
for (;;)
{
auto num = in.read (buffer, bufferSize);
if (num <= 0)
break;
for (int i = 0; i < num; ++i)
t = t * 65599 + buffer[i];
}
return t;
}
uint64 calculateFileHashCode (const File& file)
{
std::unique_ptr<FileInputStream> stream (file.createInputStream());
return stream != nullptr ? calculateStreamHashCode (*stream) : 0;
}
uint64 calculateMemoryHashCode (const void* data, size_t numBytes)
{
uint64 t = 0;
for (size_t i = 0; i < numBytes; ++i)
t = t * 65599 + static_cast<const uint8*> (data)[i];
return t;
}
bool overwriteFileWithNewDataIfDifferent (const File& file, const void* data, size_t numBytes)
{
if (file.getSize() == (int64) numBytes
&& calculateMemoryHashCode (data, numBytes) == calculateFileHashCode (file))
return true;
if (file.exists())
return file.replaceWithData (data, numBytes);
return file.getParentDirectory().createDirectory() && file.appendData (data, numBytes);
}
bool overwriteFileWithNewDataIfDifferent (const File& file, const MemoryOutputStream& newData)
{
return overwriteFileWithNewDataIfDifferent (file, newData.getData(), newData.getDataSize());
}
bool overwriteFileWithNewDataIfDifferent (const File& file, const String& newData)
{
const char* const utf8 = newData.toUTF8();
return overwriteFileWithNewDataIfDifferent (file, utf8, strlen (utf8));
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
uint64 calculateStreamHashCode (InputStream& in)
{
uint64 t = 0;
const int bufferSize = 4096;
HeapBlock<uint8> buffer;
buffer.malloc (bufferSize);
for (;;)
{
auto num = in.read (buffer, bufferSize);
if (num <= 0)
break;
for (int i = 0; i < num; ++i)
t = t * 65599 + buffer[i];
}
return t;
}
uint64 calculateFileHashCode (const File& file)
{
std::unique_ptr<FileInputStream> stream (file.createInputStream());
return stream != nullptr ? calculateStreamHashCode (*stream) : 0;
}
uint64 calculateMemoryHashCode (const void* data, size_t numBytes)
{
uint64 t = 0;
for (size_t i = 0; i < numBytes; ++i)
t = t * 65599 + static_cast<const uint8*> (data)[i];
return t;
}
bool overwriteFileWithNewDataIfDifferent (const File& file, const void* data, size_t numBytes)
{
if (file.getSize() == (int64) numBytes
&& calculateMemoryHashCode (data, numBytes) == calculateFileHashCode (file))
return true;
if (file.exists())
return file.replaceWithData (data, numBytes);
return file.getParentDirectory().createDirectory() && file.appendData (data, numBytes);
}
bool overwriteFileWithNewDataIfDifferent (const File& file, const MemoryOutputStream& newData)
{
return overwriteFileWithNewDataIfDifferent (file, newData.getData(), newData.getDataSize());
}
bool overwriteFileWithNewDataIfDifferent (const File& file, const String& newData)
{
const char* const utf8 = newData.toUTF8();
return overwriteFileWithNewDataIfDifferent (file, utf8, strlen (utf8));
}
}
}

View File

@ -1,38 +1,38 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
uint64 calculateStreamHashCode (InputStream& in);
uint64 calculateFileHashCode (const File& file);
uint64 calculateMemoryHashCode (const void* data, size_t numBytes);
bool overwriteFileWithNewDataIfDifferent (const File& file, const void* data, size_t numBytes);
bool overwriteFileWithNewDataIfDifferent (const File& file, const MemoryOutputStream& newData);
bool overwriteFileWithNewDataIfDifferent (const File& file, const String& newData);
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
uint64 calculateStreamHashCode (InputStream& in);
uint64 calculateFileHashCode (const File& file);
uint64 calculateMemoryHashCode (const void* data, size_t numBytes);
bool overwriteFileWithNewDataIfDifferent (const File& file, const void* data, size_t numBytes);
bool overwriteFileWithNewDataIfDifferent (const File& file, const MemoryOutputStream& newData);
bool overwriteFileWithNewDataIfDifferent (const File& file, const String& newData);
}
}

View File

@ -1,97 +1,97 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
static String getCommaSeparatedVersionNumber (const String& version)
{
auto versionParts = StringArray::fromTokens (version, ",.", "");
versionParts.trim();
versionParts.removeEmptyStrings();
while (versionParts.size() < 4)
versionParts.add ("0");
return versionParts.joinIntoString (",");
}
void ResourceRcOptions::write (const File& resourceRcFile) const
{
MemoryOutputStream mo;
mo << "#pragma code_page(65001)" << newLine
<< newLine
<< "#ifdef JUCE_USER_DEFINED_RC_FILE" << newLine
<< " #include JUCE_USER_DEFINED_RC_FILE" << newLine
<< "#else" << newLine
<< newLine
<< "#undef WIN32_LEAN_AND_MEAN" << newLine
<< "#define WIN32_LEAN_AND_MEAN" << newLine
<< "#include <windows.h>" << newLine
<< newLine
<< "VS_VERSION_INFO VERSIONINFO" << newLine
<< "FILEVERSION " << getCommaSeparatedVersionNumber (version) << newLine
<< "BEGIN" << newLine
<< " BLOCK \"StringFileInfo\"" << newLine
<< " BEGIN" << newLine
<< " BLOCK \"040904E4\"" << newLine
<< " BEGIN" << newLine;
const auto writeRCValue = [&] (const String& n, const String& value)
{
if (value.isNotEmpty())
mo << " VALUE \"" << n << "\", \""
<< value.replace ("\"", "\"\"") << "\\0\"" << newLine;
};
writeRCValue ("CompanyName", companyName);
writeRCValue ("LegalCopyright", companyCopyright);
writeRCValue ("FileDescription", projectName);
writeRCValue ("FileVersion", version);
writeRCValue ("ProductName", projectName);
writeRCValue ("ProductVersion", version);
mo << " END" << newLine
<< " END" << newLine
<< newLine
<< " BLOCK \"VarFileInfo\"" << newLine
<< " BEGIN" << newLine
<< " VALUE \"Translation\", 0x409, 1252" << newLine
<< " END" << newLine
<< "END" << newLine
<< newLine
<< "#endif" << newLine;
if (icon.existsAsFile())
mo << newLine
<< "IDI_ICON1 ICON DISCARDABLE " << icon.getFileName().quoted()
<< newLine
<< "IDI_ICON2 ICON DISCARDABLE " << icon.getFileName().quoted();
overwriteFileIfDifferentOrThrow (resourceRcFile, mo);
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
static String getCommaSeparatedVersionNumber (const String& version)
{
auto versionParts = StringArray::fromTokens (version, ",.", "");
versionParts.trim();
versionParts.removeEmptyStrings();
while (versionParts.size() < 4)
versionParts.add ("0");
return versionParts.joinIntoString (",");
}
void ResourceRcOptions::write (const File& resourceRcFile) const
{
MemoryOutputStream mo;
mo << "#pragma code_page(65001)" << newLine
<< newLine
<< "#ifdef JUCE_USER_DEFINED_RC_FILE" << newLine
<< " #include JUCE_USER_DEFINED_RC_FILE" << newLine
<< "#else" << newLine
<< newLine
<< "#undef WIN32_LEAN_AND_MEAN" << newLine
<< "#define WIN32_LEAN_AND_MEAN" << newLine
<< "#include <windows.h>" << newLine
<< newLine
<< "VS_VERSION_INFO VERSIONINFO" << newLine
<< "FILEVERSION " << getCommaSeparatedVersionNumber (version) << newLine
<< "BEGIN" << newLine
<< " BLOCK \"StringFileInfo\"" << newLine
<< " BEGIN" << newLine
<< " BLOCK \"040904E4\"" << newLine
<< " BEGIN" << newLine;
const auto writeRCValue = [&] (const String& n, const String& value)
{
if (value.isNotEmpty())
mo << " VALUE \"" << n << "\", \""
<< value.replace ("\"", "\"\"") << "\\0\"" << newLine;
};
writeRCValue ("CompanyName", companyName);
writeRCValue ("LegalCopyright", companyCopyright);
writeRCValue ("FileDescription", projectName);
writeRCValue ("FileVersion", version);
writeRCValue ("ProductName", projectName);
writeRCValue ("ProductVersion", version);
mo << " END" << newLine
<< " END" << newLine
<< newLine
<< " BLOCK \"VarFileInfo\"" << newLine
<< " BEGIN" << newLine
<< " VALUE \"Translation\", 0x409, 1252" << newLine
<< " END" << newLine
<< "END" << newLine
<< newLine
<< "#endif" << newLine;
if (icon.existsAsFile())
mo << newLine
<< "IDI_ICON1 ICON DISCARDABLE " << icon.getFileName().quoted()
<< newLine
<< "IDI_ICON2 ICON DISCARDABLE " << icon.getFileName().quoted();
overwriteFileIfDifferentOrThrow (resourceRcFile, mo);
}
}
}

View File

@ -1,43 +1,43 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
class ResourceRcOptions final
{
public:
void write (const File& resourceRcFile) const;
//==============================================================================
String version;
String companyName;
String companyCopyright;
String projectName;
File icon;
};
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
class ResourceRcOptions final
{
public:
void write (const File& resourceRcFile) const;
//==============================================================================
String version;
String companyName;
String companyCopyright;
String projectName;
File icon;
};
}
}

View File

@ -1,60 +1,60 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
StringArray getVersionSegments (StringRef p)
{
auto segments = StringArray::fromTokens (p, ",.", "");
segments.trim();
segments.removeEmptyStrings();
return segments;
}
int getVersionAsHexIntegerFromParts (const StringArray& segments)
{
auto value = (segments[0].getIntValue() << 16)
+ (segments[1].getIntValue() << 8)
+ segments[2].getIntValue();
if (segments.size() > 3)
value = (value << 8) + segments[3].getIntValue();
return value;
}
int getVersionAsHexInteger (StringRef versionString)
{
return getVersionAsHexIntegerFromParts (getVersionSegments (versionString));
}
String getVersionAsHex (StringRef versionString)
{
return "0x" + String::toHexString (getVersionAsHexInteger (versionString));
}
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
StringArray getVersionSegments (StringRef p)
{
auto segments = StringArray::fromTokens (p, ",.", "");
segments.trim();
segments.removeEmptyStrings();
return segments;
}
int getVersionAsHexIntegerFromParts (const StringArray& segments)
{
auto value = (segments[0].getIntValue() << 16)
+ (segments[1].getIntValue() << 8)
+ segments[2].getIntValue();
if (segments.size() > 3)
value = (value << 8) + segments[3].getIntValue();
return value;
}
int getVersionAsHexInteger (StringRef versionString)
{
return getVersionAsHexIntegerFromParts (getVersionSegments (versionString));
}
String getVersionAsHex (StringRef versionString)
{
return "0x" + String::toHexString (getVersionAsHexInteger (versionString));
}
}
}

View File

@ -1,37 +1,37 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
StringArray getVersionSegments (StringRef p);
int getVersionAsHexIntegerFromParts (const StringArray& versionString);
int getVersionAsHexInteger (StringRef versionString);
String getVersionAsHex (StringRef versionString);
}
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace build_tools
{
StringArray getVersionSegments (StringRef p);
int getVersionAsHexIntegerFromParts (const StringArray& versionString);
int getVersionAsHexInteger (StringRef versionString);
String getVersionAsHex (StringRef versionString);
}
}