|
- /*
- ==============================================================================
-
- 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::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::LV2Helper:
- case Type::VST3Helper:
- 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::LV2Helper:
- case Type::VST3Helper:
- 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);
- }
-
- } // namespace juce::build_tools
|