30namespace PropertyFileConstants
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');
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";
43 : commonToAllUsers (false),
44 ignoreCaseOfKeyNames (false),
46 millisecondsBeforeSaving (3000),
57 #if JUCE_MAC || JUCE_IOS
58 File dir (commonToAllUsers ?
"/Library/"
61 if (osxLibrarySubFolder !=
"Preferences"
62 && ! osxLibrarySubFolder.startsWith (
"Application Support")
63 && ! osxLibrarySubFolder.startsWith (
"Containers"))
90 if (folderName.isNotEmpty())
93 #elif JUCE_LINUX || JUCE_ANDROID
94 auto dir =
File (commonToAllUsers ?
"/var" :
"~")
95 .getChildFile (folderName.isNotEmpty() ? folderName
96 : (
"." + applicationName));
105 dir = dir.
getChildFile (folderName.isNotEmpty() ? folderName
109 return (filenameSuffix.startsWithChar (L
'.')
111 : dir.
getChildFile (applicationName +
"." + filenameSuffix));
118 file (f), options (o)
125 file (o.getDefaultFile()), options (o)
132 ProcessScopedLock pl (createProcessLock());
134 if (pl !=
nullptr && ! pl->isLocked())
137 loadedOk = (! file.
exists()) || loadAsBinary() || loadAsXml();
154 return (! needsWriting) ||
save();
166 needsWriting = needsToBeSaved_;
184 return saveAsBinary();
187bool PropertiesFile::loadAsXml()
190 std::unique_ptr<XmlElement> doc (parser.getDocumentElement (
true));
192 if (doc !=
nullptr && doc->hasTagName (PropertyFileConstants::fileTag))
194 doc.reset (parser.getDocumentElement());
198 forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag)
200 auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute);
202 if (name.isNotEmpty())
204 e->getFirstChildElement() !=
nullptr
205 ? e->getFirstChildElement()->createDocument (
"",
true)
206 : e->getStringAttribute (PropertyFileConstants::valueAttribute));
221bool PropertiesFile::saveAsXml()
223 XmlElement doc (PropertyFileConstants::fileTag);
226 for (
int i = 0; i < props.size(); ++i)
228 auto* e = doc.createNewChildElement (PropertyFileConstants::valueTag);
229 e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]);
233 e->addChildElement (childElement);
235 e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]);
238 ProcessScopedLock pl (createProcessLock());
240 if (pl !=
nullptr && ! pl->isLocked())
243 if (doc.writeToFile (file, {}))
245 needsWriting =
false;
252bool PropertiesFile::loadAsBinary()
254 FileInputStream fileStream (file);
256 if (fileStream.openedOk())
258 auto magicNumber = fileStream.readInt();
260 if (magicNumber == PropertyFileConstants::magicNumberCompressed)
262 SubregionStream subStream (&fileStream, 4, -1,
false);
263 GZIPDecompressorInputStream gzip (subStream);
264 return loadAsBinary (gzip);
267 if (magicNumber == PropertyFileConstants::magicNumber)
268 return loadAsBinary (fileStream);
274bool PropertiesFile::loadAsBinary (InputStream& input)
276 BufferedInputStream in (input, 2048);
278 int numValues = in.readInt();
280 while (--numValues >= 0 && ! in.isExhausted())
282 auto key = in.readString();
283 auto value = in.readString();
284 jassert (key.isNotEmpty());
286 if (key.isNotEmpty())
293bool PropertiesFile::saveAsBinary()
295 ProcessScopedLock pl (createProcessLock());
297 if (pl !=
nullptr && ! pl->isLocked())
300 TemporaryFile tempFile (file);
303 FileOutputStream out (tempFile.getFile());
305 if (! out.openedOk())
310 out.writeInt (PropertyFileConstants::magicNumberCompressed);
313 GZIPCompressorOutputStream zipped (out, 9);
315 if (! writeToStream (zipped))
323 out.writeInt (PropertyFileConstants::magicNumber);
325 if (! writeToStream (out))
330 if (! tempFile.overwriteTargetFileWithTemporary())
333 needsWriting =
false;
337bool PropertiesFile::writeToStream (OutputStream& out)
340 auto& keys = props.getAllKeys();
341 auto& values = props.getAllValues();
342 auto numProperties = props.size();
344 if (! out.writeInt (numProperties))
347 for (
int i = 0; i < numProperties; ++i)
349 if (! out.writeString (keys[i]))
return false;
350 if (! out.writeString (values[i]))
return false;
356void PropertiesFile::timerCallback()
static JUCE_CONSTEXPR uint16 makeInt(uint8 leastSig, uint8 mostSig) noexcept
Constructs a 16-bit integer from its constituent bytes, in order of significance.
void sendChangeMessage()
Causes an asynchronous change message to be sent to all the registered listeners.
Represents a local file or directory.
bool isDirectory() const
Checks whether the file is a directory that exists.
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.
File getChildFile(StringRef relativeOrAbsolutePath) const
Returns a file that represents a relative (or absolute) sub-path of the current one.
@ userApplicationDataDirectory
The folder in which applications store their persistent user-specific settings.
@ commonApplicationDataDirectory
An equivalent of the userApplicationDataDirectory folder that is shared by all users of the computer,...
File getParentDirectory() const
Returns the directory that contains this file or directory.
File withFileExtension(StringRef newExtension) const
Returns a version of this file with a different file extension.
static String createLegalFileName(const String &fileNameToFix)
Returns a version of a filename with any illegal characters removed.
bool exists() const
Checks whether the file actually exists.
Result createDirectory() const
Creates a new directory for this filename.
Automatically locks and unlocks a mutex object.
Automatically locks and unlocks an InterProcessLock object.
Wrapper on a file that stores a list of key/value data pairs.
~PropertiesFile() override
Destructor.
PropertiesFile(const Options &options)
Creates a PropertiesFile object.
void setNeedsToBeSaved(bool needsToBeSaved)
Explicitly sets the flag to indicate whether the file needs saving or not.
bool reload()
Attempts to reload the settings from the file.
bool needsToBeSaved() const
Returns true if the properties have been altered since the last time they were saved.
bool saveIfNeeded()
This will flush all the values to disk if they've changed since the last time they were saved.
bool save()
This will force a write-to-disk of the current values, regardless of whether anything has changed sin...
void propertyChanged() override
A set of named property values, which can be strings, integers, floating point, etc.
StringPairArray & getAllProperties() noexcept
Returns the keys/value pair array containing all the properties.
const CriticalSection & getLock() const noexcept
Returns the lock used when reading or writing to this set.
void set(const String &key, const String &value)
Adds or amends a key/value pair.
void stopTimer() noexcept
Stops the timer.
void startTimer(int intervalInMilliseconds) noexcept
Starts the timer and sets the length of interval required.
Parses a text-based XML document and creates an XmlElement object from it.
static XmlElement * parse(const File &file)
A handy static method that parses a file.
Structure describing properties file options.
Options()
Creates an empty Options structure.
StorageFormat storageFormat
Specifies whether the file should be written as XML, binary, etc.
File getDefaultFile() const
This can be called to suggest a file that should be used, based on the values in this structure.
InterProcessLock * processLock
An optional InterprocessLock object that will be used to prevent multiple threads or processes from w...
bool doNotSave
If set to true, this prevents the file from being written to disk.
int millisecondsBeforeSaving
If this is zero or greater, then after a value is changed, the object will wait for this amount of ti...