410 lines
12 KiB
C++
410 lines
12 KiB
C++
/*
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
|
* file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
*
|
|
*/
|
|
/*
|
|
File: XMLPrefsParser.cpp
|
|
|
|
Contains: Prototype implementation of XMLPrefsParser object.
|
|
|
|
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
#ifndef __Win32__
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "XMLPrefsParser.h"
|
|
#include "OSMemory.h"
|
|
#include "OSHeaders.h"
|
|
|
|
static const UInt32 kPrefArrayMinSize = 20;
|
|
|
|
static char* kMainTag = "CONFIGURATION";
|
|
static char* kServer = "SERVER";
|
|
static char* kModule = "MODULE";
|
|
static char* kPref = "PREF";
|
|
static char* kListPref = "LIST-PREF";
|
|
static char* kEmptyObject = "EMPTY-OBJECT";
|
|
static char* kObject = "OBJECT";
|
|
static char* kObjectList = "LIST-OBJECT";
|
|
static char* kValue = "VALUE";
|
|
static char* kNameAttr = "NAME";
|
|
static char* kTypeAttr = "TYPE";
|
|
|
|
static char* kFileHeader[] =
|
|
{
|
|
"<?xml version =\"1.0\"?>",
|
|
"<!-- The Document Type Definition (DTD) for the file -->",
|
|
"<!DOCTYPE CONFIGURATION [",
|
|
"<!ELEMENT CONFIGURATION (SERVER, MODULE*)>",
|
|
"<!ELEMENT SERVER (PREF|LIST-PREF|OBJECT|LIST-OBJECT)*>",
|
|
"<!ELEMENT MODULE (PREF|LIST-PREF|OBJECT|LIST-OBJECT)*>",
|
|
"<!ATTLIST MODULE",
|
|
"\tNAME CDATA #REQUIRED>",
|
|
"<!ELEMENT PREF (#PCDATA)>",
|
|
"<!ATTLIST PREF",
|
|
"\tNAME CDATA #REQUIRED",
|
|
"\tTYPE (UInt8|SInt8|UInt16|SInt16|UInt32|SInt32|UInt64|SInt64|Float32|Float64|Bool16|Bool8|char) \"char\">",
|
|
"<!ELEMENT LIST-PREF (VALUE*)>",
|
|
"<!ELEMENT VALUE (#PCDATA)>",
|
|
"<!ATTLIST LIST-PREF",
|
|
"\tNAME CDATA #REQUIRED",
|
|
"\tTYPE (UInt8|SInt8|UInt16|SInt16|UInt32|SInt32|UInt64|SInt64|Float32|Float64|Bool16|Bool8|char) \"char\">",
|
|
"<!ELEMENT OBJECT (PREF|LIST-PREF|OBJECT|LIST-OBJECT)*>",
|
|
"<!ATTLIST OBJECT",
|
|
"\tNAME CDATA #REQUIRED>",
|
|
"<!ELEMENT LIST-OBJECT (OBJECT-VALUE*)>",
|
|
"<!ELEMENT OBJECT-VALUE (PREF|LIST-PREF|OBJECT|LIST-OBJECT)*>",
|
|
"<!ATTLIST LIST-OBJECT",
|
|
"\tNAME CDATA #REQUIRED>",
|
|
"]>",
|
|
NULL
|
|
};
|
|
|
|
XMLPrefsParser::XMLPrefsParser(char* inPath)
|
|
: XMLParser(inPath)
|
|
{}
|
|
|
|
XMLPrefsParser::~XMLPrefsParser()
|
|
{}
|
|
|
|
|
|
ContainerRef XMLPrefsParser::GetConfigurationTag()
|
|
{
|
|
ContainerRef result = GetRootTag();
|
|
if (result == NULL)
|
|
{
|
|
result = new XMLTag(kMainTag);
|
|
SetRootTag(result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
ContainerRef XMLPrefsParser::GetRefForModule(char* inModuleName, Bool16 create)
|
|
{
|
|
if (inModuleName == NULL)
|
|
return GetRefForServer();
|
|
|
|
ContainerRef result = GetConfigurationTag()->GetEmbeddedTagByNameAndAttr(kModule, kNameAttr, inModuleName);
|
|
if (result == NULL)
|
|
{
|
|
result = new XMLTag(kModule);
|
|
result->AddAttribute( kNameAttr, (char*)inModuleName);
|
|
GetRootTag()->AddEmbeddedTag(result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
ContainerRef XMLPrefsParser::GetRefForServer()
|
|
{
|
|
ContainerRef result = GetConfigurationTag()->GetEmbeddedTagByName(kServer);
|
|
if (result == NULL)
|
|
{
|
|
result = new XMLTag(kServer);
|
|
GetRootTag()->AddEmbeddedTag(result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
UInt32 XMLPrefsParser::GetNumPrefValues(ContainerRef pref)
|
|
{
|
|
if (!strcmp(pref->GetTagName(), kPref))
|
|
{
|
|
if (pref->GetValue() == NULL)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
else if (!strcmp(pref->GetTagName(), kObject))
|
|
return 1;
|
|
else if (!strcmp(pref->GetTagName(), kEmptyObject))
|
|
return 0;
|
|
|
|
return pref->GetNumEmbeddedTags(); // it must be a list
|
|
}
|
|
|
|
UInt32 XMLPrefsParser::GetNumPrefsByContainer(ContainerRef container)
|
|
{
|
|
return container->GetNumEmbeddedTags();
|
|
}
|
|
|
|
char* XMLPrefsParser::GetPrefValueByIndex(ContainerRef container, const UInt32 inPrefsIndex, const UInt32 inValueIndex,
|
|
char** outPrefName, char** outDataType)
|
|
{
|
|
if (outPrefName != NULL)
|
|
*outPrefName = NULL;
|
|
if (outPrefName != NULL)
|
|
*outDataType = NULL;
|
|
XMLTag* pref = container->GetEmbeddedTag(inPrefsIndex);
|
|
if (pref == NULL)
|
|
return NULL;
|
|
|
|
return GetPrefValueByRef(pref, inValueIndex, outPrefName, outDataType);
|
|
}
|
|
|
|
char* XMLPrefsParser::GetPrefValueByRef(ContainerRef pref, const UInt32 inValueIndex,
|
|
char** outPrefName, char** outDataType)
|
|
{
|
|
if (outPrefName != NULL)
|
|
*outPrefName = pref->GetAttributeValue(kNameAttr);
|
|
if (outDataType != NULL)
|
|
{
|
|
*outDataType = pref->GetAttributeValue(kTypeAttr);
|
|
if (*outDataType == NULL)
|
|
*outDataType = "CharArray";
|
|
}
|
|
|
|
if (!strcmp(pref->GetTagName(), kPref))
|
|
{
|
|
if (inValueIndex > 0)
|
|
return NULL;
|
|
else
|
|
return pref->GetValue();
|
|
}
|
|
|
|
if (!strcmp(pref->GetTagName(), kListPref))
|
|
{
|
|
XMLTag* value = pref->GetEmbeddedTag(inValueIndex);
|
|
if (value != NULL)
|
|
return value->GetValue();
|
|
}
|
|
|
|
if (!strcmp(pref->GetTagName(), kObject) || !strcmp(pref->GetTagName(), kObjectList))
|
|
*outDataType = "QTSS_Object";
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ContainerRef XMLPrefsParser::GetObjectValue(ContainerRef pref, const UInt32 inValueIndex)
|
|
{
|
|
if (!strcmp(pref->GetTagName(), kObject) && (inValueIndex == 0))
|
|
return pref;
|
|
if (!strcmp(pref->GetTagName(), kObjectList))
|
|
return pref->GetEmbeddedTag(inValueIndex);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ContainerRef XMLPrefsParser::GetPrefRefByName( ContainerRef container,
|
|
const char* inPrefName)
|
|
{
|
|
return container->GetEmbeddedTagByAttr(kNameAttr, inPrefName);
|
|
}
|
|
|
|
ContainerRef XMLPrefsParser::GetPrefRefByIndex( ContainerRef container,
|
|
const UInt32 inPrefsIndex)
|
|
{
|
|
return container->GetEmbeddedTag(inPrefsIndex);
|
|
}
|
|
|
|
ContainerRef XMLPrefsParser::AddPref( ContainerRef container, char* inPrefName,
|
|
char* inPrefDataType )
|
|
{
|
|
XMLTag* pref = container->GetEmbeddedTagByAttr(kNameAttr, inPrefName);
|
|
if (pref != NULL)
|
|
return pref; // it already exists
|
|
|
|
pref = NEW XMLTag(kPref); // start it out as a pref
|
|
pref->AddAttribute(kNameAttr, inPrefName);
|
|
if (!strcmp(inPrefDataType, "QTSS_Object"))
|
|
pref->SetTagName(kEmptyObject);
|
|
else if (strcmp(inPrefDataType, "CharArray"))
|
|
pref->AddAttribute(kTypeAttr, (char*)inPrefDataType);
|
|
|
|
container->AddEmbeddedTag(pref);
|
|
|
|
return pref;
|
|
}
|
|
|
|
void XMLPrefsParser::AddPrefValue( ContainerRef pref, char* inNewValue)
|
|
{
|
|
if (!strcmp(pref->GetTagName(), kPref)) // is this a PREF tag
|
|
{
|
|
if (pref->GetValue() == NULL)
|
|
{
|
|
// easy case, no existing value, so just add a vlue
|
|
pref->SetValue(inNewValue);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// it already has a value, so change the pref to be a list pref and go to code below
|
|
char* firstValue = pref->GetValue();
|
|
XMLTag* value = NEW XMLTag(kValue);
|
|
value->SetValue(firstValue);
|
|
|
|
pref->SetTagName(kListPref);
|
|
pref->SetValue(NULL);
|
|
pref->AddEmbeddedTag(value);
|
|
}
|
|
}
|
|
|
|
// we want to fall through from second case above, so this isn't an else
|
|
if (!strcmp(pref->GetTagName(), kListPref))
|
|
{
|
|
XMLTag* value = NEW XMLTag(kValue);
|
|
value->SetValue(inNewValue);
|
|
pref->AddEmbeddedTag(value);
|
|
}
|
|
}
|
|
|
|
void XMLPrefsParser::AddNewObject( ContainerRef pref )
|
|
{
|
|
if (!strcmp(pref->GetTagName(), kEmptyObject))
|
|
{
|
|
// just flag that this is now a real object instead of a placeholder
|
|
pref->SetTagName(kObject);
|
|
return;
|
|
}
|
|
|
|
if (!strcmp(pref->GetTagName(), kObject))
|
|
{
|
|
// change the object to be an object list and go to code below
|
|
XMLTag* subObject = NEW XMLTag(kObject);
|
|
XMLTag* objectPref;
|
|
// copy all this objects tags into the new listed object
|
|
while((objectPref = pref->GetEmbeddedTag()) != NULL)
|
|
{
|
|
pref->RemoveEmbeddedTag(objectPref);
|
|
subObject->AddEmbeddedTag(objectPref);
|
|
}
|
|
|
|
pref->SetTagName(kObjectList);
|
|
pref->AddEmbeddedTag(subObject);
|
|
}
|
|
|
|
// we want to fall through from second case above, so this isn't an else
|
|
if (!strcmp(pref->GetTagName(), kObjectList))
|
|
{
|
|
XMLTag* subObject = NEW XMLTag(kObject);
|
|
pref->AddEmbeddedTag(subObject);
|
|
}
|
|
}
|
|
|
|
void XMLPrefsParser::ChangePrefType( ContainerRef pref, char* inNewPrefDataType)
|
|
{
|
|
pref->RemoveAttribute(kTypeAttr); // remove it if it exists
|
|
if (strcmp(inNewPrefDataType, "CharArray"))
|
|
pref->AddAttribute(kTypeAttr, inNewPrefDataType);
|
|
}
|
|
|
|
void XMLPrefsParser::SetPrefValue( ContainerRef pref, const UInt32 inValueIndex,
|
|
char* inNewValue)
|
|
{
|
|
UInt32 numValues = GetNumPrefValues(pref);
|
|
|
|
if (((numValues == 0) || (numValues == 1)) && (inValueIndex == 0))
|
|
{
|
|
pref->SetValue(inNewValue);
|
|
}
|
|
else if (inValueIndex == numValues) // this is an additional value
|
|
AddPrefValue(pref, inNewValue);
|
|
else
|
|
{
|
|
XMLTag* value = pref->GetEmbeddedTag(inValueIndex);
|
|
if (value != NULL)
|
|
value->SetValue(inNewValue);
|
|
}
|
|
}
|
|
|
|
void XMLPrefsParser::RemovePrefValue( ContainerRef pref, const UInt32 inValueIndex)
|
|
{
|
|
UInt32 numValues = GetNumPrefValues(pref);
|
|
if (inValueIndex >= numValues)
|
|
return;
|
|
|
|
if (numValues == 1)
|
|
{
|
|
delete pref; // just remove the whole pref
|
|
}
|
|
else if (numValues == 2)
|
|
{
|
|
XMLTag* value = pref->GetEmbeddedTag(inValueIndex); // get the one we're removing
|
|
delete value; // delete it
|
|
value = pref->GetEmbeddedTag(0); // get the remaining tag index always 0 for 2 vals
|
|
pref->RemoveEmbeddedTag(value); // pull it out of the parent
|
|
if (!strcmp(pref->GetTagName(), kObjectList))
|
|
{
|
|
pref->SetTagName(kObject); // set it back to a simple pref
|
|
// move all this objects tags into the parent
|
|
XMLTag* objectPref;
|
|
while((objectPref = value->GetEmbeddedTag()) != NULL)
|
|
{
|
|
value->RemoveEmbeddedTag(objectPref);
|
|
pref->AddEmbeddedTag(objectPref);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char* temp = value->GetValue();
|
|
pref->SetTagName(kPref); // set it back to a simple pref
|
|
pref->SetValue(temp);
|
|
}
|
|
|
|
delete value; // get rid of the other one
|
|
}
|
|
else
|
|
{
|
|
XMLTag* value = pref->GetEmbeddedTag(inValueIndex);
|
|
if (value)
|
|
delete value;
|
|
}
|
|
}
|
|
|
|
void XMLPrefsParser::RemovePref( ContainerRef pref )
|
|
{
|
|
delete pref;
|
|
}
|
|
|
|
int XMLPrefsParser::Parse()
|
|
{
|
|
char error[500];
|
|
|
|
if (!ParseFile(error, sizeof(error)))
|
|
{
|
|
qtss_printf("%s\n", error);
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
// the above routine checks that it's a valid XML file, we should check that
|
|
// all the tags conform to our prefs format
|
|
|
|
return 0;
|
|
}
|
|
|
|
int XMLPrefsParser::WritePrefsFile()
|
|
{
|
|
GetConfigurationTag(); // force it to be created if it doesn't exist
|
|
WriteToFile(kFileHeader);
|
|
return 0;
|
|
}
|