/* * * @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); }