We stumbled upon an issue with the way double attributes are converted in the XmlElement class.
When executed within a plugin on a system with German locale (!), the XmlElement::setAttribute(String, double) method will use a comma as delimiter. When parsing the attribute with XmlElement::getDoubleAttribute() everything behind the comma is discarded.
We narrowed it down further:
NumberToStringConverters::doubleToString will use sprintf if the number of decimal places isn’t specified. In a ProTools plugin, this will result in a comma.
In CharacterFunctions::readDoubleValue the decimal point is hard-coded as “.”
We didn’t see this behaviour in the standalone version or any other host than ProTools. Nevertheless, it feels wrong that the XmlElement’s setAttribute() methods use conversions that can depend on the system’s locale.
Here’s a paint method to reproduce this issue with a basic IntroJucer plugin project:
I suppose the correct thing to do would be to write my own exponential string formatter, but haven’t time to do that right now… An alternative would be to add some code that checks the result of sprintf and replaces any commas with dots, but that’d be an awful hack! (But you might want to add a quick bit of code yourself to do that while I have a think about it)
however, I think that the double-writing and reading in the String class is still a bit unconsistent. In doubleToString (…) if numDecPlaces is > 0, you do the following:
while (numDecPlaces >= 0 || v > 0)
{
if (numDecPlaces == 0)
*--t = (char) getDecimalPoint();
*--t = (char) ('0' + (v % 10));
v /= 10;
--numDecPlaces;
}
where getDecimalPoint uses the locale symbol (so either dot or comma), but in juce_CharacterFunctions.h in readDoubleValue (CharPointerType& text) you assume the decimal point to be a dot.
Maybe it would be better to omit the getDecimalPoint and stick with the dot?!?! Then things would be at least consistent.
What do you think?
We had to change the _sprintf_l solution to be effective on my windows system. Just passing null didn’t work as intended, so we explicitly request the C locale now:
len = _sprintf_l (buffer, "%.9g", _create_locale(LC_NUMERIC, "C"), n);