The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
6.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../jucer_Headers.h"
  18. #include "jucer_CodeHelpers.h"
  19. //==============================================================================
  20. namespace FileHelpers
  21. {
  22. static int64 calculateMemoryHashCode (const void* data, const size_t numBytes)
  23. {
  24. int64 t = 0;
  25. for (size_t i = 0; i < numBytes; ++i)
  26. t = t * 65599 + static_cast<const uint8*> (data)[i];
  27. return t;
  28. }
  29. int64 calculateStreamHashCode (InputStream& in)
  30. {
  31. int64 t = 0;
  32. const int bufferSize = 4096;
  33. HeapBlock<uint8> buffer;
  34. buffer.malloc (bufferSize);
  35. for (;;)
  36. {
  37. const int num = in.read (buffer, bufferSize);
  38. if (num <= 0)
  39. break;
  40. for (int i = 0; i < num; ++i)
  41. t = t * 65599 + buffer[i];
  42. }
  43. return t;
  44. }
  45. int64 calculateFileHashCode (const File& file)
  46. {
  47. ScopedPointer<FileInputStream> stream (file.createInputStream());
  48. return stream != nullptr ? calculateStreamHashCode (*stream) : 0;
  49. }
  50. bool overwriteFileWithNewDataIfDifferent (const File& file, const void* data, size_t numBytes)
  51. {
  52. if (file.getSize() == (int64) numBytes
  53. && calculateMemoryHashCode (data, numBytes) == calculateFileHashCode (file))
  54. return true;
  55. if (file.exists())
  56. return file.replaceWithData (data, numBytes);
  57. return file.getParentDirectory().createDirectory() && file.appendData (data, numBytes);
  58. }
  59. bool overwriteFileWithNewDataIfDifferent (const File& file, const MemoryOutputStream& newData)
  60. {
  61. return overwriteFileWithNewDataIfDifferent (file, newData.getData(), newData.getDataSize());
  62. }
  63. bool overwriteFileWithNewDataIfDifferent (const File& file, const String& newData)
  64. {
  65. const char* const utf8 = newData.toUTF8();
  66. return overwriteFileWithNewDataIfDifferent (file, utf8, strlen (utf8));
  67. }
  68. bool containsAnyNonHiddenFiles (const File& folder)
  69. {
  70. DirectoryIterator di (folder, false);
  71. while (di.next())
  72. if (! di.getFile().isHidden())
  73. return true;
  74. return false;
  75. }
  76. String unixStylePath (const String& path) { return path.replaceCharacter ('\\', '/'); }
  77. String windowsStylePath (const String& path) { return path.replaceCharacter ('/', '\\'); }
  78. String currentOSStylePath (const String& path)
  79. {
  80. #if JUCE_WINDOWS
  81. return windowsStylePath (path);
  82. #else
  83. return unixStylePath (path);
  84. #endif
  85. }
  86. bool isAbsolutePath (const String& path)
  87. {
  88. return File::isAbsolutePath (path)
  89. || path.startsWithChar ('/') // (needed because File::isAbsolutePath will ignore forward-slashes on Windows)
  90. || path.startsWithChar ('$')
  91. || path.startsWithChar ('~')
  92. || (CharacterFunctions::isLetter (path[0]) && path[1] == ':')
  93. || path.startsWithIgnoreCase ("smb:");
  94. }
  95. String appendPath (const String& path, const String& subpath)
  96. {
  97. if (isAbsolutePath (subpath))
  98. return unixStylePath (subpath);
  99. String path1 (unixStylePath (path));
  100. if (! path1.endsWithChar ('/'))
  101. path1 << '/';
  102. return path1 + unixStylePath (subpath);
  103. }
  104. bool shouldPathsBeRelative (String path1, String path2)
  105. {
  106. path1 = unixStylePath (path1);
  107. path2 = unixStylePath (path2);
  108. const int len = jmin (path1.length(), path2.length());
  109. int commonBitLength = 0;
  110. for (int i = 0; i < len; ++i)
  111. {
  112. if (CharacterFunctions::toLowerCase (path1[i]) != CharacterFunctions::toLowerCase (path2[i]))
  113. break;
  114. ++commonBitLength;
  115. }
  116. return path1.substring (0, commonBitLength).removeCharacters ("/:").isNotEmpty();
  117. }
  118. String getRelativePathFrom (const File& file, const File& sourceFolder)
  119. {
  120. #if ! JUCE_WINDOWS
  121. // On a non-windows machine, we can't know if a drive-letter path may be relative or not.
  122. if (CharacterFunctions::isLetter (file.getFullPathName()[0]) && file.getFullPathName()[1] == ':')
  123. return file.getFullPathName();
  124. #endif
  125. return file.getRelativePathFrom (sourceFolder);
  126. }
  127. // removes "/../" bits from the middle of the path
  128. String simplifyPath (String::CharPointerType p)
  129. {
  130. #if JUCE_WINDOWS
  131. if (CharacterFunctions::indexOf (p, CharPointer_ASCII ("/../")) >= 0
  132. || CharacterFunctions::indexOf (p, CharPointer_ASCII ("\\..\\")) >= 0)
  133. #else
  134. if (CharacterFunctions::indexOf (p, CharPointer_ASCII ("/../")) >= 0)
  135. #endif
  136. {
  137. StringArray toks;
  138. #if JUCE_WINDOWS
  139. toks.addTokens (p, "\\/", StringRef());
  140. #else
  141. toks.addTokens (p, "/", StringRef());
  142. #endif
  143. while (toks[0] == ".")
  144. toks.remove (0);
  145. for (int i = 1; i < toks.size(); ++i)
  146. {
  147. if (toks[i] == ".." && toks [i - 1] != "..")
  148. {
  149. toks.removeRange (i - 1, 2);
  150. i = jmax (0, i - 2);
  151. }
  152. }
  153. return toks.joinIntoString ("/");
  154. }
  155. return p;
  156. }
  157. String simplifyPath (const String& path)
  158. {
  159. #if JUCE_WINDOWS
  160. if (path.contains ("\\..\\") || path.contains ("/../"))
  161. #else
  162. if (path.contains ("/../"))
  163. #endif
  164. return simplifyPath (path.getCharPointer());
  165. return path;
  166. }
  167. }