OpenShot Library | libopenshot-audio  0.2.0
juce_PropertiesFile.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11  Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12  27th April 2017).
13 
14  End User License Agreement: www.juce.com/juce-5-licence
15  Privacy Policy: www.juce.com/juce-5-privacy-policy
16 
17  Or: You may also use this code under the terms of the GPL v3 (see
18  www.gnu.org/licenses).
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
30 namespace PropertyFileConstants
31 {
32  JUCE_CONSTEXPR static const int magicNumber = (int) ByteOrder::makeInt ('P', 'R', 'O', 'P');
33  JUCE_CONSTEXPR static const int magicNumberCompressed = (int) ByteOrder::makeInt ('C', 'P', 'R', 'P');
34 
35  JUCE_CONSTEXPR static const char* const fileTag = "PROPERTIES";
36  JUCE_CONSTEXPR static const char* const valueTag = "VALUE";
37  JUCE_CONSTEXPR static const char* const nameAttribute = "name";
38  JUCE_CONSTEXPR static const char* const valueAttribute = "val";
39 }
40 
41 //==============================================================================
43  : commonToAllUsers (false),
44  ignoreCaseOfKeyNames (false),
45  doNotSave (false),
46  millisecondsBeforeSaving (3000),
47  storageFormat (PropertiesFile::storeAsXML),
48  processLock (nullptr)
49 {
50 }
51 
53 {
54  // mustn't have illegal characters in this name..
55  jassert (applicationName == File::createLegalFileName (applicationName));
56 
57  #if JUCE_MAC || JUCE_IOS
58  File dir (commonToAllUsers ? "/Library/"
59  : "~/Library/");
60 
61  if (osxLibrarySubFolder != "Preferences"
62  && ! osxLibrarySubFolder.startsWith ("Application Support")
63  && ! osxLibrarySubFolder.startsWith ("Containers"))
64  {
65  /* The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple
66  have changed their advice, and now stipulate that settings should go in "Library/Application Support",
67  or Library/Containers/[app_bundle_id] for a sandboxed app.
68 
69  Because older apps would be broken by a silent change in this class's behaviour, you must now
70  explicitly set the osxLibrarySubFolder value to indicate which path you want to use.
71 
72  In newer apps, you should always set this to "Application Support"
73  or "Application Support/YourSubFolderName".
74 
75  If your app needs to load settings files that were created by older versions of juce and
76  you want to maintain backwards-compatibility, then you can set this to "Preferences".
77  But.. for better Apple-compliance, the recommended approach would be to write some code that
78  finds your old settings files in ~/Library/Preferences, moves them to ~/Library/Application Support,
79  and then uses the new path.
80  */
81  jassertfalse;
82 
83  dir = dir.getChildFile ("Application Support");
84  }
85  else
86  {
87  dir = dir.getChildFile (osxLibrarySubFolder);
88  }
89 
90  if (folderName.isNotEmpty())
91  dir = dir.getChildFile (folderName);
92 
93  #elif JUCE_LINUX || JUCE_ANDROID
94  auto dir = File (commonToAllUsers ? "/var" : "~")
95  .getChildFile (folderName.isNotEmpty() ? folderName
96  : ("." + applicationName));
97 
98  #elif JUCE_WINDOWS
101 
102  if (dir == File())
103  return {};
104 
105  dir = dir.getChildFile (folderName.isNotEmpty() ? folderName
106  : applicationName);
107  #endif
108 
109  return (filenameSuffix.startsWithChar (L'.')
110  ? dir.getChildFile (applicationName).withFileExtension (filenameSuffix)
111  : dir.getChildFile (applicationName + "." + filenameSuffix));
112 }
113 
114 
115 //==============================================================================
117  : PropertySet (o.ignoreCaseOfKeyNames),
118  file (f), options (o)
119 {
120  reload();
121 }
122 
124  : PropertySet (o.ignoreCaseOfKeyNames),
125  file (o.getDefaultFile()), options (o)
126 {
127  reload();
128 }
129 
131 {
132  ProcessScopedLock pl (createProcessLock());
133 
134  if (pl != nullptr && ! pl->isLocked())
135  return false; // locking failure..
136 
137  loadedOk = (! file.exists()) || loadAsBinary() || loadAsXml();
138  return loadedOk;
139 }
140 
142 {
143  saveIfNeeded();
144 }
145 
146 InterProcessLock::ScopedLockType* PropertiesFile::createProcessLock() const
147 {
148  return options.processLock != nullptr ? new InterProcessLock::ScopedLockType (*options.processLock) : nullptr;
149 }
150 
152 {
153  const ScopedLock sl (getLock());
154  return (! needsWriting) || save();
155 }
156 
158 {
159  const ScopedLock sl (getLock());
160  return needsWriting;
161 }
162 
163 void PropertiesFile::setNeedsToBeSaved (const bool needsToBeSaved_)
164 {
165  const ScopedLock sl (getLock());
166  needsWriting = needsToBeSaved_;
167 }
168 
170 {
171  const ScopedLock sl (getLock());
172 
173  stopTimer();
174 
175  if (options.doNotSave
176  || file == File()
177  || file.isDirectory()
178  || ! file.getParentDirectory().createDirectory())
179  return false;
180 
181  if (options.storageFormat == storeAsXML)
182  return saveAsXml();
183 
184  return saveAsBinary();
185 }
186 
187 bool PropertiesFile::loadAsXml()
188 {
189  XmlDocument parser (file);
190  std::unique_ptr<XmlElement> doc (parser.getDocumentElement (true));
191 
192  if (doc != nullptr && doc->hasTagName (PropertyFileConstants::fileTag))
193  {
194  doc.reset (parser.getDocumentElement());
195 
196  if (doc != nullptr)
197  {
198  forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag)
199  {
200  auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute);
201 
202  if (name.isNotEmpty())
203  getAllProperties().set (name,
204  e->getFirstChildElement() != nullptr
205  ? e->getFirstChildElement()->createDocument ("", true)
206  : e->getStringAttribute (PropertyFileConstants::valueAttribute));
207  }
208 
209  return true;
210  }
211 
212  // must be a pretty broken XML file we're trying to parse here,
213  // or a sign that this object needs an InterProcessLock,
214  // or just a failure reading the file. This last reason is why
215  // we don't jassertfalse here.
216  }
217 
218  return false;
219 }
220 
221 bool PropertiesFile::saveAsXml()
222 {
223  XmlElement doc (PropertyFileConstants::fileTag);
224  auto& props = getAllProperties();
225 
226  for (int i = 0; i < props.size(); ++i)
227  {
228  auto* e = doc.createNewChildElement (PropertyFileConstants::valueTag);
229  e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]);
230 
231  // if the value seems to contain xml, store it as such..
232  if (auto* childElement = XmlDocument::parse (props.getAllValues() [i]))
233  e->addChildElement (childElement);
234  else
235  e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]);
236  }
237 
238  ProcessScopedLock pl (createProcessLock());
239 
240  if (pl != nullptr && ! pl->isLocked())
241  return false; // locking failure..
242 
243  if (doc.writeToFile (file, {}))
244  {
245  needsWriting = false;
246  return true;
247  }
248 
249  return false;
250 }
251 
252 bool PropertiesFile::loadAsBinary()
253 {
254  FileInputStream fileStream (file);
255 
256  if (fileStream.openedOk())
257  {
258  auto magicNumber = fileStream.readInt();
259 
260  if (magicNumber == PropertyFileConstants::magicNumberCompressed)
261  {
262  SubregionStream subStream (&fileStream, 4, -1, false);
263  GZIPDecompressorInputStream gzip (subStream);
264  return loadAsBinary (gzip);
265  }
266 
267  if (magicNumber == PropertyFileConstants::magicNumber)
268  return loadAsBinary (fileStream);
269  }
270 
271  return false;
272 }
273 
274 bool PropertiesFile::loadAsBinary (InputStream& input)
275 {
276  BufferedInputStream in (input, 2048);
277 
278  int numValues = in.readInt();
279 
280  while (--numValues >= 0 && ! in.isExhausted())
281  {
282  auto key = in.readString();
283  auto value = in.readString();
284  jassert (key.isNotEmpty());
285 
286  if (key.isNotEmpty())
287  getAllProperties().set (key, value);
288  }
289 
290  return true;
291 }
292 
293 bool PropertiesFile::saveAsBinary()
294 {
295  ProcessScopedLock pl (createProcessLock());
296 
297  if (pl != nullptr && ! pl->isLocked())
298  return false; // locking failure..
299 
300  TemporaryFile tempFile (file);
301 
302  {
303  FileOutputStream out (tempFile.getFile());
304 
305  if (! out.openedOk())
306  return false;
307 
308  if (options.storageFormat == storeAsCompressedBinary)
309  {
310  out.writeInt (PropertyFileConstants::magicNumberCompressed);
311  out.flush();
312 
313  GZIPCompressorOutputStream zipped (out, 9);
314 
315  if (! writeToStream (zipped))
316  return false;
317  }
318  else
319  {
320  // have you set up the storage option flags correctly?
321  jassert (options.storageFormat == storeAsBinary);
322 
323  out.writeInt (PropertyFileConstants::magicNumber);
324 
325  if (! writeToStream (out))
326  return false;
327  }
328  }
329 
330  if (! tempFile.overwriteTargetFileWithTemporary())
331  return false;
332 
333  needsWriting = false;
334  return true;
335 }
336 
337 bool PropertiesFile::writeToStream (OutputStream& out)
338 {
339  auto& props = getAllProperties();
340  auto& keys = props.getAllKeys();
341  auto& values = props.getAllValues();
342  auto numProperties = props.size();
343 
344  if (! out.writeInt (numProperties))
345  return false;
346 
347  for (int i = 0; i < numProperties; ++i)
348  {
349  if (! out.writeString (keys[i])) return false;
350  if (! out.writeString (values[i])) return false;
351  }
352 
353  return true;
354 }
355 
356 void PropertiesFile::timerCallback()
357 {
358  saveIfNeeded();
359 }
360 
362 {
364  needsWriting = true;
365 
366  if (options.millisecondsBeforeSaving > 0)
368  else if (options.millisecondsBeforeSaving == 0)
369  saveIfNeeded();
370 }
371 
372 } // namespace juce
juce::PropertiesFile::Options
Structure describing properties file options.
Definition: juce_PropertiesFile.h:65
juce::PropertiesFile::Options::processLock
InterProcessLock * processLock
An optional InterprocessLock object that will be used to prevent multiple threads or processes from w...
Definition: juce_PropertiesFile.h:148
juce::XmlDocument
Parses a text-based XML document and creates an XmlElement object from it.
Definition: juce_XmlDocument.h:70
juce::File::isDirectory
bool isDirectory() const
Checks whether the file is a directory that exists.
juce::File::getParentDirectory
File getParentDirectory() const
Returns the directory that contains this file or directory.
Definition: juce_File.cpp:340
juce::PropertiesFile::save
bool save()
This will force a write-to-disk of the current values, regardless of whether anything has changed sin...
Definition: juce_PropertiesFile.cpp:169
juce::PropertiesFile::propertyChanged
void propertyChanged() override
Definition: juce_PropertiesFile.cpp:361
juce::Timer::startTimer
void startTimer(int intervalInMilliseconds) noexcept
Starts the timer and sets the length of interval required.
Definition: juce_Timer.cpp:323
juce::PropertySet
A set of named property values, which can be strings, integers, floating point, etc.
Definition: juce_PropertySet.h:42
juce::File::commonApplicationDataDirectory
@ commonApplicationDataDirectory
An equivalent of the userApplicationDataDirectory folder that is shared by all users of the computer,...
Definition: juce_File.h:874
juce::PropertiesFile::~PropertiesFile
~PropertiesFile() override
Destructor.
Definition: juce_PropertiesFile.cpp:141
juce::File::createDirectory
Result createDirectory() const
Creates a new directory for this filename.
Definition: juce_File.cpp:493
juce::PropertiesFile::Options::storageFormat
StorageFormat storageFormat
Specifies whether the file should be written as XML, binary, etc.
Definition: juce_PropertiesFile.h:139
juce::File::getSpecialLocation
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
Finds the location of a special type of file or directory, such as a home folder or documents folder.
juce::PropertiesFile::needsToBeSaved
bool needsToBeSaved() const
Returns true if the properties have been altered since the last time they were saved.
Definition: juce_PropertiesFile.cpp:157
juce::PropertiesFile::Options::millisecondsBeforeSaving
int millisecondsBeforeSaving
If this is zero or greater, then after a value is changed, the object will wait for this amount of ti...
Definition: juce_PropertiesFile.h:133
juce::PropertiesFile
Wrapper on a file that stores a list of key/value data pairs.
Definition: juce_PropertiesFile.h:50
juce::PropertySet::getLock
const CriticalSection & getLock() const noexcept
Returns the lock used when reading or writing to this set.
Definition: juce_PropertySet.h:161
juce::File
Represents a local file or directory.
Definition: juce_File.h:44
juce::InterProcessLock::ScopedLockType
Automatically locks and unlocks an InterProcessLock object.
Definition: juce_InterProcessLock.h:75
juce::File::exists
bool exists() const
Checks whether the file actually exists.
juce::Timer::stopTimer
void stopTimer() noexcept
Stops the timer.
Definition: juce_Timer.cpp:348
juce::PropertySet::getAllProperties
StringPairArray & getAllProperties() noexcept
Returns the keys/value pair array containing all the properties.
Definition: juce_PropertySet.h:158
juce::PropertiesFile::setNeedsToBeSaved
void setNeedsToBeSaved(bool needsToBeSaved)
Explicitly sets the flag to indicate whether the file needs saving or not.
Definition: juce_PropertiesFile.cpp:163
juce::PropertiesFile::Options::doNotSave
bool doNotSave
If set to true, this prevents the file from being written to disk.
Definition: juce_PropertiesFile.h:123
juce::File::withFileExtension
File withFileExtension(StringRef newExtension) const
Returns a version of this file with a different file extension.
Definition: juce_File.cpp:684
juce::StringPairArray::set
void set(const String &key, const String &value)
Adds or amends a key/value pair.
Definition: juce_StringPairArray.cpp:105
juce::ChangeBroadcaster::sendChangeMessage
void sendChangeMessage()
Causes an asynchronous change message to be sent to all the registered listeners.
Definition: juce_ChangeBroadcaster.cpp:62
juce::GenericScopedLock
Automatically locks and unlocks a mutex object.
Definition: juce_ScopedLock.h:58
juce::PropertiesFile::Options::getDefaultFile
File getDefaultFile() const
This can be called to suggest a file that should be used, based on the values in this structure.
Definition: juce_PropertiesFile.cpp:52
juce::File::userApplicationDataDirectory
@ userApplicationDataDirectory
The folder in which applications store their persistent user-specific settings.
Definition: juce_File.h:862
juce::PropertiesFile::saveIfNeeded
bool saveIfNeeded()
This will flush all the values to disk if they've changed since the last time they were saved.
Definition: juce_PropertiesFile.cpp:151
juce::File::createLegalFileName
static String createLegalFileName(const String &fileNameToFix)
Returns a version of a filename with any illegal characters removed.
Definition: juce_File.cpp:818
juce::PropertiesFile::Options::Options
Options()
Creates an empty Options structure.
Definition: juce_PropertiesFile.cpp:42
juce::ByteOrder::makeInt
static JUCE_CONSTEXPR uint16 makeInt(uint8 leastSig, uint8 mostSig) noexcept
Constructs a 16-bit integer from its constituent bytes, in order of significance.
Definition: juce_ByteOrder.h:185
juce::PropertiesFile::PropertiesFile
PropertiesFile(const Options &options)
Creates a PropertiesFile object.
Definition: juce_PropertiesFile.cpp:123
juce::XmlDocument::parse
static XmlElement * parse(const File &file)
A handy static method that parses a file.
Definition: juce_XmlDocument.cpp:31
juce::PropertiesFile::reload
bool reload()
Attempts to reload the settings from the file.
Definition: juce_PropertiesFile.cpp:130
juce::File::getChildFile
File getChildFile(StringRef relativeOrAbsolutePath) const
Returns a file that represents a relative (or absolute) sub-path of the current one.
Definition: juce_File.cpp:394