425 lines
16 KiB
C++
425 lines
16 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: QTSSPrefs.cpp
|
||
|
|
||
|
Contains: Implements class defined in QTSSPrefs.h.
|
||
|
|
||
|
Change History (most recent first):
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "QTSSPrefs.h"
|
||
|
#include "MyAssert.h"
|
||
|
#include "OSMemory.h"
|
||
|
#include "QTSSDataConverter.h"
|
||
|
#include "OSArrayObjectDeleter.h"
|
||
|
|
||
|
|
||
|
QTSSPrefs::QTSSPrefs(XMLPrefsParser* inPrefsSource, StrPtrLen* inModuleName, QTSSDictionaryMap* inMap,
|
||
|
Bool16 areInstanceAttrsAllowed, QTSSPrefs* parentDictionary )
|
||
|
: QTSSDictionary(inMap, &fPrefsMutex),
|
||
|
fPrefsSource(inPrefsSource),
|
||
|
fPrefName(NULL),
|
||
|
fParentDictionary(parentDictionary)
|
||
|
{
|
||
|
if (inModuleName != NULL)
|
||
|
fPrefName = inModuleName->GetAsCString();
|
||
|
}
|
||
|
|
||
|
QTSSDictionary* QTSSPrefs::CreateNewDictionary(QTSSDictionaryMap* inMap, OSMutex* /* inMutex */)
|
||
|
{
|
||
|
return NEW QTSSPrefs(fPrefsSource, NULL, inMap, true, this );
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::RereadPreferences()
|
||
|
{
|
||
|
RereadObjectPreferences(GetContainerRef());
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::RereadObjectPreferences(ContainerRef container)
|
||
|
{
|
||
|
QTSS_Error theErr = QTSS_NoErr;
|
||
|
|
||
|
//
|
||
|
// Keep track of which pref attributes should remain. All others
|
||
|
// will be removed.
|
||
|
// This routine uses names because it adds and deletes attributes. This means attribute indexes,positions and counts are constantly changing.
|
||
|
UInt32 initialNumAttrs = 0;
|
||
|
if (this->GetInstanceDictMap() != NULL)
|
||
|
{
|
||
|
initialNumAttrs = this->GetInstanceDictMap()->GetNumAttrs();
|
||
|
};
|
||
|
|
||
|
char** modulePrefInServer;
|
||
|
if (initialNumAttrs > 0)
|
||
|
{
|
||
|
modulePrefInServer = NEW char*[initialNumAttrs ];
|
||
|
::memset(modulePrefInServer, 0, sizeof(char*) * initialNumAttrs);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
modulePrefInServer = NULL;
|
||
|
}
|
||
|
|
||
|
OSMutexLocker locker(&fPrefsMutex);
|
||
|
UInt32 theNumPrefs = fPrefsSource->GetNumPrefsByContainer(container);
|
||
|
|
||
|
for (UInt32 i = 0; i < initialNumAttrs;i++) // pull out all the names in the server
|
||
|
{
|
||
|
QTSSAttrInfoDict* theAttrInfoPtr = NULL;
|
||
|
theErr = this->GetInstanceDictMap()->GetAttrInfoByIndex(i, &theAttrInfoPtr);
|
||
|
if (theErr != QTSS_NoErr)
|
||
|
continue;
|
||
|
|
||
|
UInt32 nameLen = 0;
|
||
|
theErr = theAttrInfoPtr->GetValuePtr(qtssAttrName,0, (void **) &modulePrefInServer[i], &nameLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
//qtss_printf("QTSSPrefs::RereadPreferences modulePrefInServer in server=%s\n",modulePrefInServer[i]);
|
||
|
}
|
||
|
|
||
|
// Use the names of the attributes in the attribute map as the key values for
|
||
|
// finding preferences in the config file.
|
||
|
|
||
|
for (UInt32 x = 0; x < theNumPrefs; x++)
|
||
|
{
|
||
|
char* thePrefTypeStr = NULL;
|
||
|
char* thePrefName = NULL;
|
||
|
(void)fPrefsSource->GetPrefValueByIndex(container, x, 0, &thePrefName, &thePrefTypeStr);
|
||
|
|
||
|
// What type is this data type?
|
||
|
QTSS_AttrDataType thePrefType = QTSSDataConverter::TypeStringToType(thePrefTypeStr);
|
||
|
|
||
|
//
|
||
|
// Check to see if there is an attribute with this name already in the
|
||
|
// instance map. If one matches, then we don't need to add this attribute.
|
||
|
QTSSAttrInfoDict* theAttrInfo = NULL;
|
||
|
if (this->GetInstanceDictMap() != NULL)
|
||
|
(void)this->GetInstanceDictMap()->GetAttrInfoByName(thePrefName,
|
||
|
&theAttrInfo,
|
||
|
false ); // false=don't return info on deleted attributes
|
||
|
UInt32 theLen = sizeof(QTSS_AttrDataType);
|
||
|
QTSS_AttributeID theAttrID = qtssIllegalAttrID;
|
||
|
|
||
|
for (UInt32 i = 0; i < initialNumAttrs;i++) // see if this name is in the server
|
||
|
{ if (modulePrefInServer[i] != NULL && thePrefName != NULL && 0 == ::strcmp(modulePrefInServer[i],thePrefName))
|
||
|
{ modulePrefInServer[i] = NULL; // in the server so don't delete later
|
||
|
//qtss_printf("QTSSPrefs::RereadPreferences modulePrefInServer in file and in server=%s\n",thePrefName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( theAttrInfo == NULL )
|
||
|
{
|
||
|
theAttrID = this->AddPrefAttribute(thePrefName, thePrefType); // not present or deleted
|
||
|
this->SetPrefValuesFromFile(container, x, theAttrID, 0); // will add another or replace a deleted attribute
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
QTSS_AttrDataType theAttrType = qtssAttrDataTypeUnknown;
|
||
|
theErr = theAttrInfo->GetValue(qtssAttrDataType, 0, &theAttrType, &theLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
theLen = sizeof(theAttrID);
|
||
|
theErr = theAttrInfo->GetValue(qtssAttrID, 0, &theAttrID, &theLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
if (theAttrType != thePrefType)
|
||
|
{
|
||
|
//
|
||
|
// This is not the same pref as before, because the data types
|
||
|
// are different. Remove the old one from the map, add the new one.
|
||
|
(void)this->RemoveInstanceAttribute(theAttrID);
|
||
|
theAttrID = this->AddPrefAttribute(thePrefName, thePrefType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// This pref already exists
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the values
|
||
|
this->SetPrefValuesFromFile(container, x, theAttrID, 0);
|
||
|
|
||
|
// Mark this pref as found.
|
||
|
SInt32 theIndex = this->GetInstanceDictMap()->ConvertAttrIDToArrayIndex(theAttrID);
|
||
|
Assert(theIndex >= 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove all attributes that no longer apply
|
||
|
if (this->GetInstanceDictMap() != NULL && initialNumAttrs > 0)
|
||
|
{
|
||
|
for (UInt32 a = 0; a < initialNumAttrs; a++)
|
||
|
{
|
||
|
if (NULL != modulePrefInServer[a]) // found a pref in the server that wasn't in the file
|
||
|
{
|
||
|
QTSSAttrInfoDict* theAttrInfoPtr = NULL;
|
||
|
theErr = this->GetInstanceDictMap()->GetAttrInfoByName(modulePrefInServer[a], &theAttrInfoPtr);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
if (theErr != QTSS_NoErr) continue;
|
||
|
|
||
|
QTSS_AttributeID theAttrID = qtssIllegalAttrID;
|
||
|
UInt32 theLen = sizeof(theAttrID);
|
||
|
theErr = theAttrInfoPtr->GetValue(qtssAttrID, 0, &theAttrID, &theLen);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
if (theErr != QTSS_NoErr) continue;
|
||
|
|
||
|
if (0)
|
||
|
{ char* theName = NULL;
|
||
|
UInt32 nameLen = 0;
|
||
|
theAttrInfoPtr->GetValuePtr(qtssAttrName,0, (void **) &theName, &nameLen);
|
||
|
qtss_printf("QTSSPrefs::RereadPreferences about to delete modulePrefInServer=%s attr=%s id=%"_U32BITARG_"\n",modulePrefInServer[a], theName,theAttrID);
|
||
|
}
|
||
|
|
||
|
|
||
|
this->GetInstanceDictMap()->RemoveAttribute(theAttrID);
|
||
|
modulePrefInServer[a] = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete modulePrefInServer;
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::SetPrefValuesFromFile(ContainerRef container, UInt32 inPrefIndex, QTSS_AttributeID inAttrID, UInt32 inNumValues)
|
||
|
{
|
||
|
ContainerRef pref = fPrefsSource->GetPrefRefByIndex(container, inPrefIndex);
|
||
|
SetPrefValuesFromFileWithRef(pref, inAttrID, inNumValues);
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::SetPrefValuesFromFileWithRef(ContainerRef pref, QTSS_AttributeID inAttrID, UInt32 inNumValues)
|
||
|
{
|
||
|
//
|
||
|
// We have an attribute ID for this pref, it is in the map and everything.
|
||
|
// Now, let's add all the values that are in the pref file.
|
||
|
if (pref == 0)
|
||
|
return;
|
||
|
|
||
|
UInt32 numPrefValues = inNumValues;
|
||
|
if (inNumValues == 0)
|
||
|
numPrefValues = fPrefsSource->GetNumPrefValues(pref);
|
||
|
|
||
|
char* thePrefName = NULL;
|
||
|
char* thePrefValue = NULL;
|
||
|
char* thePrefTypeStr = NULL;
|
||
|
QTSS_AttrDataType thePrefType = qtssAttrDataTypeUnknown;
|
||
|
|
||
|
// find the type. If this is a QTSSObject, then we need to call a different routine
|
||
|
thePrefValue = fPrefsSource->GetPrefValueByRef( pref, 0, &thePrefName, &thePrefTypeStr);
|
||
|
thePrefType = QTSSDataConverter::TypeStringToType(thePrefTypeStr);
|
||
|
if (thePrefType == qtssAttrDataTypeQTSS_Object)
|
||
|
{
|
||
|
SetObjectValuesFromFile(pref, inAttrID, numPrefValues, thePrefName);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
UInt32 maxPrefValueSize = 0;
|
||
|
QTSS_Error theErr = QTSS_NoErr;
|
||
|
|
||
|
//
|
||
|
// We have to loop through all the values associated with this pref twice:
|
||
|
// first, to figure out the length (in bytes) of the longest value, secondly
|
||
|
// to actually copy these values into the dictionary.
|
||
|
for (UInt32 y = 0; y < numPrefValues; y++)
|
||
|
{
|
||
|
UInt32 tempMaxPrefValueSize = 0;
|
||
|
|
||
|
thePrefValue = fPrefsSource->GetPrefValueByRef( pref, y, &thePrefName, &thePrefTypeStr);
|
||
|
|
||
|
theErr = QTSSDataConverter::StringToValue( thePrefValue, thePrefType,
|
||
|
NULL, &tempMaxPrefValueSize );
|
||
|
Assert(theErr == QTSS_NotEnoughSpace);
|
||
|
|
||
|
if (tempMaxPrefValueSize > maxPrefValueSize)
|
||
|
maxPrefValueSize = tempMaxPrefValueSize;
|
||
|
}
|
||
|
|
||
|
|
||
|
for (UInt32 z = 0; z < numPrefValues; z++)
|
||
|
{
|
||
|
thePrefValue = fPrefsSource->GetPrefValueByRef( pref, z, &thePrefName, &thePrefTypeStr);
|
||
|
this->SetPrefValue(inAttrID, z, thePrefValue, thePrefType, maxPrefValueSize);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure the dictionary knows exactly how many values are associated with
|
||
|
// this pref
|
||
|
this->SetNumValues(inAttrID, numPrefValues);
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::SetObjectValuesFromFile(ContainerRef pref, QTSS_AttributeID inAttrID, UInt32 inNumValues, char* prefName)
|
||
|
{
|
||
|
for (UInt32 z = 0; z < inNumValues; z++)
|
||
|
{
|
||
|
ContainerRef object = fPrefsSource->GetObjectValue( pref, z );
|
||
|
QTSSPrefs* prefObject;
|
||
|
UInt32 len = sizeof(QTSSPrefs*);
|
||
|
QTSS_Error err = this->GetValue(inAttrID, z, &prefObject, &len);
|
||
|
if (err != QTSS_NoErr)
|
||
|
{
|
||
|
UInt32 tempIndex;
|
||
|
err = CreateObjectValue(inAttrID, &tempIndex, (QTSSDictionary**)&prefObject, NULL, QTSSDictionary::kDontObeyReadOnly | QTSSDictionary::kDontCallCompletionRoutine);
|
||
|
Assert(err == QTSS_NoErr);
|
||
|
Assert(tempIndex == z);
|
||
|
if (err != QTSS_NoErr) // this shouldn't happen
|
||
|
return;
|
||
|
StrPtrLen temp(prefName);
|
||
|
prefObject->fPrefName = temp.GetAsCString();
|
||
|
}
|
||
|
prefObject->RereadObjectPreferences(object);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure the dictionary knows exactly how many values are associated with
|
||
|
// this pref
|
||
|
this->SetNumValues(inAttrID, inNumValues);
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::SetPrefValue(QTSS_AttributeID inAttrID, UInt32 inAttrIndex,
|
||
|
char* inPrefValue, QTSS_AttrDataType inPrefType, UInt32 inValueSize)
|
||
|
|
||
|
{
|
||
|
static const UInt32 kMaxPrefValueSize = 1024;
|
||
|
char convertedPrefValue[kMaxPrefValueSize];
|
||
|
::memset(convertedPrefValue, 0, kMaxPrefValueSize);
|
||
|
Assert(inValueSize < kMaxPrefValueSize);
|
||
|
|
||
|
UInt32 convertedBufSize = kMaxPrefValueSize;
|
||
|
QTSS_Error theErr = QTSSDataConverter::StringToValue
|
||
|
(inPrefValue, inPrefType, convertedPrefValue, &convertedBufSize );
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
if (inValueSize == 0)
|
||
|
inValueSize = convertedBufSize;
|
||
|
|
||
|
this->SetValue(inAttrID, inAttrIndex, convertedPrefValue, inValueSize, QTSSDictionary::kDontObeyReadOnly | QTSSDictionary::kDontCallCompletionRoutine);
|
||
|
|
||
|
}
|
||
|
|
||
|
QTSS_AttributeID QTSSPrefs::AddPrefAttribute(const char* inAttrName, QTSS_AttrDataType inDataType)
|
||
|
{
|
||
|
QTSS_Error theErr = this->AddInstanceAttribute( inAttrName, NULL, inDataType, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModeDelete);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
QTSS_AttributeID theID = qtssIllegalAttrID;
|
||
|
theErr = this->GetInstanceDictMap()->GetAttrID( inAttrName, &theID);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
|
||
|
return theID;
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::RemoveValueComplete(UInt32 inAttrIndex, QTSSDictionaryMap* inMap,
|
||
|
UInt32 inValueIndex)
|
||
|
{
|
||
|
ContainerRef objectRef = GetContainerRef();
|
||
|
ContainerRef pref = fPrefsSource->GetPrefRefByName( objectRef, inMap->GetAttrName(inAttrIndex));
|
||
|
Assert(pref != NULL);
|
||
|
if (pref != NULL)
|
||
|
fPrefsSource->RemovePrefValue( pref, inValueIndex);
|
||
|
|
||
|
if (fPrefsSource->WritePrefsFile())
|
||
|
QTSSModuleUtils::LogError(qtssWarningVerbosity, qtssMsgCantWriteFile, 0);
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::RemoveInstanceAttrComplete(UInt32 inAttrIndex, QTSSDictionaryMap* inMap)
|
||
|
{
|
||
|
ContainerRef objectRef = GetContainerRef();
|
||
|
ContainerRef pref = fPrefsSource->GetPrefRefByName( objectRef, inMap->GetAttrName(inAttrIndex));
|
||
|
Assert(pref != NULL);
|
||
|
if (pref != NULL)
|
||
|
{
|
||
|
fPrefsSource->RemovePref(pref);
|
||
|
}
|
||
|
|
||
|
if (fPrefsSource->WritePrefsFile())
|
||
|
QTSSModuleUtils::LogError(qtssWarningVerbosity, qtssMsgCantWriteFile, 0);
|
||
|
}
|
||
|
|
||
|
void QTSSPrefs::SetValueComplete(UInt32 inAttrIndex, QTSSDictionaryMap* inMap,
|
||
|
UInt32 inValueIndex, void* inNewValue, UInt32 inNewValueLen)
|
||
|
{
|
||
|
ContainerRef objectRef = GetContainerRef();
|
||
|
ContainerRef pref = fPrefsSource->AddPref(objectRef, inMap->GetAttrName(inAttrIndex), QTSSDataConverter::TypeToTypeString(inMap->GetAttrType(inAttrIndex)));
|
||
|
if (inMap->GetAttrType(inAttrIndex) == qtssAttrDataTypeQTSS_Object)
|
||
|
{
|
||
|
QTSSPrefs* object = *(QTSSPrefs**)inNewValue; // value is a pointer to a QTSSPrefs object
|
||
|
StrPtrLen temp(inMap->GetAttrName(inAttrIndex));
|
||
|
object->fPrefName = temp.GetAsCString();
|
||
|
if (inValueIndex == fPrefsSource->GetNumPrefValues(pref))
|
||
|
fPrefsSource->AddNewObject(pref);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OSCharArrayDeleter theValueAsString(QTSSDataConverter::ValueToString(inNewValue, inNewValueLen, inMap->GetAttrType(inAttrIndex)));
|
||
|
fPrefsSource->SetPrefValue(pref, inValueIndex, theValueAsString.GetObject());
|
||
|
}
|
||
|
|
||
|
if (fPrefsSource->WritePrefsFile())
|
||
|
QTSSModuleUtils::LogError(qtssWarningVerbosity, qtssMsgCantWriteFile, 0);
|
||
|
}
|
||
|
|
||
|
ContainerRef QTSSPrefs::GetContainerRefForObject(QTSSPrefs* object)
|
||
|
{
|
||
|
ContainerRef thisContainer = GetContainerRef();
|
||
|
ContainerRef pref = fPrefsSource->GetPrefRefByName(thisContainer, object->fPrefName);
|
||
|
if (pref == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
if (fPrefsSource->GetNumPrefValues(pref) <= 1)
|
||
|
return fPrefsSource->GetObjectValue(pref, 0);
|
||
|
|
||
|
QTSSAttrInfoDict* theAttrInfoPtr = NULL;
|
||
|
QTSS_Error theErr = this->GetInstanceDictMap()->GetAttrInfoByName(object->fPrefName, &theAttrInfoPtr);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
if (theErr != QTSS_NoErr) return NULL;
|
||
|
QTSS_AttributeID theAttrID = qtssIllegalAttrID;
|
||
|
UInt32 len = sizeof(theAttrID);
|
||
|
theErr = theAttrInfoPtr->GetValue(qtssAttrID, 0, &theAttrID, &len);
|
||
|
Assert(theErr == QTSS_NoErr);
|
||
|
if (theErr != QTSS_NoErr) return NULL;
|
||
|
|
||
|
UInt32 index = 0;
|
||
|
QTSSPrefs* prefObject;
|
||
|
len = sizeof(prefObject);
|
||
|
while (this->GetValue(theAttrID, index, &prefObject, &len) == QTSS_NoErr)
|
||
|
{
|
||
|
if (prefObject == object)
|
||
|
{
|
||
|
return fPrefsSource->GetObjectValue(pref, index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ContainerRef QTSSPrefs::GetContainerRef()
|
||
|
{
|
||
|
if (fParentDictionary == NULL) // this is a top level Pref, so it must be a module
|
||
|
return fPrefsSource->GetRefForModule(fPrefName);
|
||
|
else
|
||
|
return fParentDictionary->GetContainerRefForObject(this);
|
||
|
}
|