writeToFile returns false?


#1

Hi All
I’m facing a weird issue, I’m saving presets into XML files, it works fine when debugging from Xcode, and fails when the application is running in release mode.

I’m testing this code on Mac OS sierra.

The writeToFile function below returns false in release mode, works fine when running from Xcode debugger.
Any tips would be greatly appreciated.

int MyClass::savePresetToFile(File theFile)
{
#ifdef DEBUG
std::cout << "savePresetToFile: " << std::endl;
#endif
// build an XML file with all params
MidiController *midiController = MidiController::getInstance();

if(midiController->isConnectedToBl == true) return PRESET_FILE_NO_DEVICE;
if(midiController->isConnectedToNormal == false) return PRESET_FILE_NO_DEVICE;
XmlElement rootNode ("Preset");
// header Preset->date/appVer
//XmlElement infoNode ("Info");
XmlElement* infoNode = new XmlElement ("Info");
infoNode->setAttribute("Date", juce::Time::getCurrentTime().toString(true, true));
infoNode->setAttribute("AppVer", APP_VER);
rootNode.addChildElement(infoNode);
//infoNode->deleteAllChildElements();
// Device infos
//XmlElement deviceNode ("Device");
XmlElement* deviceNode = new XmlElement ("Device");
deviceNode->setAttribute("prodId", (int) midiController->SYSX_PRODUCT_ID_25_37);
deviceNode->setAttribute("FwVer", String::formatted("%.1f", midiController->connectedDevice.fwVersion));
deviceNode->setAttribute("BlVer", String::formatted("%.1f", midiController->connectedDevice.blVersion));
rootNode.addChildElement(deviceNode);
//deviceNode->deleteAllChildElements();
// all add parameters to the XML
XmlElement* paramNode = new XmlElement ("Params");
int nbReg = FillMultiParamArrayWithAllRegisters();
for(int i=0; i<nbReg; i++)
{
    XmlElement* regNode = new XmlElement ("Reg");
    // grab the register value in paramsBeforeUpdateArray[paramId][i] without sending to midi
    int nbWordsForThisReg = midiController->updateSingleRegister(midiController->multiParamArray[i], false);
    String valStr = "";
    for(int j=0; j<nbWordsForThisReg; j++)
    {
        valStr += String::formatted("%08X", midiController->paramsBeforeUpdateArray[midiController->multiParamArray[i]][j]);
    }

#ifdef DEBUG
std::cout << String::formatted(“Reg%d ->”, midiController->multiParamArray[i])+valStr << std::endl;
#endif

    regNode->setAttribute(String::formatted("Reg%d", midiController->multiParamArray[i]), valStr);
    paramNode->addChildElement(regNode);
    //regNode->deleteAllChildElements();
}
rootNode.addChildElement(paramNode);
//paramNode->deleteAllChildElements();

#ifdef DEBUG
String myXmlDoc = rootNode.createDocument(String::empty);
std::cout << "XML: " + myXmlDoc << std::endl;
#endif

// save the xml to file
int res = rootNode.writeToFile(theFile, "");
rootNode.deleteAllChildElements();
if(res > 0) return PRESET_FILE_OK;
return PRESET_FILE_CANNOT_CREATE;

}


#2

…and the ifdef DEBUG is intentional?
Without that line the element is not a valid XML document, I think…


#3

Thanks Daniel
I tried to comment this #ifdef DEBUG and it did not help.
myXmlDoc is just used to display the doc to save in the console, I’m saving the rootNode, not myXmlDoc
rootNode.writeToFile(theFile, “”);


#4

Ah sorry, my mistake…
And I just realize, that the writeToFile() will also add DTD and other needed stuff, so I was on the wrong track…


#5

No other tip regarding this weird issue ?


#6

Probably writing to the wrong file, or appending to it rather than replacing it, or writing somewhere you’ve not got permission. Or running in a sandbox in release mode?

Debug it! Step into the method and see what happens in there.


#7

Thanks Jules for your inputs.
I debugged the issue and found an error code “Operation not permitted” while trying to open the temporary file created by Juce.
This happens in “openHandle->open->getFullPathName”.
My app is available on the app store, compiled with Xcode 8, so I had to enable App sandboxing.
App sandbox is configured with “User selected file” -> Read/Write so I was thinking this would enable writing to any folder within the user directory.
What am I missing ?
Does anybody here have experience with enabling file write on Sierra ?
Again, thanks to all for any input, I’m stuck.
Jerome

Edit: I enabled the file access “Download folder” in the App sandbox settings, and now I can write the file within the “Download” folder.
My question is now, how can I enable an arbitrary folder to be written ?


#8

After in depth reading the sandboxed apps security issues, I found the app has read/write permissions enabled on its own folder, For sandboxed apps, this folder on Mac OS is:

/Users/username/Library/Containers/app bundle ID/Data/

According to the above, the file picker dialog is initialized with the directory “userApplicationDataDirectory”, but this points to ‘/Users/username/Library/’ rather than ‘/Users/username/Library/Containers/app bundle ID/Data/’

Should I append the missing ‘Containers/app bundle ID/Data/’ myself so the default directory is correct ?


#9

I don’t think JUCE provides a way to query the current bundle id. You could, however, add it as a preprocessor define in the Projucer.