29namespace PropertyFileConstants
31 constexpr static const int magicNumber = (int)
ByteOrder::makeInt (
'P',
'R',
'O',
'P');
32 constexpr static const int magicNumberCompressed = (int)
ByteOrder::makeInt (
'C',
'P',
'R',
'P');
34 constexpr static const char*
const fileTag =
"PROPERTIES";
35 constexpr static const char*
const valueTag =
"VALUE";
36 constexpr static const char*
const nameAttribute =
"name";
37 constexpr static const char*
const valueAttribute =
"val";
56 #if JUCE_MAC || JUCE_IOS
92 #elif JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
117 file (f), options (o)
124 file (o.getDefaultFile()), options (o)
131 ProcessScopedLock pl (createProcessLock());
133 if (pl !=
nullptr && ! pl->isLocked())
136 loadedOk = (! file.exists()) || loadAsBinary() || loadAsXml();
152 const ScopedLock sl (
getLock());
153 return (! needsWriting) ||
save();
158 const ScopedLock sl (
getLock());
164 const ScopedLock sl (
getLock());
165 needsWriting = needsToBeSaved_;
170 const ScopedLock sl (
getLock());
174 if (options.doNotSave
177 || ! file.getParentDirectory().createDirectory())
180 if (options.storageFormat == storeAsXML)
183 return saveAsBinary();
186bool PropertiesFile::loadAsXml()
188 if (
auto doc = parseXMLIfTagMatches (file, PropertyFileConstants::fileTag))
190 for (
auto* e : doc->getChildWithTagNameIterator (PropertyFileConstants::valueTag))
192 auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute);
194 if (name.isNotEmpty())
196 e->getFirstChildElement() !=
nullptr
198 : e->getStringAttribute (PropertyFileConstants::valueAttribute));
207bool PropertiesFile::saveAsXml()
209 XmlElement doc (PropertyFileConstants::fileTag);
212 for (
int i = 0; i < props.size(); ++i)
214 auto* e = doc.createNewChildElement (PropertyFileConstants::valueTag);
215 e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]);
218 if (
auto childElement = parseXML (props.getAllValues() [i]))
219 e->addChildElement (childElement.release());
221 e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]);
224 ProcessScopedLock pl (createProcessLock());
226 if (pl !=
nullptr && ! pl->isLocked())
229 if (doc.writeTo (file, {}))
231 needsWriting =
false;
238bool PropertiesFile::loadAsBinary()
240 FileInputStream fileStream (file);
242 if (fileStream.openedOk())
244 auto magicNumber = fileStream.readInt();
246 if (magicNumber == PropertyFileConstants::magicNumberCompressed)
248 SubregionStream subStream (&fileStream, 4, -1,
false);
249 GZIPDecompressorInputStream gzip (subStream);
250 return loadAsBinary (gzip);
253 if (magicNumber == PropertyFileConstants::magicNumber)
254 return loadAsBinary (fileStream);
260bool PropertiesFile::loadAsBinary (
InputStream& input)
262 BufferedInputStream in (input, 2048);
264 int numValues = in.readInt();
266 while (--numValues >= 0 && ! in.isExhausted())
268 auto key = in.readString();
269 auto value = in.readString();
270 jassert (key.isNotEmpty());
272 if (key.isNotEmpty())
279bool PropertiesFile::saveAsBinary()
281 ProcessScopedLock pl (createProcessLock());
283 if (pl !=
nullptr && ! pl->isLocked())
286 TemporaryFile tempFile (file);
289 FileOutputStream out (tempFile.getFile());
291 if (! out.openedOk())
294 if (options.storageFormat == storeAsCompressedBinary)
296 out.writeInt (PropertyFileConstants::magicNumberCompressed);
299 GZIPCompressorOutputStream zipped (out, 9);
301 if (! writeToStream (zipped))
307 jassert (options.storageFormat == storeAsBinary);
309 out.writeInt (PropertyFileConstants::magicNumber);
311 if (! writeToStream (out))
316 if (! tempFile.overwriteTargetFileWithTemporary())
319 needsWriting =
false;
326 auto& keys = props.getAllKeys();
327 auto& values = props.getAllValues();
328 auto numProperties = props.size();
330 if (! out.writeInt (numProperties))
333 for (
int i = 0; i < numProperties; ++i)
335 if (! out.writeString (keys[i]))
return false;
336 if (! out.writeString (values[i]))
return false;
342void PropertiesFile::timerCallback()
352 if (options.millisecondsBeforeSaving > 0)
353 startTimer (options.millisecondsBeforeSaving);
354 else if (options.millisecondsBeforeSaving == 0)
static constexpr uint16 makeInt(uint8 leastSig, uint8 mostSig) noexcept
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
File getChildFile(StringRef relativeOrAbsolutePath) const
@ userApplicationDataDirectory
@ commonApplicationDataDirectory
File withFileExtension(StringRef newExtension) const
static String createLegalFileName(const String &fileNameToFix)
~PropertiesFile() override
PropertiesFile(const Options &options)
void setNeedsToBeSaved(bool needsToBeSaved)
bool needsToBeSaved() const
void propertyChanged() override
StringPairArray & getAllProperties() noexcept
const CriticalSection & getLock() const noexcept
PropertySet(bool ignoreCaseOfKeyNames=false)
void set(const String &key, const String &value)
void stopTimer() noexcept
void startTimer(int intervalInMilliseconds) noexcept
StorageFormat storageFormat
File getDefaultFile() const
InterProcessLock * processLock
String osxLibrarySubFolder
bool ignoreCaseOfKeyNames
int millisecondsBeforeSaving
TextFormat withoutHeader() const
TextFormat singleLine() const