OpenShot Audio Library | OpenShotAudio: juce_PropertiesFile.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.3.0

Loading...
Searching...
No Matches
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
27namespace juce
28{
29
30namespace 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//==============================================================================
42PropertiesFile::Options::Options()
43 : commonToAllUsers (false),
44 ignoreCaseOfKeyNames (false),
45 doNotSave (false),
46 millisecondsBeforeSaving (3000),
47 storageFormat (PropertiesFile::storeAsXML),
48 processLock (nullptr)
49{
50}
51
52 File PropertiesFile::Options::getDefaultFile() const
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
99 auto dir = File::getSpecialLocation (commonToAllUsers ? File::commonApplicationDataDirectory
100 : File::userApplicationDataDirectory);
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//==============================================================================
116 PropertiesFile::PropertiesFile (const File& f, const Options& o)
117 : PropertySet (o.ignoreCaseOfKeyNames),
118 file (f), options (o)
119{
120 reload();
121}
122
123PropertiesFile::PropertiesFile (const Options& o)
124 : PropertySet (o.ignoreCaseOfKeyNames),
125 file (o.getDefaultFile()), options (o)
126{
127 reload();
128}
129
130 bool PropertiesFile::reload()
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
141PropertiesFile::~PropertiesFile()
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
151 bool PropertiesFile::saveIfNeeded()
152{
153 const ScopedLock sl (getLock());
154 return (! needsWriting) || save();
155}
156
157 bool PropertiesFile::needsToBeSaved() const
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
169 bool PropertiesFile::save()
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
187bool PropertiesFile::loadAsXml()
188{
189 if (auto doc = parseXMLIfTagMatches (file, PropertyFileConstants::fileTag))
190 {
191 forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag)
192 {
193 auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute);
194
195 if (name.isNotEmpty())
196 getAllProperties().set (name,
197 e->getFirstChildElement() != nullptr
198 ? e->getFirstChildElement()->toString (XmlElement::TextFormat().singleLine().withoutHeader())
199 : e->getStringAttribute (PropertyFileConstants::valueAttribute));
200 }
201
202 return true;
203 }
204
205 return false;
206}
207
208bool PropertiesFile::saveAsXml()
209{
210 XmlElement doc (PropertyFileConstants::fileTag);
211 auto& props = getAllProperties();
212
213 for (int i = 0; i < props.size(); ++i)
214 {
215 auto* e = doc.createNewChildElement (PropertyFileConstants::valueTag);
216 e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]);
217
218 // if the value seems to contain xml, store it as such..
219 if (auto childElement = parseXML (props.getAllValues() [i]))
220 e->addChildElement (childElement.release());
221 else
222 e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]);
223 }
224
225 ProcessScopedLock pl (createProcessLock());
226
227 if (pl != nullptr && ! pl->isLocked())
228 return false; // locking failure..
229
230 if (doc.writeTo (file, {}))
231 {
232 needsWriting = false;
233 return true;
234 }
235
236 return false;
237}
238
239bool PropertiesFile::loadAsBinary()
240{
241 FileInputStream fileStream (file);
242
243 if (fileStream.openedOk())
244 {
245 auto magicNumber = fileStream.readInt();
246
247 if (magicNumber == PropertyFileConstants::magicNumberCompressed)
248 {
249 SubregionStream subStream (&fileStream, 4, -1, false);
250 GZIPDecompressorInputStream gzip (subStream);
251 return loadAsBinary (gzip);
252 }
253
254 if (magicNumber == PropertyFileConstants::magicNumber)
255 return loadAsBinary (fileStream);
256 }
257
258 return false;
259}
260
261bool PropertiesFile::loadAsBinary (InputStream& input)
262{
263 BufferedInputStream in (input, 2048);
264
265 int numValues = in.readInt();
266
267 while (--numValues >= 0 && ! in.isExhausted())
268 {
269 auto key = in.readString();
270 auto value = in.readString();
271 jassert (key.isNotEmpty());
272
273 if (key.isNotEmpty())
274 getAllProperties().set (key, value);
275 }
276
277 return true;
278}
279
280bool PropertiesFile::saveAsBinary()
281{
282 ProcessScopedLock pl (createProcessLock());
283
284 if (pl != nullptr && ! pl->isLocked())
285 return false; // locking failure..
286
287 TemporaryFile tempFile (file);
288
289 {
290 FileOutputStream out (tempFile.getFile());
291
292 if (! out.openedOk())
293 return false;
294
295 if (options.storageFormat == storeAsCompressedBinary)
296 {
297 out.writeInt (PropertyFileConstants::magicNumberCompressed);
298 out.flush();
299
300 GZIPCompressorOutputStream zipped (out, 9);
301
302 if (! writeToStream (zipped))
303 return false;
304 }
305 else
306 {
307 // have you set up the storage option flags correctly?
308 jassert (options.storageFormat == storeAsBinary);
309
310 out.writeInt (PropertyFileConstants::magicNumber);
311
312 if (! writeToStream (out))
313 return false;
314 }
315 }
316
317 if (! tempFile.overwriteTargetFileWithTemporary())
318 return false;
319
320 needsWriting = false;
321 return true;
322}
323
324bool PropertiesFile::writeToStream (OutputStream& out)
325{
326 auto& props = getAllProperties();
327 auto& keys = props.getAllKeys();
328 auto& values = props.getAllValues();
329 auto numProperties = props.size();
330
331 if (! out.writeInt (numProperties))
332 return false;
333
334 for (int i = 0; i < numProperties; ++i)
335 {
336 if (! out.writeString (keys[i])) return false;
337 if (! out.writeString (values[i])) return false;
338 }
339
340 return true;
341}
342
343void PropertiesFile::timerCallback()
344{
345 saveIfNeeded();
346}
347
348 void PropertiesFile::propertyChanged()
349{
350 sendChangeMessage();
351 needsWriting = true;
352
353 if (options.millisecondsBeforeSaving > 0)
354 startTimer (options.millisecondsBeforeSaving);
355 else if (options.millisecondsBeforeSaving == 0)
356 saveIfNeeded();
357}
358
359} // namespace juce
juce::ByteOrder::makeInt
static JUCE_CONSTEXPR uint16 makeInt(uint8 leastSig, uint8 mostSig) noexcept
Definition: juce_ByteOrder.h:181
juce::ChangeBroadcaster::sendChangeMessage
void sendChangeMessage()
Definition: juce_ChangeBroadcaster.cpp:65
juce::File
Definition: juce_File.h:41
juce::File::isDirectory
bool isDirectory() const
juce::File::getSpecialLocation
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
juce::File::getChildFile
File getChildFile(StringRef relativeOrAbsolutePath) const
Definition: juce_File.cpp:414
juce::File::userApplicationDataDirectory
@ userApplicationDataDirectory
Definition: juce_File.h:858
juce::File::commonApplicationDataDirectory
@ commonApplicationDataDirectory
Definition: juce_File.h:870
juce::File::getParentDirectory
File getParentDirectory() const
Definition: juce_File.cpp:360
juce::File::withFileExtension
File withFileExtension(StringRef newExtension) const
Definition: juce_File.cpp:704
juce::File::createLegalFileName
static String createLegalFileName(const String &fileNameToFix)
Definition: juce_File.cpp:838
juce::File::exists
bool exists() const
juce::File::createDirectory
Result createDirectory() const
Definition: juce_File.cpp:513
juce::GenericScopedLock
Definition: juce_ScopedLock.h:55
juce::InterProcessLock::ScopedLockType
Definition: juce_InterProcessLock.h:72
juce::PropertiesFile
Definition: juce_PropertiesFile.h:49
juce::PropertiesFile::~PropertiesFile
~PropertiesFile() override
Definition: juce_PropertiesFile.cpp:141
juce::PropertiesFile::PropertiesFile
PropertiesFile(const Options &options)
Definition: juce_PropertiesFile.cpp:123
juce::PropertiesFile::setNeedsToBeSaved
void setNeedsToBeSaved(bool needsToBeSaved)
Definition: juce_PropertiesFile.cpp:163
juce::PropertiesFile::reload
bool reload()
Definition: juce_PropertiesFile.cpp:130
juce::PropertiesFile::needsToBeSaved
bool needsToBeSaved() const
Definition: juce_PropertiesFile.cpp:157
juce::PropertiesFile::saveIfNeeded
bool saveIfNeeded()
Definition: juce_PropertiesFile.cpp:151
juce::PropertiesFile::save
bool save()
Definition: juce_PropertiesFile.cpp:169
juce::PropertiesFile::propertyChanged
void propertyChanged() override
Definition: juce_PropertiesFile.cpp:348
juce::PropertySet
Definition: juce_PropertySet.h:39
juce::PropertySet::getAllProperties
StringPairArray & getAllProperties() noexcept
Definition: juce_PropertySet.h:154
juce::PropertySet::getLock
const CriticalSection & getLock() const noexcept
Definition: juce_PropertySet.h:157
juce::StringPairArray::set
void set(const String &key, const String &value)
Definition: juce_StringPairArray.cpp:105
juce::Timer::stopTimer
void stopTimer() noexcept
Definition: juce_Timer.cpp:348
juce::Timer::startTimer
void startTimer(int intervalInMilliseconds) noexcept
Definition: juce_Timer.cpp:323
juce::PropertiesFile::Options
Definition: juce_PropertiesFile.h:62
juce::PropertiesFile::Options::Options
Options()
Definition: juce_PropertiesFile.cpp:42
juce::PropertiesFile::Options::storageFormat
StorageFormat storageFormat
Definition: juce_PropertiesFile.h:135
juce::PropertiesFile::Options::getDefaultFile
File getDefaultFile() const
Definition: juce_PropertiesFile.cpp:52
juce::PropertiesFile::Options::processLock
InterProcessLock * processLock
Definition: juce_PropertiesFile.h:144
juce::PropertiesFile::Options::doNotSave
bool doNotSave
Definition: juce_PropertiesFile.h:119
juce::PropertiesFile::Options::millisecondsBeforeSaving
int millisecondsBeforeSaving
Definition: juce_PropertiesFile.h:129
juce::XmlElement::TextFormat
Definition: juce_XmlElement.h:191
juce::XmlElement::TextFormat::withoutHeader
TextFormat withoutHeader() const
Definition: juce_XmlElement.cpp:345
juce::XmlElement::TextFormat::singleLine
TextFormat singleLine() const
Definition: juce_XmlElement.cpp:338