OpenShot Audio Library | OpenShotAudio  0.6.0
juce_File.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 File::File (const String& fullPathName)
27  : fullPath (parseAbsolutePath (fullPathName))
28 {
29 }
30 
32 {
33  File f;
34  f.fullPath = path;
35  return f;
36 }
37 
38 File::File (const File& other)
39  : fullPath (other.fullPath)
40 {
41 }
42 
43 File& File::operator= (const String& newPath)
44 {
45  fullPath = parseAbsolutePath (newPath);
46  return *this;
47 }
48 
49 File& File::operator= (const File& other)
50 {
51  fullPath = other.fullPath;
52  return *this;
53 }
54 
55 File::File (File&& other) noexcept
56  : fullPath (std::move (other.fullPath))
57 {
58 }
59 
60 File& File::operator= (File&& other) noexcept
61 {
62  fullPath = std::move (other.fullPath);
63  return *this;
64 }
65 
66 //==============================================================================
67 static String removeEllipsis (const String& path)
68 {
69  // This will quickly find both /../ and /./ at the expense of a minor
70  // false-positive performance hit when path elements end in a dot.
71  #if JUCE_WINDOWS
72  if (path.contains (".\\"))
73  #else
74  if (path.contains ("./"))
75  #endif
76  {
77  StringArray toks;
78  toks.addTokens (path, File::getSeparatorString(), {});
79  bool anythingChanged = false;
80 
81  for (int i = 1; i < toks.size(); ++i)
82  {
83  auto& t = toks[i];
84 
85  if (t == ".." && toks[i - 1] != "..")
86  {
87  anythingChanged = true;
88  toks.removeRange (i - 1, 2);
89  i = jmax (0, i - 2);
90  }
91  else if (t == ".")
92  {
93  anythingChanged = true;
94  toks.remove (i--);
95  }
96  }
97 
98  if (anythingChanged)
100  }
101 
102  return path;
103 }
104 
105 static String normaliseSeparators (const String& path)
106 {
107  auto normalisedPath = path;
108 
109  String separator (File::getSeparatorString());
110  String doubleSeparator (separator + separator);
111 
112  auto uncPath = normalisedPath.startsWith (doubleSeparator)
113  && ! normalisedPath.fromFirstOccurrenceOf (doubleSeparator, false, false).startsWith (separator);
114 
115  if (uncPath)
116  normalisedPath = normalisedPath.fromFirstOccurrenceOf (doubleSeparator, false, false);
117 
118  while (normalisedPath.contains (doubleSeparator))
119  normalisedPath = normalisedPath.replace (doubleSeparator, separator);
120 
121  return uncPath ? doubleSeparator + normalisedPath
122  : normalisedPath;
123 }
124 
125 bool File::isRoot() const
126 {
127  return fullPath.isNotEmpty() && *this == getParentDirectory();
128 }
129 
130 String File::parseAbsolutePath (const String& p)
131 {
132  if (p.isEmpty())
133  return {};
134 
135  #if JUCE_WINDOWS
136  // Windows..
137  auto path = normaliseSeparators (removeEllipsis (p.replaceCharacter ('/', '\\')));
138 
139  if (path.startsWithChar (getSeparatorChar()))
140  {
141  if (path[1] != getSeparatorChar())
142  {
143  /* When you supply a raw string to the File object constructor, it must be an absolute path.
144  If you're trying to parse a string that may be either a relative path or an absolute path,
145  you MUST provide a context against which the partial path can be evaluated - you can do
146  this by simply using File::getChildFile() instead of the File constructor. E.g. saying
147  "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
148  path if that's what was supplied, or would evaluate a partial path relative to the CWD.
149  */
150  jassertfalse;
151 
153  }
154  }
155  else if (! path.containsChar (':'))
156  {
157  /* When you supply a raw string to the File object constructor, it must be an absolute path.
158  If you're trying to parse a string that may be either a relative path or an absolute path,
159  you MUST provide a context against which the partial path can be evaluated - you can do
160  this by simply using File::getChildFile() instead of the File constructor. E.g. saying
161  "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
162  path if that's what was supplied, or would evaluate a partial path relative to the CWD.
163  */
164  jassertfalse;
165 
167  }
168  #else
169  // Mac or Linux..
170 
171  // Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here
172  // to catch anyone who's trying to run code that was written on Windows with hard-coded path names.
173  // If that's why you've ended up here, use File::getChildFile() to build your paths instead.
174  jassert ((! p.containsChar ('\\')) || (p.indexOfChar ('/') >= 0 && p.indexOfChar ('/') < p.indexOfChar ('\\')));
175 
176  auto path = normaliseSeparators (removeEllipsis (p));
177 
178  if (path.startsWithChar ('~'))
179  {
180  if (path[1] == getSeparatorChar() || path[1] == 0)
181  {
182  // expand a name of the form "~/abc"
184  + path.substring (1);
185  }
186  else
187  {
188  // expand a name of type "~dave/abc"
189  auto userName = path.substring (1).upToFirstOccurrenceOf ("/", false, false);
190 
191  if (auto* pw = getpwnam (userName.toUTF8()))
192  path = addTrailingSeparator (pw->pw_dir) + path.fromFirstOccurrenceOf ("/", false, false);
193  }
194  }
195  else if (! path.startsWithChar (getSeparatorChar()))
196  {
197  #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
198  if (! (path.startsWith ("./") || path.startsWith ("../")))
199  {
200  /* When you supply a raw string to the File object constructor, it must be an absolute path.
201  If you're trying to parse a string that may be either a relative path or an absolute path,
202  you MUST provide a context against which the partial path can be evaluated - you can do
203  this by simply using File::getChildFile() instead of the File constructor. E.g. saying
204  "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
205  path if that's what was supplied, or would evaluate a partial path relative to the CWD.
206  */
207  jassertfalse;
208 
209  #if JUCE_LOG_ASSERTIONS
210  Logger::writeToLog ("Illegal absolute path: " + path);
211  #endif
212  }
213  #endif
214 
216  }
217  #endif
218 
219  while (path.endsWithChar (getSeparatorChar()) && path != getSeparatorString()) // careful not to turn a single "/" into an empty string.
220  path = path.dropLastCharacters (1);
221 
222  return path;
223 }
224 
226 {
227  return path.endsWithChar (getSeparatorChar()) ? path
228  : path + getSeparatorChar();
229 }
230 
231 //==============================================================================
232 #if JUCE_LINUX || JUCE_BSD
233  #define NAMES_ARE_CASE_SENSITIVE 1
234 #endif
235 
237 {
238  #if NAMES_ARE_CASE_SENSITIVE
239  return true;
240  #else
241  return false;
242  #endif
243 }
244 
245 static int compareFilenames (const String& name1, const String& name2) noexcept
246 {
247  #if NAMES_ARE_CASE_SENSITIVE
248  return name1.compare (name2);
249  #else
250  return name1.compareIgnoreCase (name2);
251  #endif
252 }
253 
254 bool File::operator== (const File& other) const { return compareFilenames (fullPath, other.fullPath) == 0; }
255 bool File::operator!= (const File& other) const { return compareFilenames (fullPath, other.fullPath) != 0; }
256 bool File::operator< (const File& other) const { return compareFilenames (fullPath, other.fullPath) < 0; }
257 bool File::operator> (const File& other) const { return compareFilenames (fullPath, other.fullPath) > 0; }
258 
259 //==============================================================================
260 bool File::setReadOnly (const bool shouldBeReadOnly,
261  const bool applyRecursively) const
262 {
263  bool worked = true;
264 
265  if (applyRecursively && isDirectory())
266  for (auto& f : findChildFiles (File::findFilesAndDirectories, false))
267  worked = f.setReadOnly (shouldBeReadOnly, true) && worked;
268 
269  return setFileReadOnlyInternal (shouldBeReadOnly) && worked;
270 }
271 
272 bool File::setExecutePermission (bool shouldBeExecutable) const
273 {
274  return setFileExecutableInternal (shouldBeExecutable);
275 }
276 
277 bool File::deleteRecursively (bool followSymlinks) const
278 {
279  bool worked = true;
280 
281  if (isDirectory() && (followSymlinks || ! isSymbolicLink()))
282  for (auto& f : findChildFiles (File::findFilesAndDirectories, false))
283  worked = f.deleteRecursively (followSymlinks) && worked;
284 
285  return deleteFile() && worked;
286 }
287 
288 bool File::moveFileTo (const File& newFile) const
289 {
290  if (newFile.fullPath == fullPath)
291  return true;
292 
293  if (! exists())
294  return false;
295 
296  #if ! NAMES_ARE_CASE_SENSITIVE
297  if (*this != newFile)
298  #endif
299  if (! newFile.deleteFile())
300  return false;
301 
302  return moveInternal (newFile);
303 }
304 
305 bool File::copyFileTo (const File& newFile) const
306 {
307  return (*this == newFile)
308  || (exists() && newFile.deleteFile() && copyInternal (newFile));
309 }
310 
311 bool File::replaceFileIn (const File& newFile) const
312 {
313  if (newFile.fullPath == fullPath)
314  return true;
315 
316  if (! newFile.exists())
317  return moveFileTo (newFile);
318 
319  if (! replaceInternal (newFile))
320  return false;
321 
322  deleteFile();
323  return true;
324 }
325 
326 bool File::copyDirectoryTo (const File& newDirectory) const
327 {
328  if (isDirectory() && newDirectory.createDirectory())
329  {
330  for (auto& f : findChildFiles (File::findFiles, false))
331  if (! f.copyFileTo (newDirectory.getChildFile (f.getFileName())))
332  return false;
333 
334  for (auto& f : findChildFiles (File::findDirectories, false))
335  if (! f.copyDirectoryTo (newDirectory.getChildFile (f.getFileName())))
336  return false;
337 
338  return true;
339  }
340 
341  return false;
342 }
343 
344 //==============================================================================
345 String File::getPathUpToLastSlash() const
346 {
347  auto lastSlash = fullPath.lastIndexOfChar (getSeparatorChar());
348 
349  if (lastSlash > 0)
350  return fullPath.substring (0, lastSlash);
351 
352  if (lastSlash == 0)
353  return getSeparatorString();
354 
355  return fullPath;
356 }
357 
359 {
360  return createFileWithoutCheckingPath (getPathUpToLastSlash());
361 }
362 
363 bool File::isNonEmptyDirectory() const
364 {
365  if (! isDirectory())
366  return false;
367 
369 }
370 
371 //==============================================================================
373 {
374  return fullPath.substring (fullPath.lastIndexOfChar (getSeparatorChar()) + 1);
375 }
376 
378 {
379  auto lastSlash = fullPath.lastIndexOfChar (getSeparatorChar()) + 1;
380  auto lastDot = fullPath.lastIndexOfChar ('.');
381 
382  if (lastDot > lastSlash)
383  return fullPath.substring (lastSlash, lastDot);
384 
385  return fullPath.substring (lastSlash);
386 }
387 
388 bool File::isAChildOf (const File& potentialParent) const
389 {
390  if (potentialParent.fullPath.isEmpty())
391  return false;
392 
393  auto ourPath = getPathUpToLastSlash();
394 
395  if (compareFilenames (potentialParent.fullPath, ourPath) == 0)
396  return true;
397 
398  if (potentialParent.fullPath.length() >= ourPath.length())
399  return false;
400 
401  return getParentDirectory().isAChildOf (potentialParent);
402 }
403 
404 int File::hashCode() const { return fullPath.hashCode(); }
405 int64 File::hashCode64() const { return fullPath.hashCode64(); }
406 
407 //==============================================================================
409 {
410  auto firstChar = *(path.text);
411 
412  return firstChar == getSeparatorChar()
413  #if JUCE_WINDOWS
414  || (firstChar != 0 && path.text[1] == ':');
415  #else
416  || firstChar == '~';
417  #endif
418 }
419 
420 File File::getChildFile (StringRef relativePath) const
421 {
422  auto r = relativePath.text;
423 
424  if (isAbsolutePath (r))
425  return File (String (r));
426 
427  #if JUCE_WINDOWS
428  if (r.indexOf ((juce_wchar) '/') >= 0)
429  return getChildFile (String (r).replaceCharacter ('/', '\\'));
430  #endif
431 
432  auto path = fullPath;
433  auto separatorChar = getSeparatorChar();
434 
435  while (*r == '.')
436  {
437  auto lastPos = r;
438  auto secondChar = *++r;
439 
440  if (secondChar == '.') // remove "../"
441  {
442  auto thirdChar = *++r;
443 
444  if (thirdChar == separatorChar || thirdChar == 0)
445  {
446  auto lastSlash = path.lastIndexOfChar (separatorChar);
447 
448  if (lastSlash >= 0)
449  path = path.substring (0, lastSlash);
450 
451  while (*r == separatorChar) // ignore duplicate slashes
452  ++r;
453  }
454  else
455  {
456  r = lastPos;
457  break;
458  }
459  }
460  else if (secondChar == separatorChar || secondChar == 0) // remove "./"
461  {
462  while (*r == separatorChar) // ignore duplicate slashes
463  ++r;
464  }
465  else
466  {
467  r = lastPos;
468  break;
469  }
470  }
471 
472  path = addTrailingSeparator (path);
473  path.appendCharPointer (r);
474  return File (path);
475 }
476 
478 {
479  return getParentDirectory().getChildFile (fileName);
480 }
481 
482 //==============================================================================
484 {
485  const char* suffix;
486  double divisor = 0;
487 
488  if (bytes == 1) { suffix = " byte"; }
489  else if (bytes < 1024) { suffix = " bytes"; }
490  else if (bytes < 1024 * 1024) { suffix = " KB"; divisor = 1024.0; }
491  else if (bytes < 1024 * 1024 * 1024) { suffix = " MB"; divisor = 1024.0 * 1024.0; }
492  else { suffix = " GB"; divisor = 1024.0 * 1024.0 * 1024.0; }
493 
494  return (divisor > 0 ? String ((double) bytes / divisor, 1) : String (bytes)) + suffix;
495 }
496 
497 //==============================================================================
499 {
500  if (exists())
501  return Result::ok();
502 
503  auto parentDir = getParentDirectory();
504 
505  if (parentDir == *this)
506  return Result::fail ("Cannot create parent directory");
507 
508  auto r = parentDir.createDirectory();
509 
510  if (r.wasOk())
511  {
512  FileOutputStream fo (*this, 8);
513  r = fo.getStatus();
514  }
515 
516  return r;
517 }
518 
520 {
521  if (isDirectory())
522  return Result::ok();
523 
524  auto parentDir = getParentDirectory();
525 
526  if (parentDir == *this)
527  return Result::fail ("Cannot create parent directory");
528 
529  auto r = parentDir.createDirectory();
530 
531  if (r.wasOk())
532  r = createDirectoryInternal (fullPath.trimCharactersAtEnd (getSeparatorString()));
533 
534  return r;
535 }
536 
537 //==============================================================================
538 Time File::getLastModificationTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (m); }
539 Time File::getLastAccessTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (a); }
540 Time File::getCreationTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (c); }
541 
542 bool File::setLastModificationTime (Time t) const { return setFileTimesInternal (t.toMilliseconds(), 0, 0); }
543 bool File::setLastAccessTime (Time t) const { return setFileTimesInternal (0, t.toMilliseconds(), 0); }
544 bool File::setCreationTime (Time t) const { return setFileTimesInternal (0, 0, t.toMilliseconds()); }
545 
546 //==============================================================================
547 bool File::loadFileAsData (MemoryBlock& destBlock) const
548 {
549  if (! existsAsFile())
550  return false;
551 
552  FileInputStream in (*this);
553  return in.openedOk() && getSize() == (int64) in.readIntoMemoryBlock (destBlock);
554 }
555 
557 {
558  if (! existsAsFile())
559  return {};
560 
561  FileInputStream in (*this);
562  return in.openedOk() ? in.readEntireStreamAsString()
563  : String();
564 }
565 
566 void File::readLines (StringArray& destLines) const
567 {
568  destLines.addLines (loadFileAsString());
569 }
570 
571 //==============================================================================
572 Array<File> File::findChildFiles (int whatToLookFor, bool searchRecursively, const String& wildcard, FollowSymlinks followSymlinks) const
573 {
574  Array<File> results;
575  findChildFiles (results, whatToLookFor, searchRecursively, wildcard, followSymlinks);
576  return results;
577 }
578 
579 int File::findChildFiles (Array<File>& results, int whatToLookFor, bool searchRecursively, const String& wildcard, FollowSymlinks followSymlinks) const
580 {
581  int total = 0;
582 
583  for (const auto& di : RangedDirectoryIterator (*this, searchRecursively, wildcard, whatToLookFor, followSymlinks))
584  {
585  results.add (di.getFile());
586  ++total;
587  }
588 
589  return total;
590 }
591 
592 int File::getNumberOfChildFiles (const int whatToLookFor, const String& wildCardPattern) const
593 {
594  return std::accumulate (RangedDirectoryIterator (*this, false, wildCardPattern, whatToLookFor),
596  0,
597  [] (int acc, const DirectoryEntry&) { return acc + 1; });
598 }
599 
601 {
602  if (! isDirectory())
603  return false;
604 
605  return RangedDirectoryIterator (*this, false, "*", findDirectories) != RangedDirectoryIterator();
606 }
607 
608 //==============================================================================
609 File File::getNonexistentChildFile (const String& suggestedPrefix,
610  const String& suffix,
611  bool putNumbersInBrackets) const
612 {
613  auto f = getChildFile (suggestedPrefix + suffix);
614 
615  if (f.exists())
616  {
617  int number = 1;
618  auto prefix = suggestedPrefix;
619 
620  // remove any bracketed numbers that may already be on the end..
621  if (prefix.trim().endsWithChar (')'))
622  {
623  putNumbersInBrackets = true;
624 
625  auto openBracks = prefix.lastIndexOfChar ('(');
626  auto closeBracks = prefix.lastIndexOfChar (')');
627 
628  if (openBracks > 0
629  && closeBracks > openBracks
630  && prefix.substring (openBracks + 1, closeBracks).containsOnly ("0123456789"))
631  {
632  number = prefix.substring (openBracks + 1, closeBracks).getIntValue();
633  prefix = prefix.substring (0, openBracks);
634  }
635  }
636 
637  do
638  {
639  auto newName = prefix;
640 
641  if (putNumbersInBrackets)
642  {
643  newName << '(' << ++number << ')';
644  }
645  else
646  {
647  if (CharacterFunctions::isDigit (prefix.getLastCharacter()))
648  newName << '_'; // pad with an underscore if the name already ends in a digit
649 
650  newName << ++number;
651  }
652 
653  f = getChildFile (newName + suffix);
654 
655  } while (f.exists());
656  }
657 
658  return f;
659 }
660 
661 File File::getNonexistentSibling (const bool putNumbersInBrackets) const
662 {
663  if (! exists())
664  return *this;
665 
668  putNumbersInBrackets);
669 }
670 
671 //==============================================================================
673 {
674  auto indexOfDot = fullPath.lastIndexOfChar ('.');
675 
676  if (indexOfDot > fullPath.lastIndexOfChar (getSeparatorChar()))
677  return fullPath.substring (indexOfDot);
678 
679  return {};
680 }
681 
682 bool File::hasFileExtension (StringRef possibleSuffix) const
683 {
684  if (possibleSuffix.isEmpty())
685  return fullPath.lastIndexOfChar ('.') <= fullPath.lastIndexOfChar (getSeparatorChar());
686 
687  auto semicolon = possibleSuffix.text.indexOf ((juce_wchar) ';');
688 
689  if (semicolon >= 0)
690  return hasFileExtension (String (possibleSuffix.text).substring (0, semicolon).trimEnd())
691  || hasFileExtension ((possibleSuffix.text + (semicolon + 1)).findEndOfWhitespace());
692 
693  if (fullPath.endsWithIgnoreCase (possibleSuffix))
694  {
695  if (possibleSuffix.text[0] == '.')
696  return true;
697 
698  auto dotPos = fullPath.length() - possibleSuffix.length() - 1;
699 
700  if (dotPos >= 0)
701  return fullPath[dotPos] == '.';
702  }
703 
704  return false;
705 }
706 
708 {
709  if (fullPath.isEmpty())
710  return {};
711 
712  auto filePart = getFileName();
713 
714  auto lastDot = filePart.lastIndexOfChar ('.');
715 
716  if (lastDot >= 0)
717  filePart = filePart.substring (0, lastDot);
718 
719  if (newExtension.isNotEmpty() && newExtension.text[0] != '.')
720  filePart << '.';
721 
722  return getSiblingFile (filePart + newExtension);
723 }
724 
725 //==============================================================================
726 bool File::startAsProcess (const String& parameters) const
727 {
728  return exists() && Process::openDocument (fullPath, parameters);
729 }
730 
731 //==============================================================================
732 std::unique_ptr<FileInputStream> File::createInputStream() const
733 {
734  auto fin = std::make_unique<FileInputStream> (*this);
735 
736  if (fin->openedOk())
737  return fin;
738 
739  return nullptr;
740 }
741 
742 std::unique_ptr<FileOutputStream> File::createOutputStream (size_t bufferSize) const
743 {
744  auto fout = std::make_unique<FileOutputStream> (*this, bufferSize);
745 
746  if (fout->openedOk())
747  return fout;
748 
749  return nullptr;
750 }
751 
752 //==============================================================================
753 bool File::appendData (const void* const dataToAppend,
754  const size_t numberOfBytes) const
755 {
756  jassert (((ssize_t) numberOfBytes) >= 0);
757 
758  if (numberOfBytes == 0)
759  return true;
760 
761  FileOutputStream fout (*this, 8192);
762  return fout.openedOk() && fout.write (dataToAppend, numberOfBytes);
763 }
764 
765 bool File::replaceWithData (const void* const dataToWrite,
766  const size_t numberOfBytes) const
767 {
768  if (numberOfBytes == 0)
769  return deleteFile();
770 
772  tempFile.getFile().appendData (dataToWrite, numberOfBytes);
773  return tempFile.overwriteTargetFileWithTemporary();
774 }
775 
776 bool File::appendText (const String& text, bool asUnicode, bool writeHeaderBytes, const char* lineFeed) const
777 {
778  FileOutputStream fout (*this);
779 
780  if (fout.failedToOpen())
781  return false;
782 
783  return fout.writeText (text, asUnicode, writeHeaderBytes, lineFeed);
784 }
785 
786 bool File::replaceWithText (const String& textToWrite, bool asUnicode, bool writeHeaderBytes, const char* lineFeed) const
787 {
789  tempFile.getFile().appendText (textToWrite, asUnicode, writeHeaderBytes, lineFeed);
790  return tempFile.overwriteTargetFileWithTemporary();
791 }
792 
793 bool File::hasIdenticalContentTo (const File& other) const
794 {
795  if (other == *this)
796  return true;
797 
798  if (getSize() == other.getSize() && existsAsFile() && other.existsAsFile())
799  {
800  FileInputStream in1 (*this), in2 (other);
801 
802  if (in1.openedOk() && in2.openedOk())
803  {
804  const int bufferSize = 4096;
805  HeapBlock<char> buffer1 (bufferSize), buffer2 (bufferSize);
806 
807  for (;;)
808  {
809  auto num1 = in1.read (buffer1, bufferSize);
810  auto num2 = in2.read (buffer2, bufferSize);
811 
812  if (num1 != num2)
813  break;
814 
815  if (num1 <= 0)
816  return true;
817 
818  if (memcmp (buffer1, buffer2, (size_t) num1) != 0)
819  break;
820  }
821  }
822  }
823 
824  return false;
825 }
826 
827 //==============================================================================
829 {
830  auto s = original;
831  String start;
832 
833  if (s.isNotEmpty() && s[1] == ':')
834  {
835  start = s.substring (0, 2);
836  s = s.substring (2);
837  }
838 
839  return start + s.removeCharacters ("\"#@,;:<>*^|?")
840  .substring (0, 1024);
841 }
842 
844 {
845  auto s = original.removeCharacters ("\"#@,;:<>*^|?\\/");
846 
847  const int maxLength = 128; // only the length of the filename, not the whole path
848  auto len = s.length();
849 
850  if (len > maxLength)
851  {
852  auto lastDot = s.lastIndexOfChar ('.');
853 
854  if (lastDot > jmax (0, len - 12))
855  {
856  s = s.substring (0, maxLength - (len - lastDot))
857  + s.substring (lastDot);
858  }
859  else
860  {
861  s = s.substring (0, maxLength);
862  }
863  }
864 
865  return s;
866 }
867 
868 //==============================================================================
869 static int countNumberOfSeparators (String::CharPointerType s)
870 {
871  int num = 0;
872 
873  for (;;)
874  {
875  auto c = s.getAndAdvance();
876 
877  if (c == 0)
878  break;
879 
880  if (c == File::getSeparatorChar())
881  ++num;
882  }
883 
884  return num;
885 }
886 
888 {
889  if (dir == *this)
890  return ".";
891 
892  auto thisPath = fullPath;
893 
894  while (thisPath.endsWithChar (getSeparatorChar()))
895  thisPath = thisPath.dropLastCharacters (1);
896 
898  : dir.fullPath);
899 
900  int commonBitLength = 0;
901  auto thisPathAfterCommon = thisPath.getCharPointer();
902  auto dirPathAfterCommon = dirPath.getCharPointer();
903 
904  {
905  auto thisPathIter = thisPath.getCharPointer();
906  auto dirPathIter = dirPath.getCharPointer();
907 
908  for (int i = 0;;)
909  {
910  auto c1 = thisPathIter.getAndAdvance();
911  auto c2 = dirPathIter.getAndAdvance();
912 
913  #if NAMES_ARE_CASE_SENSITIVE
914  if (c1 != c2
915  #else
917  #endif
918  || c1 == 0)
919  break;
920 
921  ++i;
922 
923  if (c1 == getSeparatorChar())
924  {
925  thisPathAfterCommon = thisPathIter;
926  dirPathAfterCommon = dirPathIter;
927  commonBitLength = i;
928  }
929  }
930  }
931 
932  // if the only common bit is the root, then just return the full path..
933  if (commonBitLength == 0 || (commonBitLength == 1 && thisPath[1] == getSeparatorChar()))
934  return fullPath;
935 
936  auto numUpDirectoriesNeeded = countNumberOfSeparators (dirPathAfterCommon);
937 
938  if (numUpDirectoriesNeeded == 0)
939  return thisPathAfterCommon;
940 
941  #if JUCE_WINDOWS
942  auto s = String::repeatedString ("..\\", numUpDirectoriesNeeded);
943  #else
944  auto s = String::repeatedString ("../", numUpDirectoriesNeeded);
945  #endif
946  s.appendCharPointer (thisPathAfterCommon);
947  return s;
948 }
949 
950 //==============================================================================
952 {
953  auto tempFile = getSpecialLocation (tempDirectory)
954  .getChildFile ("temp_" + String::toHexString (Random::getSystemRandom().nextInt()))
955  .withFileExtension (fileNameEnding);
956 
957  if (tempFile.exists())
958  return createTempFile (fileNameEnding);
959 
960  return tempFile;
961 }
962 
963 bool File::createSymbolicLink (const File& linkFileToCreate,
964  [[maybe_unused]] const String& nativePathOfTarget,
965  bool overwriteExisting)
966 {
967  if (linkFileToCreate.exists())
968  {
969  if (! linkFileToCreate.isSymbolicLink())
970  {
971  // user has specified an existing file / directory as the link
972  // this is bad! the user could end up unintentionally destroying data
973  jassertfalse;
974  return false;
975  }
976 
977  if (overwriteExisting)
978  linkFileToCreate.deleteFile();
979  }
980 
981  #if JUCE_MAC || JUCE_LINUX || JUCE_BSD
982  // one common reason for getting an error here is that the file already exists
983  if (symlink (nativePathOfTarget.toRawUTF8(), linkFileToCreate.getFullPathName().toRawUTF8()) == -1)
984  {
985  jassertfalse;
986  return false;
987  }
988 
989  return true;
990  #elif JUCE_MSVC
991  File targetFile (linkFileToCreate.getSiblingFile (nativePathOfTarget));
992 
993  return CreateSymbolicLink (linkFileToCreate.getFullPathName().toWideCharPointer(),
994  nativePathOfTarget.toWideCharPointer(),
995  targetFile.isDirectory() ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) != FALSE;
996  #else
997  jassertfalse; // symbolic links not supported on this platform!
998  return false;
999  #endif
1000 }
1001 
1002 bool File::createSymbolicLink (const File& linkFileToCreate, bool overwriteExisting) const
1003 {
1004  return createSymbolicLink (linkFileToCreate, getFullPathName(), overwriteExisting);
1005 }
1006 
1007 #if ! JUCE_WINDOWS
1009 {
1010  if (isSymbolicLink())
1012 
1013  return *this;
1014 }
1015 #endif
1016 
1017 //==============================================================================
1018 #if JUCE_ALLOW_STATIC_NULL_VARIABLES
1019 
1020 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
1021 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
1022 
1023 const File File::nonexistent{};
1024 
1025 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1026 JUCE_END_IGNORE_WARNINGS_MSVC
1027 
1028 #endif
1029 
1030 //==============================================================================
1032  : range (0, file.getSize())
1033 {
1034  openInternal (file, mode, exclusive);
1035 }
1036 
1037 MemoryMappedFile::MemoryMappedFile (const File& file, const Range<int64>& fileRange, AccessMode mode, bool exclusive)
1038  : range (fileRange.getIntersectionWith (Range<int64> (0, file.getSize())))
1039 {
1040  openInternal (file, mode, exclusive);
1041 }
1042 
1043 
1044 //==============================================================================
1045 //==============================================================================
1046 #if JUCE_UNIT_TESTS
1047 
1048 class FileTests final : public UnitTest
1049 {
1050 public:
1051  FileTests()
1052  : UnitTest ("Files", UnitTestCategories::files)
1053  {}
1054 
1055  void runTest() override
1056  {
1057  beginTest ("Reading");
1058 
1060  const File temp (File::getSpecialLocation (File::tempDirectory));
1061 
1062  expect (! File().exists());
1063  expect (! File().existsAsFile());
1064  expect (! File().isDirectory());
1065  #if ! JUCE_WINDOWS
1066  expect (File ("/").isDirectory());
1067  #endif
1068  expect (home.isDirectory());
1069  expect (home.exists());
1070  expect (! home.existsAsFile());
1075  expect (home.getVolumeTotalSize() > 1024 * 1024);
1076  expect (home.getBytesFreeOnVolume() > 0);
1077  expect (! home.isHidden());
1078  expect (home.isOnHardDisk());
1079  expect (! home.isOnCDRomDrive());
1080  expect (File::getCurrentWorkingDirectory().exists());
1081  expect (home.setAsCurrentWorkingDirectory());
1082 
1083  {
1084  auto homeParent = home;
1085  bool noSymlinks = true;
1086 
1087  while (! homeParent.isRoot())
1088  {
1089  if (homeParent.isSymbolicLink())
1090  {
1091  noSymlinks = false;
1092  break;
1093  }
1094 
1095  homeParent = homeParent.getParentDirectory();
1096  }
1097 
1098  if (noSymlinks)
1099  expect (File::getCurrentWorkingDirectory() == home);
1100  }
1101 
1102  {
1103  Array<File> roots;
1104  File::findFileSystemRoots (roots);
1105  expect (roots.size() > 0);
1106 
1107  int numRootsExisting = 0;
1108  for (int i = 0; i < roots.size(); ++i)
1109  if (roots[i].exists())
1110  ++numRootsExisting;
1111 
1112  // (on windows, some of the drives may not contain media, so as long as at least one is ok..)
1113  expect (numRootsExisting > 0);
1114  }
1115 
1116  beginTest ("Writing");
1117 
1118  auto random = getRandom();
1119  const auto tempFolderName = "JUCE UnitTests Temp Folder "
1120  + String::toHexString (random.nextInt())
1121  + ".folder";
1122  File demoFolder (temp.getChildFile (tempFolderName));
1123  expect (demoFolder.deleteRecursively());
1124  expect (demoFolder.createDirectory());
1125  expect (demoFolder.isDirectory());
1126  expect (demoFolder.getParentDirectory() == temp);
1127  expect (temp.isDirectory());
1128  expect (temp.findChildFiles (File::findFilesAndDirectories, false, "*").contains (demoFolder));
1129  expect (temp.findChildFiles (File::findDirectories, true, "*.folder").contains (demoFolder));
1130 
1131  File tempFile (demoFolder.getNonexistentChildFile ("test", ".txt", false));
1132 
1133  expect (tempFile.getFileExtension() == ".txt");
1134  expect (tempFile.hasFileExtension (".txt"));
1135  expect (tempFile.hasFileExtension ("txt"));
1136  expect (tempFile.withFileExtension ("xyz").hasFileExtension (".xyz"));
1137  expect (tempFile.withFileExtension ("xyz").hasFileExtension ("abc;xyz;foo"));
1138  expect (tempFile.withFileExtension ("xyz").hasFileExtension ("xyz;foo"));
1139  expect (! tempFile.withFileExtension ("h").hasFileExtension ("bar;foo;xx"));
1140  expect (tempFile.getSiblingFile ("foo").isAChildOf (temp));
1141  expect (tempFile.hasWriteAccess());
1142 
1143  expect (home.getChildFile (".") == home);
1144  expect (home.getChildFile ("..") == home.getParentDirectory());
1145  expect (home.getChildFile (".xyz").getFileName() == ".xyz");
1146  expect (home.getChildFile ("..xyz").getFileName() == "..xyz");
1147  expect (home.getChildFile ("...xyz").getFileName() == "...xyz");
1148  expect (home.getChildFile ("./xyz") == home.getChildFile ("xyz"));
1149  expect (home.getChildFile ("././xyz") == home.getChildFile ("xyz"));
1150  expect (home.getChildFile ("../xyz") == home.getParentDirectory().getChildFile ("xyz"));
1151  expect (home.getChildFile (".././xyz") == home.getParentDirectory().getChildFile ("xyz"));
1152  expect (home.getChildFile (".././xyz/./abc") == home.getParentDirectory().getChildFile ("xyz/abc"));
1153  expect (home.getChildFile ("./../xyz") == home.getParentDirectory().getChildFile ("xyz"));
1154  expect (home.getChildFile ("a1/a2/a3/./../../a4") == home.getChildFile ("a1/a4"));
1155 
1156  expect (! File().hasReadAccess());
1157  expect (! File().hasWriteAccess());
1158 
1159  expect (! tempFile.hasReadAccess());
1160 
1161  {
1162  FileOutputStream fo (tempFile);
1163  fo.write ("0123456789", 10);
1164  }
1165 
1166  expect (tempFile.hasReadAccess());
1167 
1168  expect (tempFile.exists());
1169  expect (tempFile.getSize() == 10);
1170  expect (std::abs ((int) (tempFile.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds())) < 3000);
1171  expectEquals (tempFile.loadFileAsString(), String ("0123456789"));
1172  expect (! demoFolder.containsSubDirectories());
1173 
1174  expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() + File::getSeparatorString() + tempFile.getFileName());
1175  expectEquals (demoFolder.getParentDirectory().getRelativePathFrom (tempFile), ".." + File::getSeparatorString() + ".." + File::getSeparatorString() + demoFolder.getParentDirectory().getFileName());
1176 
1177  expect (demoFolder.getNumberOfChildFiles (File::findFiles) == 1);
1178  expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 1);
1179  expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 0);
1180  demoFolder.getNonexistentChildFile ("tempFolder", "", false).createDirectory();
1181  expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 1);
1182  expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 2);
1183  expect (demoFolder.containsSubDirectories());
1184 
1185  expect (tempFile.hasWriteAccess());
1186  tempFile.setReadOnly (true);
1187  expect (! tempFile.hasWriteAccess());
1188  tempFile.setReadOnly (false);
1189  expect (tempFile.hasWriteAccess());
1190 
1191  Time t (Time::getCurrentTime());
1192  tempFile.setLastModificationTime (t);
1193  Time t2 = tempFile.getLastModificationTime();
1194  expect (std::abs ((int) (t2.toMilliseconds() - t.toMilliseconds())) <= 1000);
1195 
1196  {
1197  MemoryBlock mb;
1198  tempFile.loadFileAsData (mb);
1199  expect (mb.getSize() == 10);
1200  expect (mb[0] == '0');
1201  }
1202 
1203  {
1204  expect (tempFile.getSize() == 10);
1205  FileOutputStream fo (tempFile);
1206  expect (fo.openedOk());
1207 
1208  expect (fo.setPosition (7));
1209  expect (fo.truncate().wasOk());
1210  expect (tempFile.getSize() == 7);
1211  fo.write ("789", 3);
1212  fo.flush();
1213  expect (tempFile.getSize() == 10);
1214  }
1215 
1216  beginTest ("Memory-mapped files");
1217 
1218  {
1219  MemoryMappedFile mmf (tempFile, MemoryMappedFile::readOnly);
1220  expect (mmf.getSize() == 10);
1221  expect (mmf.getData() != nullptr);
1222  expect (memcmp (mmf.getData(), "0123456789", 10) == 0);
1223  }
1224 
1225  {
1226  const File tempFile2 (tempFile.getNonexistentSibling (false));
1227  expect (tempFile2.create());
1228  expect (tempFile2.appendData ("xxxxxxxxxx", 10));
1229 
1230  {
1231  MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite);
1232  expect (mmf.getSize() == 10);
1233  expect (mmf.getData() != nullptr);
1234  memcpy (mmf.getData(), "abcdefghij", 10);
1235  }
1236 
1237  {
1238  MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite);
1239  expect (mmf.getSize() == 10);
1240  expect (mmf.getData() != nullptr);
1241  expect (memcmp (mmf.getData(), "abcdefghij", 10) == 0);
1242  }
1243 
1244  expect (tempFile2.deleteFile());
1245  }
1246 
1247  beginTest ("More writing");
1248 
1249  expect (tempFile.appendData ("abcdefghij", 10));
1250  expect (tempFile.getSize() == 20);
1251  expect (tempFile.replaceWithData ("abcdefghij", 10));
1252  expect (tempFile.getSize() == 10);
1253 
1254  File tempFile2 (tempFile.getNonexistentSibling (false));
1255  expect (tempFile.copyFileTo (tempFile2));
1256  expect (tempFile2.exists());
1257  expect (tempFile2.hasIdenticalContentTo (tempFile));
1258  expect (tempFile.deleteFile());
1259  expect (! tempFile.exists());
1260  expect (tempFile2.moveFileTo (tempFile));
1261  expect (tempFile.exists());
1262  expect (! tempFile2.exists());
1263 
1264  expect (demoFolder.deleteRecursively());
1265  expect (! demoFolder.exists());
1266 
1267  {
1268  URL url ("https://audio.dev/foo/bar/");
1269  expectEquals (url.toString (false), String ("https://audio.dev/foo/bar/"));
1270  expectEquals (url.getChildURL ("x").toString (false), String ("https://audio.dev/foo/bar/x"));
1271  expectEquals (url.getParentURL().toString (false), String ("https://audio.dev/foo"));
1272  expectEquals (url.getParentURL().getParentURL().toString (false), String ("https://audio.dev/"));
1273  expectEquals (url.getParentURL().getParentURL().getParentURL().toString (false), String ("https://audio.dev/"));
1274  expectEquals (url.getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/foo/x"));
1275  expectEquals (url.getParentURL().getParentURL().getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/x"));
1276  }
1277 
1278  {
1279  URL url ("https://audio.dev/foo/bar");
1280  expectEquals (url.toString (false), String ("https://audio.dev/foo/bar"));
1281  expectEquals (url.getChildURL ("x").toString (false), String ("https://audio.dev/foo/bar/x"));
1282  expectEquals (url.getParentURL().toString (false), String ("https://audio.dev/foo"));
1283  expectEquals (url.getParentURL().getParentURL().toString (false), String ("https://audio.dev/"));
1284  expectEquals (url.getParentURL().getParentURL().getParentURL().toString (false), String ("https://audio.dev/"));
1285  expectEquals (url.getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/foo/x"));
1286  expectEquals (url.getParentURL().getParentURL().getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/x"));
1287  }
1288  }
1289 };
1290 
1291 static FileTests fileUnitTests;
1292 
1293 #endif
1294 
1295 } // namespace juce
void add(const ElementType &newElement)
Definition: juce_Array.h:418
static juce_wchar toLowerCase(juce_wchar character) noexcept
static bool isDigit(char character) noexcept
int read(void *, int) override
bool openedOk() const noexcept
bool write(const void *, size_t) override
bool failedToOpen() const noexcept
const Result & getStatus() const noexcept
bool openedOk() const noexcept
std::unique_ptr< FileOutputStream > createOutputStream(size_t bufferSize=0x8000) const
Definition: juce_File.cpp:742
bool replaceWithText(const String &textToWrite, bool asUnicode=false, bool writeUnicodeHeaderBytes=false, const char *lineEndings="\r\n") const
Definition: juce_File.cpp:786
bool isSymbolicLink() const
int getNumberOfChildFiles(int whatToLookFor, const String &wildCardPattern="*") const
Definition: juce_File.cpp:592
bool moveFileTo(const File &targetLocation) const
Definition: juce_File.cpp:288
bool operator==(const File &) const
Definition: juce_File.cpp:254
int64 hashCode64() const
Definition: juce_File.cpp:405
bool containsSubDirectories() const
Definition: juce_File.cpp:600
bool isDirectory() const
Array< File > findChildFiles(int whatToLookFor, bool searchRecursively, const String &wildCardPattern="*", FollowSymlinks followSymlinks=FollowSymlinks::yes) const
Definition: juce_File.cpp:572
static void findFileSystemRoots(Array< File > &results)
bool hasIdenticalContentTo(const File &other) const
Definition: juce_File.cpp:793
static String createLegalPathName(const String &pathNameToFix)
Definition: juce_File.cpp:828
static String addTrailingSeparator(const String &path)
Definition: juce_File.cpp:225
String getFileExtension() const
Definition: juce_File.cpp:672
Time getLastModificationTime() const
Definition: juce_File.cpp:538
const String & getFullPathName() const noexcept
Definition: juce_File.h:153
bool existsAsFile() const
bool copyFileTo(const File &targetLocation) const
Definition: juce_File.cpp:305
int64 getSize() const
bool deleteRecursively(bool followSymlinks=false) const
Definition: juce_File.cpp:277
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
String getFileName() const
Definition: juce_File.cpp:372
bool replaceWithData(const void *dataToWrite, size_t numberOfBytes) const
Definition: juce_File.cpp:765
bool setLastAccessTime(Time newTime) const
Definition: juce_File.cpp:543
File getChildFile(StringRef relativeOrAbsolutePath) const
Definition: juce_File.cpp:420
void readLines(StringArray &destLines) const
Definition: juce_File.cpp:566
static bool isAbsolutePath(StringRef path)
Definition: juce_File.cpp:408
File getSiblingFile(StringRef siblingFileName) const
Definition: juce_File.cpp:477
bool createSymbolicLink(const File &linkFileToCreate, bool overwriteExisting) const
Definition: juce_File.cpp:1002
String getFileNameWithoutExtension() const
Definition: juce_File.cpp:377
File getNonexistentSibling(bool putNumbersInBrackets=true) const
Definition: juce_File.cpp:661
@ tempDirectory
Definition: juce_File.h:919
@ currentApplicationFile
Definition: juce_File.h:942
@ invokedExecutableFile
Definition: juce_File.h:949
@ userApplicationDataDirectory
Definition: juce_File.h:895
@ currentExecutableFile
Definition: juce_File.h:932
@ userHomeDirectory
Definition: juce_File.h:869
String getRelativePathFrom(const File &directoryToBeRelativeTo) const
Definition: juce_File.cpp:887
bool appendText(const String &textToAppend, bool asUnicode=false, bool writeUnicodeHeaderBytes=false, const char *lineEndings="\r\n") const
Definition: juce_File.cpp:776
int hashCode() const
Definition: juce_File.cpp:404
Result create() const
Definition: juce_File.cpp:498
@ findDirectories
Definition: juce_File.h:565
@ findFilesAndDirectories
Definition: juce_File.h:567
File getNonexistentChildFile(const String &prefix, const String &suffix, bool putNumbersInBrackets=true) const
Definition: juce_File.cpp:609
bool operator!=(const File &) const
Definition: juce_File.cpp:255
bool setCreationTime(Time newTime) const
Definition: juce_File.cpp:544
static String descriptionOfSizeInBytes(int64 bytes)
Definition: juce_File.cpp:483
bool setReadOnly(bool shouldBeReadOnly, bool applyRecursively=false) const
Definition: juce_File.cpp:260
static File createTempFile(StringRef fileNameEnding)
Definition: juce_File.cpp:951
static juce_wchar getSeparatorChar()
static bool areFileNamesCaseSensitive()
Definition: juce_File.cpp:236
bool isRoot() const
Definition: juce_File.cpp:125
String loadFileAsString() const
Definition: juce_File.cpp:556
bool operator>(const File &) const
Definition: juce_File.cpp:257
File getLinkedTarget() const
Definition: juce_File.cpp:1008
File getParentDirectory() const
Definition: juce_File.cpp:358
bool appendData(const void *dataToAppend, size_t numberOfBytes) const
Definition: juce_File.cpp:753
std::unique_ptr< FileInputStream > createInputStream() const
Definition: juce_File.cpp:732
bool operator<(const File &) const
Definition: juce_File.cpp:256
Time getCreationTime() const
Definition: juce_File.cpp:540
bool setExecutePermission(bool shouldBeExecutable) const
Definition: juce_File.cpp:272
File withFileExtension(StringRef newExtension) const
Definition: juce_File.cpp:707
static String createLegalFileName(const String &fileNameToFix)
Definition: juce_File.cpp:843
File()=default
bool deleteFile() const
bool replaceFileIn(const File &targetLocation) const
Definition: juce_File.cpp:311
bool isAChildOf(const File &potentialParentDirectory) const
Definition: juce_File.cpp:388
static File createFileWithoutCheckingPath(const String &absolutePath) noexcept
Definition: juce_File.cpp:31
bool startAsProcess(const String &parameters=String()) const
Definition: juce_File.cpp:726
String getNativeLinkedTarget() const
bool hasFileExtension(StringRef extensionToTest) const
Definition: juce_File.cpp:682
bool exists() const
bool copyDirectoryTo(const File &newDirectory) const
Definition: juce_File.cpp:326
bool loadFileAsData(MemoryBlock &result) const
Definition: juce_File.cpp:547
bool setLastModificationTime(Time newTime) const
Definition: juce_File.cpp:542
Time getLastAccessTime() const
Definition: juce_File.cpp:539
Result createDirectory() const
Definition: juce_File.cpp:519
static File getCurrentWorkingDirectory()
static StringRef getSeparatorString()
File & operator=(const String &newAbsolutePath)
Definition: juce_File.cpp:43
virtual size_t readIntoMemoryBlock(MemoryBlock &destBlock, ssize_t maxNumBytesToRead=-1)
virtual String readEntireStreamAsString()
static void JUCE_CALLTYPE writeToLog(const String &message)
Definition: juce_Logger.cpp:40
MemoryMappedFile(const File &file, AccessMode mode, bool exclusive=false)
Definition: juce_File.cpp:1031
virtual bool writeText(const String &text, bool asUTF16, bool writeUTF16ByteOrderMark, const char *lineEndings)
static bool JUCE_CALLTYPE openDocument(const String &documentURL, const String &parameters)
static Random & getSystemRandom() noexcept
Definition: juce_Random.cpp:67
static Result fail(const String &errorMessage) noexcept
Definition: juce_Result.cpp:65
static Result ok() noexcept
Definition: juce_Result.h:61
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
int size() const noexcept
int addLines(StringRef stringToBreakUp)
void removeRange(int startIndex, int numberToRemove)
void remove(int index)
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
bool isNotEmpty() const noexcept
int length() const noexcept
String::CharPointerType text
bool isEmpty() const noexcept
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
int indexOfChar(juce_wchar characterToLookFor) const noexcept
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
int length() const noexcept
bool endsWithChar(juce_wchar character) const noexcept
bool isEmpty() const noexcept
Definition: juce_String.h:310
const char * toRawUTF8() const
int64 hashCode64() const noexcept
bool containsChar(juce_wchar character) const noexcept
String removeCharacters(StringRef charactersToRemove) const
bool endsWithIgnoreCase(StringRef text) const noexcept
String dropLastCharacters(int numberToDrop) const
bool contains(StringRef text) const noexcept
String trimEnd() const
static String toHexString(IntegerType number)
Definition: juce_String.h:1097
int lastIndexOfChar(juce_wchar character) const noexcept
const wchar_t * toWideCharPointer() const
String trimCharactersAtEnd(StringRef charactersToTrim) const
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
String substring(int startIndex, int endIndex) const
int hashCode() const noexcept
bool isNotEmpty() const noexcept
Definition: juce_String.h:316
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
bool overwriteTargetFileWithTemporary() const
const File & getFile() const noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Definition: juce_Time.cpp:233
int64 toMilliseconds() const noexcept
Definition: juce_Time.h:98