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"))
83 dir =
dir.getChildFile (
"Application Support");
87 dir =
dir.getChildFile (osxLibrarySubFolder);
90 if (folderName.isNotEmpty())
91 dir =
dir.getChildFile (folderName);
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'.')
110 ?
dir.getChildFile (applicationName).withFileExtension (filenameSuffix)
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();
184 return saveAsBinary();
187bool PropertiesFile::loadAsXml()
189 if (
auto doc = parseXMLIfTagMatches (file, PropertyFileConstants::fileTag))
191 forEachXmlChildElementWithTagName (*
doc,
e, PropertyFileConstants::valueTag)
193 auto name =
e->getStringAttribute (PropertyFileConstants::nameAttribute);
195 if (name.isNotEmpty())
197 e->getFirstChildElement() !=
nullptr
199 :
e->getStringAttribute (PropertyFileConstants::valueAttribute));
208bool PropertiesFile::saveAsXml()
210 XmlElement doc (PropertyFileConstants::fileTag);
213 for (
int i = 0; i < props.size(); ++i)
215 auto* e = doc.createNewChildElement (PropertyFileConstants::valueTag);
216 e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]);
219 if (
auto childElement = parseXML (props.getAllValues() [i]))
220 e->addChildElement (childElement.release());
222 e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]);
225 ProcessScopedLock pl (createProcessLock());
227 if (pl !=
nullptr && ! pl->isLocked())
230 if (doc.writeTo (file, {}))
232 needsWriting =
false;
239bool PropertiesFile::loadAsBinary()
241 FileInputStream fileStream (file);
243 if (fileStream.openedOk())
245 auto magicNumber = fileStream.readInt();
247 if (magicNumber == PropertyFileConstants::magicNumberCompressed)
249 SubregionStream subStream (&fileStream, 4, -1,
false);
250 GZIPDecompressorInputStream gzip (subStream);
251 return loadAsBinary (gzip);
254 if (magicNumber == PropertyFileConstants::magicNumber)
255 return loadAsBinary (fileStream);
261bool PropertiesFile::loadAsBinary (InputStream& input)
263 BufferedInputStream in (input, 2048);
265 int numValues = in.readInt();
267 while (--numValues >= 0 && ! in.isExhausted())
269 auto key = in.readString();
270 auto value = in.readString();
271 jassert (key.isNotEmpty());
273 if (key.isNotEmpty())
280bool PropertiesFile::saveAsBinary()
282 ProcessScopedLock pl (createProcessLock());
284 if (pl !=
nullptr && ! pl->isLocked())
287 TemporaryFile tempFile (file);
290 FileOutputStream out (tempFile.getFile());
292 if (! out.openedOk())
297 out.writeInt (PropertyFileConstants::magicNumberCompressed);
300 GZIPCompressorOutputStream zipped (out, 9);
302 if (! writeToStream (zipped))
310 out.writeInt (PropertyFileConstants::magicNumber);
312 if (! writeToStream (out))
317 if (! tempFile.overwriteTargetFileWithTemporary())
320 needsWriting =
false;
324bool PropertiesFile::writeToStream (OutputStream& out)
327 auto& keys = props.getAllKeys();
328 auto& values = props.getAllValues();
329 auto numProperties = props.size();
331 if (! out.writeInt (numProperties))
334 for (
int i = 0; i < numProperties; ++i)
336 if (! out.writeString (keys[i]))
return false;
337 if (! out.writeString (values[i]))
return false;
343void PropertiesFile::timerCallback()
static JUCE_CONSTEXPR uint16 makeInt(uint8 leastSig, uint8 mostSig) noexcept
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
@ userApplicationDataDirectory
@ commonApplicationDataDirectory
File getParentDirectory() const
static String createLegalFileName(const String &fileNameToFix)
Result createDirectory() const
~PropertiesFile() override
PropertiesFile(const Options &options)
void setNeedsToBeSaved(bool needsToBeSaved)
bool needsToBeSaved() const
void propertyChanged() override
StringPairArray & getAllProperties() noexcept
const CriticalSection & getLock() const noexcept
void set(const String &key, const String &value)
void stopTimer() noexcept
void startTimer(int intervalInMilliseconds) noexcept
StorageFormat storageFormat
File getDefaultFile() const
InterProcessLock * processLock
int millisecondsBeforeSaving
TextFormat withoutHeader() const
TextFormat singleLine() const