ovr_sdk
diff LibOVR/Src/OVR_Profile.cpp @ 0:1b39a1b46319
initial 0.4.4
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 14 Jan 2015 06:51:16 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/OVR_Profile.cpp Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,1627 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +PublicHeader: None 1.7 +Filename : OVR_Profile.cpp 1.8 +Content : Structs and functions for loading and storing device profile settings 1.9 +Created : February 14, 2013 1.10 +Notes : 1.11 + 1.12 + Profiles are used to store per-user settings that can be transferred and used 1.13 + across multiple applications. For example, player IPD can be configured once 1.14 + and reused for a unified experience across games. Configuration and saving of profiles 1.15 + can be accomplished in game via the Profile API or by the official Oculus Configuration 1.16 + Utility. 1.17 + 1.18 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.19 + 1.20 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.21 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.22 +which is provided at the time of installation or download, or which 1.23 +otherwise accompanies this software in either electronic or hard copy form. 1.24 + 1.25 +You may obtain a copy of the License at 1.26 + 1.27 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.28 + 1.29 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.30 +distributed under the License is distributed on an "AS IS" BASIS, 1.31 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.32 +See the License for the specific language governing permissions and 1.33 +limitations under the License. 1.34 + 1.35 +************************************************************************************/ 1.36 + 1.37 +#include "OVR_Profile.h" 1.38 +#include "OVR_JSON.h" 1.39 +#include "Kernel/OVR_SysFile.h" 1.40 +#include "Kernel/OVR_Allocator.h" 1.41 +#include "OVR_Stereo.h" 1.42 + 1.43 +#ifdef OVR_OS_WIN32 1.44 +#define WIN32_LEAN_AND_MEAN 1.45 +#include <Windows.h> 1.46 +#include <Shlobj.h> 1.47 +#elif defined(OVR_OS_MS) // Other Microsoft OSs 1.48 +// Nothing, thanks. 1.49 +#else 1.50 +#include <dirent.h> 1.51 +#include <sys/stat.h> 1.52 + 1.53 +#ifdef OVR_OS_LINUX 1.54 +#include <unistd.h> 1.55 +#include <pwd.h> 1.56 +#endif 1.57 + 1.58 +#endif 1.59 + 1.60 +#define PROFILE_VERSION 2.0 1.61 +#define MAX_PROFILE_MAJOR_VERSION 2 1.62 +#define MAX_DEVICE_PROFILE_MAJOR_VERSION 1 1.63 + 1.64 + 1.65 +namespace OVR { 1.66 + 1.67 + 1.68 +//----------------------------------------------------------------------------- 1.69 +// ProfileDeviceKey 1.70 + 1.71 +ProfileDeviceKey::ProfileDeviceKey(const HMDInfo* info) : 1.72 + Valid(false) 1.73 +{ 1.74 + if (info) 1.75 + { 1.76 + PrintedSerial = info->PrintedSerial; 1.77 + ProductName = SanitizeProductName(info->ProductName); 1.78 + ProductId = info->ProductId; 1.79 + HmdType = info->HmdType; 1.80 + 1.81 + if (ProductId != 0) 1.82 + { 1.83 + Valid = true; 1.84 + } 1.85 + } 1.86 + else 1.87 + { 1.88 + ProductId = 0; 1.89 + HmdType = HmdType_None; 1.90 + } 1.91 +} 1.92 + 1.93 +String ProfileDeviceKey::SanitizeProductName(String productName) 1.94 +{ 1.95 + String result; 1.96 + 1.97 + if (!productName.IsEmpty()) 1.98 + { 1.99 + const char* product_name = productName.ToCStr(); 1.100 + 1.101 + // First strip off "Oculus" 1.102 + const char* oculus = strstr(product_name, "Oculus "); 1.103 + if (oculus) 1.104 + { 1.105 + product_name = oculus + OVR_strlen("Oculus "); 1.106 + } 1.107 + 1.108 + // And remove spaces from the name 1.109 + for (const char* s = product_name; *s != 0; s++) 1.110 + { 1.111 + if (*s != ' ') 1.112 + { 1.113 + result.AppendChar(*s); 1.114 + } 1.115 + } 1.116 + } 1.117 + 1.118 + return result; 1.119 +} 1.120 + 1.121 + 1.122 + 1.123 +//----------------------------------------------------------------------------- 1.124 +// Returns the pathname of the JSON file containing the stored profiles 1.125 +String GetBaseOVRPath(bool create_dir) 1.126 +{ 1.127 + String path; 1.128 + 1.129 +#if defined(OVR_OS_WIN32) 1.130 + 1.131 + TCHAR data_path[MAX_PATH]; 1.132 + SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, NULL, 0, data_path); 1.133 + path = String(data_path); 1.134 + 1.135 + path += "/Oculus"; 1.136 + 1.137 + if (create_dir) 1.138 + { // Create the Oculus directory if it doesn't exist 1.139 + WCHAR wpath[128]; 1.140 + OVR::UTF8Util::DecodeString(wpath, path.ToCStr()); 1.141 + 1.142 + DWORD attrib = GetFileAttributes(wpath); 1.143 + bool exists = attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY); 1.144 + if (!exists) 1.145 + { 1.146 + CreateDirectory(wpath, NULL); 1.147 + } 1.148 + } 1.149 + 1.150 +#elif defined(OVR_OS_OS) // Other Microsoft OSs 1.151 + 1.152 + // TODO: figure this out. 1.153 + OVR_UNUSED ( create_dir ); 1.154 + path = ""; 1.155 + 1.156 +#elif defined(OVR_OS_MAC) 1.157 + 1.158 + const char* home = getenv("HOME"); 1.159 + path = home; 1.160 + path += "/Library/Preferences/Oculus"; 1.161 + 1.162 + if (create_dir) 1.163 + { // Create the Oculus directory if it doesn't exist 1.164 + DIR* dir = opendir(path); 1.165 + if (dir == NULL) 1.166 + { 1.167 + mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO); 1.168 + } 1.169 + else 1.170 + { 1.171 + closedir(dir); 1.172 + } 1.173 + } 1.174 + 1.175 +#else 1.176 + 1.177 + const char* home = getenv("HOME"); 1.178 + path = home; 1.179 + path += "/.config/Oculus"; 1.180 + 1.181 + if (create_dir) 1.182 + { // Create the Oculus directory if it doesn't exist 1.183 + DIR* dir = opendir(path); 1.184 + if (dir == NULL) 1.185 + { 1.186 + mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO); 1.187 + } 1.188 + else 1.189 + { 1.190 + closedir(dir); 1.191 + } 1.192 + } 1.193 + 1.194 +#endif 1.195 + 1.196 + return path; 1.197 +} 1.198 + 1.199 +String ProfileManager::GetProfilePath() 1.200 +{ 1.201 + return BasePath + "/ProfileDB.json"; 1.202 +} 1.203 + 1.204 +static JSON* FindTaggedData(JSON* data, const char** tag_names, const char** qtags, int num_qtags) 1.205 +{ 1.206 + if (data == NULL || !(data->Name == "TaggedData") || data->Type != JSON_Array) 1.207 + return NULL; 1.208 + 1.209 + JSON* tagged_item = data->GetFirstItem(); 1.210 + while (tagged_item) 1.211 + { 1.212 + JSON* tags = tagged_item->GetItemByName("tags"); 1.213 + if (tags->Type == JSON_Array && num_qtags == tags->GetArraySize()) 1.214 + { // Check for a full tag match on each item 1.215 + int num_matches = 0; 1.216 + 1.217 + for (int k=0; k<num_qtags; k++) 1.218 + { 1.219 + JSON* tag = tags->GetFirstItem(); 1.220 + while (tag) 1.221 + { 1.222 + JSON* tagval = tag->GetFirstItem(); 1.223 + if (tagval && tagval->Name == tag_names[k]) 1.224 + { 1.225 + if (tagval->Value == qtags[k]) 1.226 + num_matches++; 1.227 + break; 1.228 + } 1.229 + tag = tags->GetNextItem(tag); 1.230 + } 1.231 + } 1.232 + 1.233 + // if all tags were matched then copy the values into this Profile 1.234 + if (num_matches == num_qtags) 1.235 + { 1.236 + JSON* vals = tagged_item->GetItemByName("vals"); 1.237 + return vals; 1.238 + } 1.239 + } 1.240 + 1.241 + tagged_item = data->GetNextItem(tagged_item); 1.242 + } 1.243 + 1.244 + return NULL; 1.245 +} 1.246 + 1.247 +static void FilterTaggedData(JSON* data, const char* tag_name, const char* qtag, Array<JSON*>& items) 1.248 +{ 1.249 + if (data == NULL || !(data->Name == "TaggedData") || data->Type != JSON_Array) 1.250 + return; 1.251 + 1.252 + JSON* tagged_item = data->GetFirstItem(); 1.253 + while (tagged_item) 1.254 + { 1.255 + JSON* tags = tagged_item->GetItemByName("tags"); 1.256 + if (tags->Type == JSON_Array) 1.257 + { // Check for a tag match on the requested tag 1.258 + 1.259 + JSON* tag = tags->GetFirstItem(); 1.260 + while (tag) 1.261 + { 1.262 + JSON* tagval = tag->GetFirstItem(); 1.263 + if (tagval && tagval->Name == tag_name) 1.264 + { 1.265 + if (tagval->Value == qtag) 1.266 + { // Add this item to the output list 1.267 + items.PushBack(tagged_item); 1.268 + } 1.269 + break; 1.270 + } 1.271 + tag = tags->GetNextItem(tag); 1.272 + } 1.273 + } 1.274 + 1.275 + tagged_item = data->GetNextItem(tagged_item); 1.276 + } 1.277 +} 1.278 + 1.279 + 1.280 +//----------------------------------------------------------------------------- 1.281 +// ***** ProfileManager 1.282 + 1.283 +template<> ProfileManager* OVR::SystemSingletonBase<ProfileManager>::SlowGetInstance() 1.284 +{ 1.285 + static OVR::Lock lock; 1.286 + OVR::Lock::Locker locker(&lock); 1.287 + if (!SingletonInstance) SingletonInstance = new ProfileManager(true); 1.288 + return SingletonInstance; 1.289 +} 1.290 + 1.291 +ProfileManager::ProfileManager(bool sys_register) : 1.292 + Changed(false) 1.293 +{ 1.294 + // Attempt to get the base path automatically, but this may fail 1.295 + BasePath = GetBaseOVRPath(false); 1.296 + 1.297 + if (sys_register) 1.298 + PushDestroyCallbacks(); 1.299 +} 1.300 + 1.301 +ProfileManager::~ProfileManager() 1.302 +{ 1.303 + ClearProfileData(); 1.304 +} 1.305 + 1.306 +void ProfileManager::OnSystemDestroy() 1.307 +{ 1.308 + delete this; 1.309 +} 1.310 + 1.311 +// In the service process it is important to set the base path because this cannot be detected automatically 1.312 +void ProfileManager::SetBasePath(String basePath) 1.313 +{ 1.314 + if (basePath != BasePath) 1.315 + { 1.316 + BasePath = basePath; 1.317 + LoadCache(false); 1.318 + } 1.319 +} 1.320 + 1.321 +// Clear the local profile cache 1.322 +void ProfileManager::ClearProfileData() 1.323 +{ 1.324 + Lock::Locker lockScope(&ProfileLock); 1.325 + 1.326 + ProfileCache.Clear(); 1.327 + Changed = false; 1.328 +} 1.329 + 1.330 +// Serializes the profiles to disk. 1.331 +void ProfileManager::Save() 1.332 +{ 1.333 + Lock::Locker lockScope(&ProfileLock); 1.334 + 1.335 + if (ProfileCache == NULL) 1.336 + return; 1.337 + 1.338 + // Save the profile to disk 1.339 + BasePath = GetBaseOVRPath(true); // create the base directory if it doesn't exist 1.340 + String path = GetProfilePath(); 1.341 + ProfileCache->Save(path); 1.342 + Changed = false; 1.343 +} 1.344 + 1.345 +// Returns a profile with all system default values 1.346 +Profile* ProfileManager::GetDefaultProfile(HmdTypeEnum device) 1.347 +{ 1.348 + // In the absence of any data, set some reasonable profile defaults. 1.349 + // However, this is not future proof and developers should still 1.350 + // provide reasonable default values for queried fields. 1.351 + 1.352 + // Biometric data 1.353 + Profile* profile = CreateProfile(); 1.354 + profile->SetValue(OVR_KEY_USER, "default"); 1.355 + profile->SetValue(OVR_KEY_NAME, "Default"); 1.356 + profile->SetValue(OVR_KEY_GENDER, OVR_DEFAULT_GENDER); 1.357 + profile->SetFloatValue(OVR_KEY_PLAYER_HEIGHT, OVR_DEFAULT_PLAYER_HEIGHT); 1.358 + profile->SetFloatValue(OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT); 1.359 + profile->SetFloatValue(OVR_KEY_IPD, OVR_DEFAULT_IPD); 1.360 + float half_ipd[2] = { OVR_DEFAULT_IPD / 2, OVR_DEFAULT_IPD / 2 }; 1.361 + profile->SetFloatValues(OVR_KEY_EYE_TO_NOSE_DISTANCE, half_ipd, 2); 1.362 + float dist[2] = {OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL, OVR_DEFAULT_NECK_TO_EYE_VERTICAL}; 1.363 + profile->SetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, dist, 2); 1.364 + 1.365 + // Device specific data 1.366 + if (device != HmdType_None) 1.367 + { 1.368 + if (device == HmdType_CrystalCoveProto || device == HmdType_DK2) 1.369 + { 1.370 + profile->SetValue("EyeCup", "A"); 1.371 + profile->SetIntValue(OVR_KEY_EYE_RELIEF_DIAL, OVR_DEFAULT_EYE_RELIEF_DIAL); 1.372 + 1.373 + // TODO: These defaults are a little bogus and designed for continuity with 0.3 1.374 + // eye-relief values. We need better measurement-based numbers in future releases 1.375 + float max_eye_plate[2] = { 0.01965f + 0.018f, 0.01965f + 0.018f }; 1.376 + profile->SetFloatValues(OVR_KEY_MAX_EYE_TO_PLATE_DISTANCE, max_eye_plate, 2); 1.377 + } 1.378 + else 1.379 + { // DK1 and DKHD variants 1.380 + profile->SetValue("EyeCup", "A"); 1.381 + profile->SetIntValue(OVR_KEY_EYE_RELIEF_DIAL, OVR_DEFAULT_EYE_RELIEF_DIAL); 1.382 + 1.383 + // TODO: These defaults are a little bogus and designed for continuity with 0.3 1.384 + // DK1 distortion. We need better measurement-based numbers in future releases 1.385 + float max_eye_plate[2] = { 0.02357f + 0.017f, 0.02357f + 0.017f }; 1.386 + profile->SetFloatValues(OVR_KEY_MAX_EYE_TO_PLATE_DISTANCE, max_eye_plate, 2); 1.387 + } 1.388 + } 1.389 + 1.390 + return profile; 1.391 +} 1.392 + 1.393 +//------------------------------------------------------------------------------ 1.394 +void ProfileManager::Read() 1.395 +{ 1.396 + LoadCache(false); 1.397 +} 1.398 + 1.399 +// Populates the local profile cache. This occurs on the first access of the profile 1.400 +// data. All profile operations are performed against the local cache until the 1.401 +// ProfileManager is released or goes out of scope at which time the cache is serialized 1.402 +// to disk. 1.403 +void ProfileManager::LoadCache(bool create) 1.404 +{ 1.405 + Lock::Locker lockScope(&ProfileLock); 1.406 + 1.407 + ClearProfileData(); 1.408 + 1.409 + String path = GetProfilePath(); 1.410 + 1.411 + Ptr<JSON> root = *JSON::Load(path); 1.412 + if (root == NULL) 1.413 + { 1.414 + path = BasePath + "/Profiles.json"; // look for legacy profile 1.415 + root = *JSON::Load(path); 1.416 + 1.417 + if (root == NULL) 1.418 + { 1.419 + if (create) 1.420 + { // Generate a skeleton profile database 1.421 + root = *JSON::CreateObject(); 1.422 + root->AddNumberItem("Oculus Profile Version", 2.0); 1.423 + root->AddItem("Users", JSON::CreateArray()); 1.424 + root->AddItem("TaggedData", JSON::CreateArray()); 1.425 + ProfileCache = root; 1.426 + } 1.427 + 1.428 + return; 1.429 + } 1.430 + 1.431 + // Verify the legacy version 1.432 + JSON* version_item = root->GetFirstItem(); 1.433 + if (version_item->Name == "Oculus Profile Version") 1.434 + { 1.435 + int major = atoi(version_item->Value.ToCStr()); 1.436 + if (major != 1) 1.437 + return; // don't use the file on unsupported major version number 1.438 + } 1.439 + else 1.440 + { 1.441 + return; // invalid file 1.442 + } 1.443 + 1.444 + // Convert the legacy format to the new database format 1.445 + LoadV1Profiles(root); 1.446 + } 1.447 + else 1.448 + { 1.449 + // Verify the file format and version 1.450 + JSON* version_item = root->GetFirstItem(); 1.451 + if (version_item && version_item->Name == "Oculus Profile Version") 1.452 + { 1.453 + int major = atoi(version_item->Value.ToCStr()); 1.454 + if (major != 2) 1.455 + return; // don't use the file on unsupported major version number 1.456 + } 1.457 + else 1.458 + { 1.459 + return; // invalid file 1.460 + } 1.461 + 1.462 + ProfileCache = root; // store the database contents for traversal 1.463 + } 1.464 +} 1.465 + 1.466 +void ProfileManager::LoadV1Profiles(JSON* v1) 1.467 +{ 1.468 + JSON* item0 = v1->GetFirstItem(); 1.469 + JSON* item1 = v1->GetNextItem(item0); 1.470 + JSON* item2 = v1->GetNextItem(item1); 1.471 + 1.472 + OVR_ASSERT(item1 && item2); 1.473 + if(!item1 || !item2) 1.474 + return; 1.475 + 1.476 + // Create the new profile database 1.477 + Ptr<JSON> root = *JSON::CreateObject(); 1.478 + root->AddNumberItem("Oculus Profile Version", 2.0); 1.479 + root->AddItem("Users", JSON::CreateArray()); 1.480 + root->AddItem("TaggedData", JSON::CreateArray()); 1.481 + ProfileCache = root; 1.482 + 1.483 + const char* default_dk1_user = item1->Value; 1.484 + 1.485 + // Read the number of profiles 1.486 + int profileCount = (int)item2->dValue; 1.487 + JSON* profileItem = item2; 1.488 + 1.489 + for (int p=0; p<profileCount; p++) 1.490 + { 1.491 + profileItem = root->GetNextItem(profileItem); 1.492 + if (profileItem == NULL) 1.493 + break; 1.494 + 1.495 + if (profileItem->Name == "Profile") 1.496 + { 1.497 + // Read the required Name field 1.498 + const char* profileName; 1.499 + JSON* item = profileItem->GetFirstItem(); 1.500 + 1.501 + if (item && (item->Name == "Name")) 1.502 + { 1.503 + profileName = item->Value; 1.504 + } 1.505 + else 1.506 + { 1.507 + return; // invalid field 1.508 + } 1.509 + 1.510 + // Read the user profile fields 1.511 + if (CreateUser(profileName, profileName)) 1.512 + { 1.513 + const char* tag_names[2] = {"User", "Product"}; 1.514 + const char* tags[2]; 1.515 + tags[0] = profileName; 1.516 + 1.517 + Ptr<Profile> user_profile = *CreateProfile(); 1.518 + user_profile->SetValue(OVR_KEY_NAME, profileName); 1.519 + 1.520 + float neckeye[2] = { 0, 0 }; 1.521 + 1.522 + item = profileItem->GetNextItem(item); 1.523 + while (item) 1.524 + { 1.525 + if (item->Type != JSON_Object) 1.526 + { 1.527 + if (item->Name == OVR_KEY_PLAYER_HEIGHT) 1.528 + { // Add an explicit eye height 1.529 + 1.530 + } 1.531 + if (item->Name == "NeckEyeHori") 1.532 + neckeye[0] = (float)item->dValue; 1.533 + else if (item->Name == "NeckEyeVert") 1.534 + neckeye[1] = (float)item->dValue; 1.535 + else 1.536 + user_profile->SetValue(item); 1.537 + } 1.538 + else 1.539 + { 1.540 + // Add the user/device tag values 1.541 + const char* device_name = item->Name.ToCStr(); 1.542 + Ptr<Profile> device_profile = *CreateProfile(); 1.543 + 1.544 + JSON* device_item = item->GetFirstItem(); 1.545 + while (device_item) 1.546 + { 1.547 + device_profile->SetValue(device_item); 1.548 + device_item = item->GetNextItem(device_item); 1.549 + } 1.550 + 1.551 + tags[1] = device_name; 1.552 + SetTaggedProfile(tag_names, tags, 2, device_profile); 1.553 + } 1.554 + 1.555 + item = profileItem->GetNextItem(item); 1.556 + } 1.557 + 1.558 + // Add an explicit eye-height field 1.559 + float player_height = user_profile->GetFloatValue(OVR_KEY_PLAYER_HEIGHT, 1.560 + OVR_DEFAULT_PLAYER_HEIGHT); 1.561 + if (player_height > 0) 1.562 + { 1.563 + char gender[16]; 1.564 + user_profile->GetValue(OVR_KEY_GENDER, gender, 16); 1.565 + 1.566 + const float EYE_TO_HEADTOP_RATIO = 0.44538f; 1.567 + const float MALE_AVG_HEAD_HEIGHT = 0.232f; 1.568 + const float FEMALE_AVG_HEAD_HEIGHT = 0.218f; 1.569 + 1.570 + // compute distance from top of skull to the eye 1.571 + float head_height; 1.572 + if (OVR_strcmp(gender, "Female") == 0) 1.573 + head_height = FEMALE_AVG_HEAD_HEIGHT; 1.574 + else 1.575 + head_height = MALE_AVG_HEAD_HEIGHT; 1.576 + 1.577 + float skull = EYE_TO_HEADTOP_RATIO * head_height; 1.578 + float eye_height = player_height - skull; 1.579 + 1.580 + user_profile->SetFloatValue(OVR_KEY_EYE_HEIGHT, eye_height); 1.581 + } 1.582 + 1.583 + // Convert NeckEye values to an array 1.584 + if (neckeye[0] > 0 && neckeye[1] > 0) 1.585 + user_profile->SetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, neckeye, 2); 1.586 + 1.587 + // Add the user tag values 1.588 + SetTaggedProfile(tag_names, tags, 1, user_profile); 1.589 + } 1.590 + } 1.591 + } 1.592 + 1.593 + // since V1 profiles were only for DK1, the assign the user to all DK1's 1.594 + const char* tag_names[1] = { "Product" }; 1.595 + const char* tags[1] = { "RiftDK1" }; 1.596 + Ptr<Profile> product_profile = *CreateProfile(); 1.597 + product_profile->SetValue("DefaultUser", default_dk1_user); 1.598 + SetTaggedProfile(tag_names, tags, 1, product_profile); 1.599 +} 1.600 + 1.601 +// Returns the number of stored profiles for this device type 1.602 +int ProfileManager::GetUserCount() 1.603 +{ 1.604 + Lock::Locker lockScope(&ProfileLock); 1.605 + 1.606 + if (ProfileCache == NULL) 1.607 + { // Load the cache 1.608 + LoadCache(false); 1.609 + if (ProfileCache == NULL) 1.610 + return 0; 1.611 + } 1.612 + 1.613 + JSON* users = ProfileCache->GetItemByName("Users"); 1.614 + if (users == NULL) 1.615 + return 0; 1.616 + 1.617 + return users->GetItemCount(); 1.618 +} 1.619 + 1.620 +bool ProfileManager::CreateUser(const char* user, const char* name) 1.621 +{ 1.622 + Lock::Locker lockScope(&ProfileLock); 1.623 + 1.624 + if (ProfileCache == NULL) 1.625 + { // Load the cache 1.626 + LoadCache(true); 1.627 + if (ProfileCache == NULL) 1.628 + return false; 1.629 + } 1.630 + 1.631 + JSON* users = ProfileCache->GetItemByName("Users"); 1.632 + if (users == NULL) 1.633 + { // Generate the User section 1.634 + users = JSON::CreateArray(); 1.635 + ProfileCache->AddItem("Users", users); 1.636 +//TODO: Insert this before the TaggedData 1.637 + } 1.638 + 1.639 + // Search for the pre-existence of this user 1.640 + JSON* user_item = users->GetFirstItem(); 1.641 + int index = 0; 1.642 + while (user_item) 1.643 + { 1.644 + JSON* userid = user_item->GetItemByName("User"); 1.645 + int compare = OVR_strcmp(user, userid->Value); 1.646 + if (compare == 0) 1.647 + { // The user already exists so simply update the fields 1.648 + JSON* name_item = user_item->GetItemByName("Name"); 1.649 + if (name_item && OVR_strcmp(name, name_item->Value) != 0) 1.650 + { 1.651 + name_item->Value = name; 1.652 + Changed = true; 1.653 + } 1.654 + return true; 1.655 + } 1.656 + else if (compare < 0) 1.657 + { // A new user should be placed before this item 1.658 + break; 1.659 + } 1.660 + 1.661 + user_item = users->GetNextItem(user_item); 1.662 + index++; 1.663 + } 1.664 + 1.665 + // Create and fill the user struct 1.666 + JSON* new_user = JSON::CreateObject(); 1.667 + new_user->AddStringItem(OVR_KEY_USER, user); 1.668 + new_user->AddStringItem(OVR_KEY_NAME, name); 1.669 + // user_item->AddStringItem("Password", password); 1.670 + 1.671 + if (user_item == NULL) 1.672 + users->AddArrayElement(new_user); 1.673 + else 1.674 + users->InsertArrayElement(index, new_user); 1.675 + 1.676 + Changed = true; 1.677 + return true; 1.678 +} 1.679 + 1.680 +bool ProfileManager::HasUser(const char* user) 1.681 +{ 1.682 + Lock::Locker lockScope(&ProfileLock); 1.683 + 1.684 + if (ProfileCache == NULL) 1.685 + { // Load the cache 1.686 + LoadCache(false); 1.687 + if (ProfileCache == NULL) 1.688 + return false; 1.689 + } 1.690 + 1.691 + JSON* users = ProfileCache->GetItemByName("Users"); 1.692 + if (users == NULL) 1.693 + return false; 1.694 + 1.695 + // Remove this user from the User table 1.696 + JSON* user_item = users->GetFirstItem(); 1.697 + while (user_item) 1.698 + { 1.699 + JSON* userid = user_item->GetItemByName("User"); 1.700 + if (OVR_strcmp(user, userid->Value) == 0) 1.701 + { 1.702 + return true; 1.703 + } 1.704 + 1.705 + user_item = users->GetNextItem(user_item); 1.706 + } 1.707 + 1.708 + return false; 1.709 +} 1.710 + 1.711 +// Returns the user id of a specific user in the list. The returned 1.712 +// memory is locally allocated and should not be stored or deleted. Returns NULL 1.713 +// if the index is invalid 1.714 +const char* ProfileManager::GetUser(unsigned int index) 1.715 +{ 1.716 + Lock::Locker lockScope(&ProfileLock); 1.717 + 1.718 + if (ProfileCache == NULL) 1.719 + { // Load the cache 1.720 + LoadCache(false); 1.721 + if (ProfileCache == NULL) 1.722 + return NULL; 1.723 + } 1.724 + 1.725 + JSON* users = ProfileCache->GetItemByName("Users"); 1.726 + 1.727 + if (users && index < users->GetItemCount()) 1.728 + { 1.729 + JSON* user_item = users->GetItemByIndex(index); 1.730 + if (user_item) 1.731 + { 1.732 + JSON* user = user_item->GetFirstItem(); 1.733 + if (user) 1.734 + { 1.735 + JSON* userid = user_item->GetItemByName(OVR_KEY_USER); 1.736 + if (userid) 1.737 + return userid->Value.ToCStr(); 1.738 + } 1.739 + } 1.740 + } 1.741 + 1.742 + 1.743 + return NULL; 1.744 +} 1.745 + 1.746 +bool ProfileManager::RemoveUser(const char* user) 1.747 +{ 1.748 + Lock::Locker lockScope(&ProfileLock); 1.749 + 1.750 + if (ProfileCache == NULL) 1.751 + { // Load the cache 1.752 + LoadCache(false); 1.753 + if (ProfileCache == NULL) 1.754 + return true; 1.755 + } 1.756 + 1.757 + JSON* users = ProfileCache->GetItemByName("Users"); 1.758 + if (users == NULL) 1.759 + return true; 1.760 + 1.761 + // Remove this user from the User table 1.762 + JSON* user_item = users->GetFirstItem(); 1.763 + while (user_item) 1.764 + { 1.765 + JSON* userid = user_item->GetItemByName("User"); 1.766 + if (OVR_strcmp(user, userid->Value) == 0) 1.767 + { // Delete the user entry 1.768 + user_item->RemoveNode(); 1.769 + user_item->Release(); 1.770 + Changed = true; 1.771 + break; 1.772 + } 1.773 + 1.774 + user_item = users->GetNextItem(user_item); 1.775 + } 1.776 + 1.777 + // Now remove all data entries with this user tag 1.778 + JSON* tagged_data = ProfileCache->GetItemByName("TaggedData"); 1.779 + Array<JSON*> user_items; 1.780 + FilterTaggedData(tagged_data, "User", user, user_items); 1.781 + for (unsigned int i=0; i<user_items.GetSize(); i++) 1.782 + { 1.783 + user_items[i]->RemoveNode(); 1.784 + user_items[i]->Release(); 1.785 + Changed = true; 1.786 + } 1.787 + 1.788 + return Changed; 1.789 +} 1.790 + 1.791 +Profile* ProfileManager::CreateProfile() 1.792 +{ 1.793 + Profile* profile = new Profile(BasePath); 1.794 + return profile; 1.795 +} 1.796 + 1.797 +const char* ProfileManager::GetDefaultUser(const ProfileDeviceKey& deviceKey) 1.798 +{ 1.799 + const char* product_str = deviceKey.ProductName.IsEmpty() ? NULL : deviceKey.ProductName.ToCStr(); 1.800 + const char* serial_str = deviceKey.PrintedSerial.IsEmpty() ? NULL : deviceKey.PrintedSerial.ToCStr(); 1.801 + 1.802 + return GetDefaultUser(product_str, serial_str); 1.803 +} 1.804 + 1.805 +// Returns the name of the profile that is marked as the current default user. 1.806 +const char* ProfileManager::GetDefaultUser(const char* product, const char* serial) 1.807 +{ 1.808 + const char* tag_names[2] = {"Product", "Serial"}; 1.809 + const char* tags[2]; 1.810 + 1.811 + if (product && serial) 1.812 + { 1.813 + tags[0] = product; 1.814 + tags[1] = serial; 1.815 + // Look for a default user on this specific device 1.816 + Ptr<Profile> p = *GetTaggedProfile(tag_names, tags, 2); 1.817 + if (p == NULL) 1.818 + { // Look for a default user on this product 1.819 + p = *GetTaggedProfile(tag_names, tags, 1); 1.820 + } 1.821 + 1.822 + if (p) 1.823 + { 1.824 + const char* user = p->GetValue("DefaultUser"); 1.825 + if (user != NULL && user[0] != 0) 1.826 + { 1.827 + TempBuff = user; 1.828 + return TempBuff.ToCStr(); 1.829 + } 1.830 + } 1.831 + } 1.832 + 1.833 + return NULL; 1.834 +} 1.835 + 1.836 +//----------------------------------------------------------------------------- 1.837 +bool ProfileManager::SetDefaultUser(const ProfileDeviceKey& deviceKey, const char* user) 1.838 +{ 1.839 + const char* tag_names[2] = {"Product", "Serial"}; 1.840 + const char* tags[2]; 1.841 + 1.842 + const char* product_str = deviceKey.ProductName.IsEmpty() ? NULL : deviceKey.ProductName.ToCStr(); 1.843 + const char* serial_str = deviceKey.PrintedSerial.IsEmpty() ? NULL : deviceKey.PrintedSerial.ToCStr(); 1.844 + 1.845 + if (product_str && serial_str) 1.846 + { 1.847 + tags[0] = product_str; 1.848 + tags[1] = serial_str; 1.849 + 1.850 + Ptr<Profile> p = *CreateProfile(); 1.851 + p->SetValue("DefaultUser", user); 1.852 + return SetTaggedProfile(tag_names, tags, 2, p); 1.853 + } 1.854 + 1.855 + return false; 1.856 +} 1.857 + 1.858 +//----------------------------------------------------------------------------- 1.859 +Profile* ProfileManager::GetTaggedProfile(const char** tag_names, const char** tags, int num_tags) 1.860 +{ 1.861 + Lock::Locker lockScope(&ProfileLock); 1.862 + 1.863 + if (ProfileCache == NULL) 1.864 + { // Load the cache 1.865 + LoadCache(false); 1.866 + if (ProfileCache == NULL) 1.867 + return NULL; 1.868 + } 1.869 + 1.870 + JSON* tagged_data = ProfileCache->GetItemByName("TaggedData"); 1.871 + OVR_ASSERT(tagged_data); 1.872 + if (tagged_data == NULL) 1.873 + return NULL; 1.874 + 1.875 + Profile* profile = new Profile(BasePath); 1.876 + 1.877 + JSON* vals = FindTaggedData(tagged_data, tag_names, tags, num_tags); 1.878 + if (vals) 1.879 + { 1.880 + JSON* item = vals->GetFirstItem(); 1.881 + while (item) 1.882 + { 1.883 + //printf("Add %s, %s\n", item->Name.ToCStr(), item->Value.ToCStr()); 1.884 + //profile->Settings.Set(item->Name, item->Value); 1.885 + profile->SetValue(item); 1.886 + item = vals->GetNextItem(item); 1.887 + } 1.888 + 1.889 + return profile; 1.890 + } 1.891 + else 1.892 + { 1.893 + profile->Release(); 1.894 + return NULL; 1.895 + } 1.896 +} 1.897 + 1.898 +//----------------------------------------------------------------------------- 1.899 +bool ProfileManager::SetTaggedProfile(const char** tag_names, const char** tags, int num_tags, Profile* profile) 1.900 +{ 1.901 + Lock::Locker lockScope(&ProfileLock); 1.902 + 1.903 + if (ProfileCache == NULL) 1.904 + { // Load the cache 1.905 + LoadCache(true); 1.906 + if (ProfileCache == NULL) 1.907 + return false; // TODO: Generate a new profile DB 1.908 + } 1.909 + 1.910 + JSON* tagged_data = ProfileCache->GetItemByName("TaggedData"); 1.911 + OVR_ASSERT(tagged_data); 1.912 + if (tagged_data == NULL) 1.913 + return false; 1.914 + 1.915 + // Get the cached tagged data section 1.916 + JSON* vals = FindTaggedData(tagged_data, tag_names, tags, num_tags); 1.917 + if (vals == NULL) 1.918 + { 1.919 + JSON* tagged_item = JSON::CreateObject(); 1.920 + JSON* taglist = JSON::CreateArray(); 1.921 + for (int i=0; i<num_tags; i++) 1.922 + { 1.923 + JSON* k = JSON::CreateObject(); 1.924 + k->AddStringItem(tag_names[i], tags[i]); 1.925 + taglist->AddArrayElement(k); 1.926 + } 1.927 + 1.928 + vals = JSON::CreateObject(); 1.929 + 1.930 + tagged_item->AddItem("tags", taglist); 1.931 + tagged_item->AddItem("vals", vals); 1.932 + tagged_data->AddArrayElement(tagged_item); 1.933 + } 1.934 + 1.935 + // Now add or update each profile setting in cache 1.936 + for (unsigned int i=0; i<profile->Values.GetSize(); i++) 1.937 + { 1.938 + JSON* value = profile->Values[i]; 1.939 + 1.940 + bool found = false; 1.941 + JSON* item = vals->GetFirstItem(); 1.942 + while (item) 1.943 + { 1.944 + if (value->Name == item->Name) 1.945 + { 1.946 + // Don't allow a pre-existing type to be overridden 1.947 + OVR_ASSERT(value->Type == item->Type); 1.948 + 1.949 + if (value->Type == item->Type) 1.950 + { // Check for the same value 1.951 + if (value->Type == JSON_Array) 1.952 + { // Update each array item 1.953 + if (item->GetArraySize() == value->GetArraySize()) 1.954 + { // Update each value (assumed to be basic types and not array of objects) 1.955 + JSON* value_element = value->GetFirstItem(); 1.956 + JSON* item_element = item->GetFirstItem(); 1.957 + while (item_element && value_element) 1.958 + { 1.959 + if (value_element->Type == JSON_String) 1.960 + { 1.961 + if (item_element->Value != value_element->Value) 1.962 + { // Overwrite the changed value and mark for file update 1.963 + item_element->Value = value_element->Value; 1.964 + Changed = true; 1.965 + } 1.966 + } 1.967 + else { 1.968 + if (item_element->dValue != value_element->dValue) 1.969 + { // Overwrite the changed value and mark for file update 1.970 + item_element->dValue = value_element->dValue; 1.971 + Changed = true; 1.972 + } 1.973 + } 1.974 + 1.975 + value_element = value->GetNextItem(value_element); 1.976 + item_element = item->GetNextItem(item_element); 1.977 + } 1.978 + } 1.979 + else 1.980 + { // if the array size changed, simply create a new one 1.981 +// TODO: Create the new array 1.982 + } 1.983 + } 1.984 + else if (value->Type == JSON_String) 1.985 + { 1.986 + if (item->Value != value->Value) 1.987 + { // Overwrite the changed value and mark for file update 1.988 + item->Value = value->Value; 1.989 + Changed = true; 1.990 + } 1.991 + } 1.992 + else { 1.993 + if (item->dValue != value->dValue) 1.994 + { // Overwrite the changed value and mark for file update 1.995 + item->dValue = value->dValue; 1.996 + Changed = true; 1.997 + } 1.998 + } 1.999 + } 1.1000 + else 1.1001 + { 1.1002 + return false; 1.1003 + } 1.1004 + 1.1005 + found = true; 1.1006 + break; 1.1007 + } 1.1008 + 1.1009 + item = vals->GetNextItem(item); 1.1010 + } 1.1011 + 1.1012 + if (!found) 1.1013 + { // Add the new value 1.1014 + Changed = true; 1.1015 + 1.1016 + if (value->Type == JSON_String) 1.1017 + vals->AddStringItem(value->Name, value->Value); 1.1018 + else if (value->Type == JSON_Bool) 1.1019 + vals->AddBoolItem(value->Name, ((int)value->dValue != 0)); 1.1020 + else if (value->Type == JSON_Number) 1.1021 + vals->AddNumberItem(value->Name, value->dValue); 1.1022 + else if (value->Type == JSON_Array) 1.1023 + vals->AddItem(value->Name, value->Copy()); 1.1024 + else 1.1025 + { 1.1026 + OVR_ASSERT(false); 1.1027 + Changed = false; 1.1028 + } 1.1029 + } 1.1030 + } 1.1031 + 1.1032 + return true; 1.1033 +} 1.1034 + 1.1035 +//----------------------------------------------------------------------------- 1.1036 +Profile* ProfileManager::GetDefaultUserProfile(const ProfileDeviceKey& deviceKey) 1.1037 +{ 1.1038 + const char* userName = GetDefaultUser(deviceKey); 1.1039 + 1.1040 + Profile* profile = GetProfile(deviceKey, userName); 1.1041 + 1.1042 + if (!profile) 1.1043 + { 1.1044 + profile = GetDefaultProfile(deviceKey.HmdType); 1.1045 + } 1.1046 + 1.1047 + return profile; 1.1048 +} 1.1049 + 1.1050 +//----------------------------------------------------------------------------- 1.1051 +Profile* ProfileManager::GetProfile(const ProfileDeviceKey& deviceKey, const char* user) 1.1052 +{ 1.1053 + Lock::Locker lockScope(&ProfileLock); 1.1054 + 1.1055 + if (ProfileCache == NULL) 1.1056 + { // Load the cache 1.1057 + LoadCache(false); 1.1058 + if (ProfileCache == NULL) 1.1059 + return NULL; 1.1060 + } 1.1061 + 1.1062 + Profile* profile = new Profile(BasePath); 1.1063 + 1.1064 + if (deviceKey.Valid) 1.1065 + { 1.1066 + if (!profile->LoadDeviceProfile(deviceKey) && (user == NULL)) 1.1067 + { 1.1068 + profile->Release(); 1.1069 + return NULL; 1.1070 + } 1.1071 + } 1.1072 + 1.1073 + if (user) 1.1074 + { 1.1075 + const char* product_str = deviceKey.ProductName.IsEmpty() ? NULL : deviceKey.ProductName.ToCStr(); 1.1076 + const char* serial_str = deviceKey.PrintedSerial.IsEmpty() ? NULL : deviceKey.PrintedSerial.ToCStr(); 1.1077 + 1.1078 + if (!profile->LoadProfile(ProfileCache.GetPtr(), user, product_str, serial_str)) 1.1079 + { 1.1080 + profile->Release(); 1.1081 + return NULL; 1.1082 + } 1.1083 + } 1.1084 + 1.1085 + return profile; 1.1086 +} 1.1087 + 1.1088 + 1.1089 +//----------------------------------------------------------------------------- 1.1090 +// ***** Profile 1.1091 + 1.1092 +Profile::~Profile() 1.1093 +{ 1.1094 + ValMap.Clear(); 1.1095 + for (unsigned int i=0; i<Values.GetSize(); i++) 1.1096 + Values[i]->Release(); 1.1097 + 1.1098 + Values.Clear(); 1.1099 +} 1.1100 + 1.1101 +bool Profile::Close() 1.1102 +{ 1.1103 + // TODO: 1.1104 + return true; 1.1105 +} 1.1106 + 1.1107 +//----------------------------------------------------------------------------- 1.1108 +void Profile::CopyItems(JSON* root, String prefix) 1.1109 +{ 1.1110 + JSON* item = root->GetFirstItem(); 1.1111 + while (item) 1.1112 + { 1.1113 + String item_name; 1.1114 + if (prefix.IsEmpty()) 1.1115 + item_name = item->Name; 1.1116 + else 1.1117 + item_name = prefix + "." + item->Name; 1.1118 + 1.1119 + if (item->Type == JSON_Object) 1.1120 + { // recursively copy the children 1.1121 + 1.1122 + CopyItems(item, item_name); 1.1123 + } 1.1124 + else 1.1125 + { 1.1126 + //Settings.Set(item_name, item->Value); 1.1127 + SetValue(item); 1.1128 + } 1.1129 + 1.1130 + item = root->GetNextItem(item); 1.1131 + } 1.1132 +} 1.1133 + 1.1134 +//----------------------------------------------------------------------------- 1.1135 +bool Profile::LoadDeviceFile(unsigned int productId, const char* printedSerialNumber) 1.1136 +{ 1.1137 + if (printedSerialNumber[0] == 0) 1.1138 + return false; 1.1139 + 1.1140 + String path = BasePath + "/Devices.json"; 1.1141 + 1.1142 + // Load the device profiles 1.1143 + Ptr<JSON> root = *JSON::Load(path); 1.1144 + if (root == NULL) 1.1145 + return false; 1.1146 + 1.1147 + // Quick sanity check of the file type and format before we parse it 1.1148 + JSON* version = root->GetFirstItem(); 1.1149 + if (version && version->Name == "Oculus Device Profile Version") 1.1150 + { 1.1151 + int major = atoi(version->Value.ToCStr()); 1.1152 + if (major > MAX_DEVICE_PROFILE_MAJOR_VERSION) 1.1153 + return false; // don't parse the file on unsupported major version number 1.1154 + } 1.1155 + else 1.1156 + { 1.1157 + return false; 1.1158 + } 1.1159 + 1.1160 + JSON* device = root->GetNextItem(version); 1.1161 + while (device) 1.1162 + { 1.1163 + if (device->Name == "Device") 1.1164 + { 1.1165 + JSON* product_item = device->GetItemByName("ProductID"); 1.1166 + JSON* serial_item = device->GetItemByName("Serial"); 1.1167 + if (product_item && serial_item && 1.1168 + (product_item->dValue == productId) && (serial_item->Value == printedSerialNumber)) 1.1169 + { 1.1170 + // found the entry for this device so recursively copy all the settings to the profile 1.1171 + CopyItems(device, ""); 1.1172 + return true; 1.1173 + } 1.1174 + } 1.1175 + 1.1176 + device = root->GetNextItem(device); 1.1177 + } 1.1178 + 1.1179 + return false; 1.1180 +} 1.1181 + 1.1182 +#if 0 1.1183 +//----------------------------------------------------------------------------- 1.1184 +static int BCDByte(unsigned int byte) 1.1185 +{ 1.1186 + int digit1 = (byte >> 4) & 0x000f; 1.1187 + int digit2 = byte & 0x000f; 1.1188 + int decimal = digit1 * 10 + digit2; 1.1189 + return decimal; 1.1190 +} 1.1191 +#endif 1.1192 + 1.1193 +//----------------------------------------------------------------------------- 1.1194 +bool Profile::LoadDeviceProfile(const ProfileDeviceKey& deviceKey) 1.1195 +{ 1.1196 + bool success = false; 1.1197 + if (!deviceKey.Valid) 1.1198 + return false; 1.1199 + 1.1200 +#if 0 1.1201 + int dev_major = BCDByte((sinfo.Version >> 8) & 0x00ff); 1.1202 + OVR_UNUSED(dev_major); 1.1203 + //int dev_minor = BCDByte(sinfo.Version & 0xff); 1.1204 + 1.1205 + //if (dev_minor > 18) 1.1206 + //{ // If the firmware supports hardware stored profiles then grab the device profile 1.1207 + // from the sensor 1.1208 + // TBD: Implement this 1.1209 + //} 1.1210 + //else 1.1211 + { 1.1212 +#endif 1.1213 + // Grab the model and serial number from the device and use it to access the device 1.1214 + // profile file stored on the local machine 1.1215 + success = LoadDeviceFile(deviceKey.ProductId, deviceKey.PrintedSerial); 1.1216 + //} 1.1217 + 1.1218 + return success; 1.1219 +} 1.1220 + 1.1221 +//----------------------------------------------------------------------------- 1.1222 +bool Profile::LoadUser(JSON* root, 1.1223 + const char* user, 1.1224 + const char* model_name, 1.1225 + const char* device_serial) 1.1226 +{ 1.1227 + if (user == NULL) 1.1228 + return false; 1.1229 + 1.1230 + // For legacy files, convert to old style names 1.1231 + //if (model_name && OVR_strcmp(model_name, "Oculus Rift DK1") == 0) 1.1232 + // model_name = "RiftDK1"; 1.1233 + 1.1234 + bool user_found = false; 1.1235 + JSON* data = root->GetItemByName("TaggedData"); 1.1236 + if (data) 1.1237 + { 1.1238 + const char* tag_names[3]; 1.1239 + const char* tags[3]; 1.1240 + tag_names[0] = "User"; 1.1241 + tags[0] = user; 1.1242 + int num_tags = 1; 1.1243 + 1.1244 + if (model_name) 1.1245 + { 1.1246 + tag_names[num_tags] = "Product"; 1.1247 + tags[num_tags] = model_name; 1.1248 + num_tags++; 1.1249 + } 1.1250 + 1.1251 + if (device_serial) 1.1252 + { 1.1253 + tag_names[num_tags] = "Serial"; 1.1254 + tags[num_tags] = device_serial; 1.1255 + num_tags++; 1.1256 + } 1.1257 + 1.1258 + // Retrieve all tag permutations 1.1259 + for (int combos=1; combos<=num_tags; combos++) 1.1260 + { 1.1261 + for (int i=0; i<(num_tags - combos + 1); i++) 1.1262 + { 1.1263 + JSON* vals = FindTaggedData(data, tag_names+i, tags+i, combos); 1.1264 + if (vals) 1.1265 + { 1.1266 + if (i==0) // This tag-combination contains a user match 1.1267 + user_found = true; 1.1268 + 1.1269 + // Add the values to the Profile. More specialized multi-tag values 1.1270 + // will take precedence over and overwrite generalized ones 1.1271 + // For example: ("Me","RiftDK1").IPD would overwrite ("Me").IPD 1.1272 + JSON* item = vals->GetFirstItem(); 1.1273 + while (item) 1.1274 + { 1.1275 + //printf("Add %s, %s\n", item->Name.ToCStr(), item->Value.ToCStr()); 1.1276 + //Settings.Set(item->Name, item->Value); 1.1277 + SetValue(item); 1.1278 + item = vals->GetNextItem(item); 1.1279 + } 1.1280 + } 1.1281 + } 1.1282 + } 1.1283 + } 1.1284 + 1.1285 + if (user_found) 1.1286 + SetValue(OVR_KEY_USER, user); 1.1287 + 1.1288 + return user_found; 1.1289 +} 1.1290 + 1.1291 + 1.1292 +//----------------------------------------------------------------------------- 1.1293 +bool Profile::LoadProfile(JSON* root, 1.1294 + const char* user, 1.1295 + const char* device_model, 1.1296 + const char* device_serial) 1.1297 +{ 1.1298 + if (!LoadUser(root, user, device_model, device_serial)) 1.1299 + return false; 1.1300 + 1.1301 + return true; 1.1302 +} 1.1303 + 1.1304 + 1.1305 +//----------------------------------------------------------------------------- 1.1306 +char* Profile::GetValue(const char* key, char* val, int val_length) const 1.1307 +{ 1.1308 + JSON* value = NULL; 1.1309 + if (ValMap.Get(key, &value)) 1.1310 + { 1.1311 + OVR_strcpy(val, val_length, value->Value.ToCStr()); 1.1312 + return val; 1.1313 + } 1.1314 + else 1.1315 + { 1.1316 + val[0] = 0; 1.1317 + return NULL; 1.1318 + } 1.1319 +} 1.1320 + 1.1321 +//----------------------------------------------------------------------------- 1.1322 +const char* Profile::GetValue(const char* key) 1.1323 +{ 1.1324 + // Non-reentrant query. The returned buffer can only be used until the next call 1.1325 + // to GetValue() 1.1326 + JSON* value = NULL; 1.1327 + if (ValMap.Get(key, &value)) 1.1328 + { 1.1329 + TempVal = value->Value; 1.1330 + return TempVal.ToCStr(); 1.1331 + } 1.1332 + else 1.1333 + { 1.1334 + return NULL; 1.1335 + } 1.1336 +} 1.1337 + 1.1338 +//----------------------------------------------------------------------------- 1.1339 +int Profile::GetNumValues(const char* key) const 1.1340 +{ 1.1341 + JSON* value = NULL; 1.1342 + if (ValMap.Get(key, &value)) 1.1343 + { 1.1344 + if (value->Type == JSON_Array) 1.1345 + return value->GetArraySize(); 1.1346 + else 1.1347 + return 1; 1.1348 + } 1.1349 + else 1.1350 + return 0; 1.1351 +} 1.1352 + 1.1353 +//----------------------------------------------------------------------------- 1.1354 +bool Profile::GetBoolValue(const char* key, bool default_val) const 1.1355 +{ 1.1356 + JSON* value = NULL; 1.1357 + if (ValMap.Get(key, &value) && value->Type == JSON_Bool) 1.1358 + return (value->dValue != 0); 1.1359 + else 1.1360 + return default_val; 1.1361 +} 1.1362 + 1.1363 +//----------------------------------------------------------------------------- 1.1364 +int Profile::GetIntValue(const char* key, int default_val) const 1.1365 +{ 1.1366 + JSON* value = NULL; 1.1367 + if (ValMap.Get(key, &value) && value->Type == JSON_Number) 1.1368 + return (int)(value->dValue); 1.1369 + else 1.1370 + return default_val; 1.1371 +} 1.1372 + 1.1373 +//----------------------------------------------------------------------------- 1.1374 +float Profile::GetFloatValue(const char* key, float default_val) const 1.1375 +{ 1.1376 + JSON* value = NULL; 1.1377 + if (ValMap.Get(key, &value) && value->Type == JSON_Number) 1.1378 + return (float)(value->dValue); 1.1379 + else 1.1380 + return default_val; 1.1381 +} 1.1382 + 1.1383 +//----------------------------------------------------------------------------- 1.1384 +int Profile::GetFloatValues(const char* key, float* values, int num_vals) const 1.1385 +{ 1.1386 + JSON* value = NULL; 1.1387 + if (ValMap.Get(key, &value) && value->Type == JSON_Array) 1.1388 + { 1.1389 + int val_count = Alg::Min(value->GetArraySize(), num_vals); 1.1390 + JSON* item = value->GetFirstItem(); 1.1391 + int count=0; 1.1392 + while (item && count < val_count) 1.1393 + { 1.1394 + if (item->Type == JSON_Number) 1.1395 + values[count] = (float)item->dValue; 1.1396 + else 1.1397 + break; 1.1398 + 1.1399 + count++; 1.1400 + item = value->GetNextItem(item); 1.1401 + } 1.1402 + 1.1403 + return count; 1.1404 + } 1.1405 + else 1.1406 + { 1.1407 + return 0; 1.1408 + } 1.1409 +} 1.1410 + 1.1411 +//----------------------------------------------------------------------------- 1.1412 +double Profile::GetDoubleValue(const char* key, double default_val) const 1.1413 +{ 1.1414 + JSON* value = NULL; 1.1415 + if (ValMap.Get(key, &value) && value->Type == JSON_Number) 1.1416 + return value->dValue; 1.1417 + else 1.1418 + return default_val; 1.1419 +} 1.1420 + 1.1421 +//----------------------------------------------------------------------------- 1.1422 +int Profile::GetDoubleValues(const char* key, double* values, int num_vals) const 1.1423 +{ 1.1424 + JSON* value = NULL; 1.1425 + if (ValMap.Get(key, &value) && value->Type == JSON_Array) 1.1426 + { 1.1427 + int val_count = Alg::Min(value->GetArraySize(), num_vals); 1.1428 + JSON* item = value->GetFirstItem(); 1.1429 + int count=0; 1.1430 + while (item && count < val_count) 1.1431 + { 1.1432 + if (item->Type == JSON_Number) 1.1433 + values[count] = item->dValue; 1.1434 + else 1.1435 + break; 1.1436 + 1.1437 + count++; 1.1438 + item = value->GetNextItem(item); 1.1439 + } 1.1440 + 1.1441 + return count; 1.1442 + } 1.1443 + return 0; 1.1444 +} 1.1445 + 1.1446 +//----------------------------------------------------------------------------- 1.1447 +void Profile::SetValue(JSON* val) 1.1448 +{ 1.1449 + if (val == NULL) 1.1450 + return; 1.1451 + 1.1452 + if (val->Type == JSON_Number) 1.1453 + SetDoubleValue(val->Name, val->dValue); 1.1454 + else if (val->Type == JSON_Bool) 1.1455 + SetBoolValue(val->Name, (val->dValue != 0)); 1.1456 + else if (val->Type == JSON_String) 1.1457 + SetValue(val->Name, val->Value); 1.1458 + else if (val->Type == JSON_Array) 1.1459 + { 1.1460 + // Create a copy of the array 1.1461 + JSON* value = val->Copy(); 1.1462 + Values.PushBack(value); 1.1463 + ValMap.Set(value->Name, value); 1.1464 + } 1.1465 +} 1.1466 + 1.1467 +//----------------------------------------------------------------------------- 1.1468 +void Profile::SetValue(const char* key, const char* val) 1.1469 +{ 1.1470 + if (key == NULL || val == NULL) 1.1471 + return; 1.1472 + 1.1473 + JSON* value = NULL; 1.1474 + if (ValMap.Get(key, &value)) 1.1475 + { 1.1476 + value->Value = val; 1.1477 + } 1.1478 + else 1.1479 + { 1.1480 + value = JSON::CreateString(val); 1.1481 + value->Name = key; 1.1482 + 1.1483 + Values.PushBack(value); 1.1484 + ValMap.Set(key, value); 1.1485 + } 1.1486 +} 1.1487 + 1.1488 +//----------------------------------------------------------------------------- 1.1489 +void Profile::SetBoolValue(const char* key, bool val) 1.1490 +{ 1.1491 + if (key == NULL) 1.1492 + return; 1.1493 + 1.1494 + JSON* value = NULL; 1.1495 + if (ValMap.Get(key, &value)) 1.1496 + { 1.1497 + value->dValue = val; 1.1498 + } 1.1499 + else 1.1500 + { 1.1501 + value = JSON::CreateBool(val); 1.1502 + value->Name = key; 1.1503 + 1.1504 + Values.PushBack(value); 1.1505 + ValMap.Set(key, value); 1.1506 + } 1.1507 +} 1.1508 + 1.1509 +//----------------------------------------------------------------------------- 1.1510 +void Profile::SetIntValue(const char* key, int val) 1.1511 +{ 1.1512 + SetDoubleValue(key, val); 1.1513 +} 1.1514 + 1.1515 +//----------------------------------------------------------------------------- 1.1516 +void Profile::SetFloatValue(const char* key, float val) 1.1517 +{ 1.1518 + SetDoubleValue(key, val); 1.1519 +} 1.1520 + 1.1521 +//----------------------------------------------------------------------------- 1.1522 +void Profile::SetFloatValues(const char* key, const float* vals, int num_vals) 1.1523 +{ 1.1524 + JSON* value = NULL; 1.1525 + int val_count = 0; 1.1526 + if (ValMap.Get(key, &value)) 1.1527 + { 1.1528 + if (value->Type == JSON_Array) 1.1529 + { 1.1530 + // truncate the existing array if fewer entries provided 1.1531 + int num_existing_vals = value->GetArraySize(); 1.1532 + for (int i=num_vals; i<num_existing_vals; i++) 1.1533 + value->RemoveLast(); 1.1534 + 1.1535 + JSON* item = value->GetFirstItem(); 1.1536 + while (item && val_count < num_vals) 1.1537 + { 1.1538 + if (item->Type == JSON_Number) 1.1539 + item->dValue = vals[val_count]; 1.1540 + 1.1541 + item = value->GetNextItem(item); 1.1542 + val_count++; 1.1543 + } 1.1544 + } 1.1545 + else 1.1546 + { 1.1547 + return; // Maybe we should change the data type? 1.1548 + } 1.1549 + } 1.1550 + else 1.1551 + { 1.1552 + value = JSON::CreateArray(); 1.1553 + value->Name = key; 1.1554 + 1.1555 + Values.PushBack(value); 1.1556 + ValMap.Set(key, value); 1.1557 + } 1.1558 + 1.1559 + for (; val_count < num_vals; val_count++) 1.1560 + value->AddArrayNumber(vals[val_count]); 1.1561 +} 1.1562 + 1.1563 +//----------------------------------------------------------------------------- 1.1564 +void Profile::SetDoubleValue(const char* key, double val) 1.1565 +{ 1.1566 + JSON* value = NULL; 1.1567 + if (ValMap.Get(key, &value)) 1.1568 + { 1.1569 + value->dValue = val; 1.1570 + } 1.1571 + else 1.1572 + { 1.1573 + value = JSON::CreateNumber(val); 1.1574 + value->Name = key; 1.1575 + 1.1576 + Values.PushBack(value); 1.1577 + ValMap.Set(key, value); 1.1578 + } 1.1579 +} 1.1580 + 1.1581 +//----------------------------------------------------------------------------- 1.1582 +void Profile::SetDoubleValues(const char* key, const double* vals, int num_vals) 1.1583 +{ 1.1584 + JSON* value = NULL; 1.1585 + int val_count = 0; 1.1586 + if (ValMap.Get(key, &value)) 1.1587 + { 1.1588 + if (value->Type == JSON_Array) 1.1589 + { 1.1590 + // truncate the existing array if fewer entries provided 1.1591 + int num_existing_vals = value->GetArraySize(); 1.1592 + for (int i=num_vals; i<num_existing_vals; i++) 1.1593 + value->RemoveLast(); 1.1594 + 1.1595 + JSON* item = value->GetFirstItem(); 1.1596 + while (item && val_count < num_vals) 1.1597 + { 1.1598 + if (item->Type == JSON_Number) 1.1599 + item->dValue = vals[val_count]; 1.1600 + 1.1601 + item = value->GetNextItem(item); 1.1602 + val_count++; 1.1603 + } 1.1604 + } 1.1605 + else 1.1606 + { 1.1607 + return; // Maybe we should change the data type? 1.1608 + } 1.1609 + } 1.1610 + else 1.1611 + { 1.1612 + value = JSON::CreateArray(); 1.1613 + value->Name = key; 1.1614 + 1.1615 + Values.PushBack(value); 1.1616 + ValMap.Set(key, value); 1.1617 + } 1.1618 + 1.1619 + for (; val_count < num_vals; val_count++) 1.1620 + value->AddArrayNumber(vals[val_count]); 1.1621 +} 1.1622 + 1.1623 +//------------------------------------------------------------------------------ 1.1624 +bool Profile::IsDefaultProfile() 1.1625 +{ 1.1626 + return 0 == OVR::String::CompareNoCase("Default", GetValue(OVR_KEY_NAME)); 1.1627 +} 1.1628 + 1.1629 + 1.1630 +} // namespace OVR