Bike-X  0.8
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
OVR_Profile.cpp
Go to the documentation of this file.
1 /************************************************************************************
2 
3 PublicHeader: None
4 Filename : OVR_Profile.cpp
5 Content : Structs and functions for loading and storing device profile settings
6 Created : February 14, 2013
7 Notes :
8 
9  Profiles are used to store per-user settings that can be transferred and used
10  across multiple applications. For example, player IPD can be configured once
11  and reused for a unified experience across games. Configuration and saving of profiles
12  can be accomplished in game via the Profile API or by the official Oculus Configuration
13  Utility.
14 
15 Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
16 
17 Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
18 you may not use the Oculus VR Rift SDK except in compliance with the License,
19 which is provided at the time of installation or download, or which
20 otherwise accompanies this software in either electronic or hard copy form.
21 
22 You may obtain a copy of the License at
23 
24 http://www.oculusvr.com/licenses/LICENSE-3.1
25 
26 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
27 distributed under the License is distributed on an "AS IS" BASIS,
28 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 See the License for the specific language governing permissions and
30 limitations under the License.
31 
32 ************************************************************************************/
33 
34 #include "OVR_Profile.h"
35 #include "OVR_Device.h"
36 #include "OVR_JSON.h"
37 #include "Kernel/OVR_Types.h"
38 #include "Kernel/OVR_SysFile.h"
39 #include "Kernel/OVR_Allocator.h"
40 #include "Kernel/OVR_Array.h"
41 
42 #ifdef OVR_OS_WIN32
43 #include <Shlobj.h>
44 #else
45 #include <dirent.h>
46 #include <sys/stat.h>
47 
48 #ifdef OVR_OS_LINUX
49 #include <unistd.h>
50 #include <pwd.h>
51 #endif
52 
53 #endif
54 
55 
56 #define PROFILE_VERSION 2.0
57 #define MAX_PROFILE_MAJOR_VERSION 2
58 #define MAX_DEVICE_PROFILE_MAJOR_VERSION 1
59 
60 namespace OVR {
61 
62 //-----------------------------------------------------------------------------
63 // Returns the pathname of the JSON file containing the stored profiles
64 String GetBaseOVRPath(bool create_dir)
65 {
66  String path;
67 
68 #if defined(OVR_OS_WIN32)
69 
70  TCHAR data_path[MAX_PATH];
71  SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, NULL, 0, data_path);
72  path = String(data_path);
73 
74  path += "/Oculus";
75 
76  if (create_dir)
77  { // Create the Oculus directory if it doesn't exist
78  WCHAR wpath[128];
79  OVR::UTF8Util::DecodeString(wpath, path.ToCStr());
80 
81  DWORD attrib = GetFileAttributes(wpath);
82  bool exists = attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY);
83  if (!exists)
84  {
85  CreateDirectory(wpath, NULL);
86  }
87  }
88 
89 #elif defined(OVR_OS_MAC)
90 
91  const char* home = getenv("HOME");
92  path = home;
93  path += "/Library/Preferences/Oculus";
94 
95  if (create_dir)
96  { // Create the Oculus directory if it doesn't exist
97  DIR* dir = opendir(path);
98  if (dir == NULL)
99  {
100  mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
101  }
102  else
103  {
104  closedir(dir);
105  }
106  }
107 
108 #else
109 
110  passwd* pwd = getpwuid(getuid());
111  const char* home = pwd->pw_dir;
112  path = home;
113  path += "/.config/Oculus";
114 
115  if (create_dir)
116  { // Create the Oculus directory if it doesn't exist
117  DIR* dir = opendir(path);
118  if (dir == NULL)
119  {
120  mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
121  }
122  else
123  {
124  closedir(dir);
125  }
126  }
127 
128 #endif
129 
130  return path;
131 }
132 
134 {
135  String path = GetBaseOVRPath(create_dir);
136  path += "/ProfileDB.json";
137  return path;
138 }
139 
140 bool ProfileManager::GetDeviceTags(const DeviceBase* device, String& product, String& serial)
141 {
142  product = "";
143  serial = "";
144 
145  if (device && device->GetType() == Device_HMD)
146  {
147  HMDDevice* hmd = (HMDDevice*)device;
148 
149  Ptr<SensorDevice> sensor = *(hmd->GetSensor());
150  if (sensor)
151  {
152  SensorInfo sinfo;
153  sensor->GetDeviceInfo(&sinfo);
154  serial = sinfo.SerialNumber; // get the serial number
155 
156  // Derive the product tag from the HMD product name
157  HMDInfo hmdinfo;
158  hmd->GetDeviceInfo(&hmdinfo);
159 
160  const char* product_name = NULL;
161 
162  // If the HMD is unrecognized then use the name stamped into the
163  // sensor firmware
164  if (hmdinfo.HmdType == HmdType_None || hmdinfo.HmdType == HmdType_Unknown)
165  product_name = sinfo.ProductName.ToCStr();
166  else
167  product_name = hmdinfo.ProductName.ToCStr();
168 
169  // First strip off "Oculus"
170  const char* oculus = strstr(product_name, "Oculus ");
171  if (oculus)
172  product_name = oculus + OVR_strlen("Oculus ");
173  // And remove spaces from the name
174  for (const char* s=product_name; *s != 0; s++)
175  {
176  if (*s != ' ')
177  product.AppendChar(*s);
178  }
179  }
180  }
181 
182  return (!product.IsEmpty() && !serial.IsEmpty());
183 }
184 
185 static JSON* FindTaggedData(JSON* data, const char** tag_names, const char** qtags, int num_qtags)
186 {
187  if (data == NULL || !(data->Name == "TaggedData") || data->Type != JSON_Array)
188  return NULL;
189 
190  JSON* tagged_item = data->GetFirstItem();
191  while (tagged_item)
192  {
193  JSON* tags = tagged_item->GetItemByName("tags");
194  if (tags->Type == JSON_Array && num_qtags == tags->GetArraySize())
195  { // Check for a full tag match on each item
196  int num_matches = 0;
197 
198  for (int k=0; k<num_qtags; k++)
199  {
200  JSON* tag = tags->GetFirstItem();
201  while (tag)
202  {
203  JSON* tagval = tag->GetFirstItem();
204  if (tagval && tagval->Name == tag_names[k])
205  {
206  if (tagval->Value == qtags[k])
207  num_matches++;
208  break;
209  }
210  tag = tags->GetNextItem(tag);
211  }
212  }
213 
214  // if all tags were matched then copy the values into this Profile
215  if (num_matches == num_qtags)
216  {
217  JSON* vals = tagged_item->GetItemByName("vals");
218  return vals;
219  }
220  }
221 
222  tagged_item = data->GetNextItem(tagged_item);
223  }
224 
225  return NULL;
226 }
227 
228 static void FilterTaggedData(JSON* data, const char* tag_name, const char* qtag, Array<JSON*>& items)
229 {
230  if (data == NULL || !(data->Name == "TaggedData") || data->Type != JSON_Array)
231  return;
232 
233  JSON* tagged_item = data->GetFirstItem();
234  while (tagged_item)
235  {
236  JSON* tags = tagged_item->GetItemByName("tags");
237  if (tags->Type == JSON_Array)
238  { // Check for a tag match on the requested tag
239 
240  JSON* tag = tags->GetFirstItem();
241  while (tag)
242  {
243  JSON* tagval = tag->GetFirstItem();
244  if (tagval && tagval->Name == tag_name)
245  {
246  if (tagval->Value == qtag)
247  { // Add this item to the output list
248  items.PushBack(tagged_item);
249  }
250  break;
251  }
252  tag = tags->GetNextItem(tag);
253  }
254  }
255 
256  tagged_item = data->GetNextItem(tagged_item);
257  }
258 }
259 
260 //-----------------------------------------------------------------------------
261 // ***** ProfileManager
262 
264 {
265  Changed = false;
266 }
267 
269 {
270  ClearCache();
271 }
272 
274 {
275  return new ProfileManager();
276 }
277 
278 // Clear the local profile cache
280 {
281  Lock::Locker lockScope(&ProfileLock);
282  //ProfileCache.Clear();
283  if (ProfileCache)
284  {
285  //ProfileCache->Release();
286  ProfileCache = NULL;
287  }
288  Changed = false;
289 }
290 
291 // Returns a profile with all system default values
293 {
294  // In the absence of any data, set some reasonable profile defaults.
295  // However, this is not future proof and developers should still
296  // provide reasonable default values for queried fields.
297  Profile* profile = CreateProfile();
298  profile->SetValue(OVR_KEY_USER, "default");
299  profile->SetValue(OVR_KEY_NAME, "Default");
302  profile->SetFloatValue(OVR_KEY_EYE_HEIGHT, 1.675f);
305  profile->SetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, dist, 2);
306  //profile->SetFloatValue(OVR_KEY_NECK_TO_EYE_VERTICAL, 0.12f);
307 
308  // TODO: Provide device specific defaults
309  OVR_UNUSED(device);
310 
311  // DK1 default
312  //profile->SetValue("EyeCup", "A");
313 
314  return profile;
315 }
316 
317 // Poplulates the local profile cache. This occurs on the first access of the profile
318 // data. All profile operations are performed against the local cache until the
319 // ProfileManager is released or goes out of scope at which time the cache is serialized
320 // to disk.
321 void ProfileManager::LoadCache(bool create)
322 {
323  Lock::Locker lockScope(&ProfileLock);
324 
325  ClearCache();
326 
327  String path = GetProfilePath(false);
328 
329  Ptr<JSON> root = *JSON::Load(path);
330  if (root == NULL)
331  {
332  path = GetBaseOVRPath(false) + "/Profiles.json"; // look for legacy profile
333  root = *JSON::Load(path);
334 
335  if (root == NULL)
336  {
337  if (create)
338  { // Generate a skeleton profile database
339  root = *JSON::CreateObject();
340  root->AddNumberItem("Oculus Profile Version", 2.0);
341  root->AddItem("Users", JSON::CreateArray());
342  root->AddItem("TaggedData", JSON::CreateArray());
343  ProfileCache = root;
344  }
345 
346  return;
347  }
348 
349  // Verify the legacy version
350  JSON* version_item = root->GetFirstItem();
351  if (version_item->Name == "Oculus Profile Version")
352  {
353  int major = atoi(version_item->Value.ToCStr());
354  if (major != 1)
355  return; // don't use the file on unsupported major version number
356  }
357  else
358  {
359  return; // invalid file
360  }
361 
362  // Convert the legacy format to the new database format
363  LoadV1Profiles(root);
364  }
365  else
366  {
367  // Verify the file format and version
368  JSON* version_item = root->GetFirstItem();
369  if (version_item->Name == "Oculus Profile Version")
370  {
371  int major = atoi(version_item->Value.ToCStr());
372  if (major != 2)
373  return; // don't use the file on unsupported major version number
374  }
375  else
376  {
377  return; // invalid file
378  }
379 
380  ProfileCache = root; // store the database contents for traversal
381  }
382 }
383 
385 {
386  JSON* item0 = v1->GetFirstItem();
387  JSON* item1 = v1->GetNextItem(item0);
388  JSON* item2 = v1->GetNextItem(item1);
389 
390  // Create the new profile database
391  Ptr<JSON> root = *JSON::CreateObject();
392  root->AddNumberItem("Oculus Profile Version", 2.0);
393  root->AddItem("Users", JSON::CreateArray());
394  root->AddItem("TaggedData", JSON::CreateArray());
395  ProfileCache = root;
396 
397  const char* default_dk1_user = item1->Value;
398 
399  // Read the number of profiles
400  int profileCount = (int)item2->dValue;
401  JSON* profileItem = item2;
402 
403  for (int p=0; p<profileCount; p++)
404  {
405  profileItem = root->GetNextItem(profileItem);
406  if (profileItem == NULL)
407  break;
408 
409  if (profileItem->Name == "Profile")
410  {
411  // Read the required Name field
412  const char* profileName;
413  JSON* item = profileItem->GetFirstItem();
414 
415  if (item && (item->Name == "Name"))
416  {
417  profileName = item->Value;
418  }
419  else
420  {
421  return; // invalid field
422  }
423 
424  // Read the user profile fields
425  if (CreateUser(profileName, profileName))
426  {
427  const char* tag_names[2] = {"User", "Product"};
428  const char* tags[2];
429  tags[0] = profileName;
430 
431  Ptr<Profile> user_profile = *CreateProfile();
432  user_profile->SetValue(OVR_KEY_NAME, profileName);
433 
434  float neckeye[2] = { 0, 0 };
435 
436  item = profileItem->GetNextItem(item);
437  while (item)
438  {
439  if (item->Type != JSON_Object)
440  {
441  if (item->Name == OVR_KEY_PLAYER_HEIGHT)
442  { // Add an explicit eye height
443 
444  }
445  if (item->Name == "NeckEyeHori")
446  neckeye[0] = (float)item->dValue;
447  else if (item->Name == "NeckEyeVert")
448  neckeye[1] = (float)item->dValue;
449  else
450  user_profile->SetValue(item);
451  }
452  else
453  {
454  // Add the user/device tag values
455  const char* device_name = item->Name.ToCStr();
456  Ptr<Profile> device_profile = *CreateProfile();
457 
458  JSON* device_item = item->GetFirstItem();
459  while (device_item)
460  {
461  device_profile->SetValue(device_item);
462  device_item = item->GetNextItem(device_item);
463  }
464 
465  tags[1] = device_name;
466  SetTaggedProfile(tag_names, tags, 2, device_profile);
467  }
468 
469  item = profileItem->GetNextItem(item);
470  }
471 
472  // Add an explicit eye-height field
473  float player_height = user_profile->GetFloatValue(OVR_KEY_PLAYER_HEIGHT,
475  if (player_height > 0)
476  {
477  char gender[16];
478  user_profile->GetValue(OVR_KEY_GENDER, gender, 16);
479 
480  const float EYE_TO_HEADTOP_RATIO = 0.44538f;
481  const float MALE_AVG_HEAD_HEIGHT = 0.232f;
482  const float FEMALE_AVG_HEAD_HEIGHT = 0.218f;
483 
484  // compute distance from top of skull to the eye
485  float head_height;
486  if (OVR_strcmp(gender, "Female") == 0)
487  head_height = FEMALE_AVG_HEAD_HEIGHT;
488  else
489  head_height = MALE_AVG_HEAD_HEIGHT;
490 
491  float skull = EYE_TO_HEADTOP_RATIO * head_height;
492  float eye_height = player_height - skull;
493 
494  user_profile->SetFloatValue(OVR_KEY_EYE_HEIGHT, eye_height);
495  }
496 
497  // Convert NeckEye values to an array
498  if (neckeye[0] > 0 && neckeye[1] > 0)
499  user_profile->SetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, neckeye, 2);
500 
501  // Add the user tag values
502  SetTaggedProfile(tag_names, tags, 1, user_profile);
503  }
504  }
505  }
506 
507  // since V1 profiles were only for DK1, the assign the user to all DK1's
508  const char* tag_names[1] = { "Product" };
509  const char* tags[1] = { "RiftDK1" };
510  Ptr<Profile> product_profile = *CreateProfile();
511  product_profile->SetValue("DefaultUser", default_dk1_user);
512  SetTaggedProfile(tag_names, tags, 1, product_profile);
513 }
514 
515 // Returns the number of stored profiles for this device type
517 {
518  Lock::Locker lockScope(&ProfileLock);
519 
520  if (ProfileCache == NULL)
521  { // Load the cache
522  LoadCache(false);
523  if (ProfileCache == NULL)
524  return 0;
525  }
526 
527  JSON* users = ProfileCache->GetItemByName("Users");
528  if (users == NULL)
529  return 0;
530 
531  return users->GetItemCount();
532 }
533 
534 bool ProfileManager::CreateUser(const char* user, const char* name)
535 {
536  Lock::Locker lockScope(&ProfileLock);
537 
538  if (ProfileCache == NULL)
539  { // Load the cache
540  LoadCache(true);
541  if (ProfileCache == NULL)
542  return false;
543  }
544 
545  JSON* users = ProfileCache->GetItemByName("Users");
546  if (users == NULL)
547  { // Generate the User section
548  users = JSON::CreateArray();
549  ProfileCache->AddItem("Users", users);
550 //TODO: Insert this before the TaggedData
551  }
552 
553  // Search for the pre-existence of this user
554  JSON* user_item = users->GetFirstItem();
555  int index = 0;
556  while (user_item)
557  {
558  JSON* userid = user_item->GetItemByName("User");
559  int compare = OVR_strcmp(user, userid->Value);
560  if (compare == 0)
561  { // The user already exists so simply update the fields
562  JSON* name_item = user_item->GetItemByName("Name");
563  if (name_item && OVR_strcmp(name, name_item->Value) != 0)
564  {
565  name_item->Value = name;
566  Changed = true;
567  }
568  return true;
569  }
570  else if (compare < 0)
571  { // A new user should be placed before this item
572  break;
573  }
574 
575  user_item = users->GetNextItem(user_item);
576  index++;
577  }
578 
579  // Create and fill the user struct
580  JSON* new_user = JSON::CreateObject();
581  new_user->AddStringItem(OVR_KEY_USER, user);
582  new_user->AddStringItem(OVR_KEY_NAME, name);
583  // user_item->AddStringItem("Password", password);
584 
585  if (user_item == NULL)
586  users->AddArrayElement(new_user);
587  else
588  users->InsertArrayElement(index, new_user);
589 
590  Changed = true;
591  return true;
592 }
593 
594 // Returns the user id of a specific user in the list. The returned
595 // memory is locally allocated and should not be stored or deleted. Returns NULL
596 // if the index is invalid
597 const char* ProfileManager::GetUser(unsigned int index)
598 {
599  Lock::Locker lockScope(&ProfileLock);
600 
601  if (ProfileCache == NULL)
602  { // Load the cache
603  LoadCache(false);
604  if (ProfileCache == NULL)
605  return NULL;
606  }
607 
608  JSON* users = ProfileCache->GetItemByName("Users");
609 
610  if (users && index < users->GetItemCount())
611  {
612  JSON* user_item = users->GetItemByIndex(index);
613  if (user_item)
614  {
615  JSON* user = user_item->GetFirstItem();
616  if (user)
617  {
618  JSON* userid = user_item->GetItemByName(OVR_KEY_USER);
619  if (userid)
620  return userid->Value.ToCStr();
621  }
622  }
623  }
624 
625 
626  return NULL;
627 }
628 
629 bool ProfileManager::RemoveUser(const char* user)
630 {
631  Lock::Locker lockScope(&ProfileLock);
632 
633  if (ProfileCache == NULL)
634  { // Load the cache
635  LoadCache(false);
636  if (ProfileCache == NULL)
637  return true;
638  }
639 
640  JSON* users = ProfileCache->GetItemByName("Users");
641  if (users == NULL)
642  return true;
643 
644  // Remove this user from the User table
645  JSON* user_item = users->GetFirstItem();
646  while (user_item)
647  {
648  JSON* userid = user_item->GetItemByName("User");
649  if (OVR_strcmp(user, userid->Value) == 0)
650  { // Delete the user entry
651  user_item->RemoveNode();
652  user_item->Release();
653  Changed = true;
654  break;
655  }
656 
657  user_item = users->GetNextItem(user_item);
658  }
659 
660  // Now remove all data entries with this user tag
661  JSON* tagged_data = ProfileCache->GetItemByName("TaggedData");
662  Array<JSON*> user_items;
663  FilterTaggedData(tagged_data, "User", user, user_items);
664  for (unsigned int i=0; i<user_items.GetSize(); i++)
665  {
666  user_items[i]->RemoveNode();
667  user_items[i]->Release();
668  Changed = true;
669  }
670 
671  return Changed;
672 }
673 
675 {
676  Profile* profile = new Profile();
677  return profile;
678 }
679 
680 // Returns the name of the profile that is marked as the current default user.
681 const char* ProfileManager::GetDefaultUser(const DeviceBase* device)
682 {
683  const char* tag_names[2] = {"Product", "Serial"};
684  const char* tags[2];
685 
686  String product;
687  String serial;
688  if (!GetDeviceTags(device, product, serial))
689  return NULL;
690 
691  const char* product_str = product.IsEmpty() ? NULL : product.ToCStr();
692  const char* serial_str = serial.IsEmpty() ? NULL : serial.ToCStr();
693 
694  if (product_str && serial_str)
695  {
696  tags[0] = product_str;
697  tags[1] = serial_str;
698  // Look for a default user on this specific device
699  Ptr<Profile> p = *GetTaggedProfile(tag_names, tags, 2);
700  if (p == NULL)
701  { // Look for a default user on this product
702  p = *GetTaggedProfile(tag_names, tags, 1);
703  }
704 
705  if (p)
706  {
707  const char* user = p->GetValue("DefaultUser");
708  if (user != NULL && user[0] != 0)
709  {
710  TempBuff = user;
711  return TempBuff.ToCStr();
712  }
713  }
714  }
715 
716  return NULL;
717 }
718 
719 //-----------------------------------------------------------------------------
720 bool ProfileManager::SetDefaultUser(const DeviceBase* device, const char* user)
721 {
722  const char* tag_names[2] = {"Product", "Serial"};
723  const char* tags[2];
724 
725  String product;
726  String serial;
727  if (!GetDeviceTags(device, product, serial))
728  return NULL;
729 
730  const char* product_str = product.IsEmpty() ? NULL : product.ToCStr();
731  const char* serial_str = serial.IsEmpty() ? NULL : serial.ToCStr();
732 
733  if (product_str && serial_str)
734  {
735  tags[0] = product_str;
736  tags[1] = serial_str;
737 
739  p->SetValue("DefaultUser", user);
740  return SetTaggedProfile(tag_names, tags, 2, p);
741  }
742 
743  return false;
744 }
745 
746 //-----------------------------------------------------------------------------
747 Profile* ProfileManager::GetTaggedProfile(const char** tag_names, const char** tags, int num_tags)
748 {
749  Lock::Locker lockScope(&ProfileLock);
750 
751  if (ProfileCache == NULL)
752  { // Load the cache
753  LoadCache(false);
754  if (ProfileCache == NULL)
755  return NULL;
756  }
757 
758  JSON* tagged_data = ProfileCache->GetItemByName("TaggedData");
759  OVR_ASSERT(tagged_data);
760  if (tagged_data == NULL)
761  return NULL;
762 
763  Profile* profile = new Profile();
764 
765  JSON* vals = FindTaggedData(tagged_data, tag_names, tags, num_tags);
766  if (vals)
767  {
768  JSON* item = vals->GetFirstItem();
769  while (item)
770  {
771  //printf("Add %s, %s\n", item->Name.ToCStr(), item->Value.ToCStr());
772  //profile->Settings.Set(item->Name, item->Value);
773  profile->SetValue(item);
774  item = vals->GetNextItem(item);
775  }
776 
777  return profile;
778  }
779  else
780  {
781  profile->Release();
782  return NULL;
783  }
784 }
785 
786 //-----------------------------------------------------------------------------
787 bool ProfileManager::SetTaggedProfile(const char** tag_names, const char** tags, int num_tags, Profile* profile)
788 {
789  Lock::Locker lockScope(&ProfileLock);
790 
791  if (ProfileCache == NULL)
792  { // Load the cache
793  LoadCache(true);
794  if (ProfileCache == NULL)
795  return false; // TODO: Generate a new profile DB
796  }
797 
798  JSON* tagged_data = ProfileCache->GetItemByName("TaggedData");
799  OVR_ASSERT(tagged_data);
800  if (tagged_data == NULL)
801  return false;
802 
803  // Get the cached tagged data section
804  JSON* vals = FindTaggedData(tagged_data, tag_names, tags, num_tags);
805  if (vals == NULL)
806  {
807  JSON* tagged_item = JSON::CreateObject();
808  JSON* taglist = JSON::CreateArray();
809  for (int i=0; i<num_tags; i++)
810  {
811  JSON* k = JSON::CreateObject();
812  k->AddStringItem(tag_names[i], tags[i]);
813  taglist->AddArrayElement(k);
814  }
815 
816  vals = JSON::CreateObject();
817 
818  tagged_item->AddItem("tags", taglist);
819  tagged_item->AddItem("vals", vals);
820  tagged_data->AddArrayElement(tagged_item);
821  }
822 
823  // Now add or update each profile setting in cache
824  for (unsigned int i=0; i<profile->Values.GetSize(); i++)
825  {
826  JSON* value = profile->Values[i];
827 
828  bool found = false;
829  JSON* item = vals->GetFirstItem();
830  while (item)
831  {
832  if (value->Name == item->Name)
833  {
834  // Don't allow a pre-existing type to be overridden
835  OVR_ASSERT(value->Type == item->Type);
836 
837  if (value->Type == item->Type)
838  { // Check for the same value
839  if (value->Type == JSON_Array)
840  { // Update each array item
841  if (item->GetArraySize() == value->GetArraySize())
842  { // Update each value (assumed to be basic types and not array of objects)
843  JSON* value_element = value->GetFirstItem();
844  JSON* item_element = item->GetFirstItem();
845  while (item_element && value_element)
846  {
847  if (value_element->Type == JSON_String)
848  {
849  if (item_element->Value != value_element->Value)
850  { // Overwrite the changed value and mark for file update
851  item_element->Value = value_element->Value;
852  Changed = true;
853  }
854  }
855  else {
856  if (item_element->dValue != value_element->dValue)
857  { // Overwrite the changed value and mark for file update
858  item_element->dValue = value_element->dValue;
859  Changed = true;
860  }
861  }
862 
863  value_element = value->GetNextItem(value_element);
864  item_element = item->GetNextItem(item_element);
865  }
866  }
867  else
868  { // if the array size changed, simply create a new one
869 // TODO: Create the new array
870  }
871  }
872  else if (value->Type == JSON_String)
873  {
874  if (item->Value != value->Value)
875  { // Overwrite the changed value and mark for file update
876  item->Value = value->Value;
877  Changed = true;
878  }
879  }
880  else {
881  if (item->dValue != value->dValue)
882  { // Overwrite the changed value and mark for file update
883  item->dValue = value->dValue;
884  Changed = true;
885  }
886  }
887  }
888  else
889  {
890  return false;
891  }
892 
893  found = true;
894  break;
895  }
896 
897  item = vals->GetNextItem(item);
898  }
899 
900  if (!found)
901  { // Add the new value
902  if (value->Type == JSON_String)
903  vals->AddStringItem(value->Name, value->Value);
904  else if (value->Type == JSON_Bool)
905  vals->AddBoolItem(value->Name, (value->dValue != 0));
906  else if (value->Type == JSON_Array)
907  vals->AddItem(value->Name, value->Copy());
908  else
909  vals->AddNumberItem(value->Name, value->dValue);
910 
911  Changed = true;
912  }
913  }
914 
915  return true;
916 }
917 
918 //-----------------------------------------------------------------------------
919 Profile* ProfileManager::GetProfile(const DeviceBase* device, const char* user)
920 {
921  Lock::Locker lockScope(&ProfileLock);
922 
923  if (ProfileCache == NULL)
924  { // Load the cache
925  LoadCache(false);
926  if (ProfileCache == NULL)
927  return NULL;
928  }
929 
930  Profile* profile = new Profile();
931 
932  if (device)
933  {
934  if (!profile->LoadDeviceProfile(device) && (user == NULL))
935  {
936  profile->Release();
937  return NULL;
938  }
939  }
940 
941  if (user)
942  {
943  String product;
944  String serial;
945  GetDeviceTags(device, product, serial);
946 
947  const char* product_str = product.IsEmpty() ? NULL : product.ToCStr();
948  const char* serial_str = serial.IsEmpty() ? NULL : serial.ToCStr();
949 
950  if (!profile->LoadProfile(ProfileCache.GetPtr(), user, product_str, serial_str))
951  {
952  profile->Release();
953  return NULL;
954  }
955  }
956 
957  return profile;
958 }
959 
960 //-----------------------------------------------------------------------------
961 // ***** Profile
962 
964 {
965  ValMap.Clear();
966  for (unsigned int i=0; i<Values.GetSize(); i++)
967  Values[i]->Release();
968 
969  Values.Clear();
970 }
971 
973 {
974  // TODO:
975  return true;
976 }
977 
978 //-----------------------------------------------------------------------------
979 void Profile::CopyItems(JSON* root, String prefix)
980 {
981  JSON* item = root->GetFirstItem();
982  while (item)
983  {
984  String item_name;
985  if (prefix.IsEmpty())
986  item_name = item->Name;
987  else
988  item_name = prefix + "." + item->Name;
989 
990  if (item->Type == JSON_Object)
991  { // recursively copy the children
992 
993  CopyItems(item, item_name);
994  }
995  else
996  {
997  //Settings.Set(item_name, item->Value);
998  SetValue(item);
999  }
1000 
1001  item = root->GetNextItem(item);
1002  }
1003 }
1004 
1005 //-----------------------------------------------------------------------------
1006 bool Profile::LoadDeviceFile(unsigned int device_id, const char* serial)
1007 {
1008  if (serial[0] == 0)
1009  return false;
1010 
1011  String path = GetBaseOVRPath(false);
1012  path += "/Devices.json";
1013 
1014  // Load the device profiles
1015  Ptr<JSON> root = *JSON::Load(path);
1016  if (root == NULL)
1017  return false;
1018 
1019  // Quick sanity check of the file type and format before we parse it
1020  JSON* version = root->GetFirstItem();
1021  if (version && version->Name == "Oculus Device Profile Version")
1022  {
1023  int major = atoi(version->Value.ToCStr());
1025  return false; // don't parse the file on unsupported major version number
1026  }
1027  else
1028  {
1029  return false;
1030  }
1031 
1032 
1033  JSON* device = root->GetNextItem(version);
1034  while (device)
1035  {
1036  if (device->Name == "Device")
1037  {
1038  JSON* product_item = device->GetItemByName("ProductID");
1039  JSON* serial_item = device->GetItemByName("Serial");
1040  if (product_item && serial_item
1041  && (product_item->dValue == device_id) && (serial_item->Value == serial))
1042  {
1043  // found the entry for this device so recursively copy all the settings to the profile
1044  CopyItems(device, "");
1045  return true;
1046  }
1047  }
1048 
1049  device = root->GetNextItem(device);
1050  }
1051 
1052  return false;
1053 }
1054 
1055 //-----------------------------------------------------------------------------
1056 static int BCDByte(unsigned int byte)
1057 {
1058  int digit1 = (byte >> 4) & 0x000f;
1059  int digit2 = byte & 0x000f;
1060  int decimal = digit1 * 10 + digit2;
1061  return decimal;
1062 }
1063 
1064 //-----------------------------------------------------------------------------
1066 {
1067  bool success = false;
1068  if (device == NULL)
1069  return false;
1070 
1071  SensorDevice* sensor = NULL;
1072 
1073  if (device->GetType() == Device_HMD)
1074  {
1075  // Convert the HMD device to Sensor
1076  sensor = ((HMDDevice*)device)->GetSensor();
1077  device = sensor;
1078  if (device == NULL)
1079  return false;
1080  }
1081 
1082  if (device->GetType() == Device_Sensor)
1083  {
1084  SensorDevice* sensor = (SensorDevice*)device;
1085 
1086  SensorInfo sinfo;
1087  sensor->GetDeviceInfo(&sinfo);
1088 
1089  int dev_major = BCDByte((sinfo.Version >> 8) & 0x00ff);
1090  OVR_UNUSED(dev_major);
1091  int dev_minor = BCDByte(sinfo.Version & 0xff);
1092 
1093  if (dev_minor > 18)
1094  { // If the firmware supports hardware stored profiles then grab the device profile
1095  // from the sensor
1096  // TBD: Implement this
1097  }
1098  else
1099  {
1100  // Grab the model and serial number from the device and use it to access the device
1101  // profile file stored on the local machine
1102  success = LoadDeviceFile(sinfo.ProductId, sinfo.SerialNumber);
1103  }
1104  }
1105 
1106  if (sensor)
1107  sensor->Release(); // release the sensor handle
1108 
1109  return success;
1110 }
1111 
1112 //-----------------------------------------------------------------------------
1114  const char* user,
1115  const char* model_name,
1116  const char* device_serial)
1117 {
1118  if (user == NULL)
1119  return false;
1120 
1121  // For legacy files, convert to old style names
1122  //if (model_name && OVR_strcmp(model_name, "Oculus Rift DK1") == 0)
1123  // model_name = "RiftDK1";
1124 
1125  bool user_found = false;
1126  JSON* data = root->GetItemByName("TaggedData");
1127  if (data)
1128  {
1129  const char* tag_names[3];
1130  const char* tags[3];
1131  tag_names[0] = "User";
1132  tags[0] = user;
1133  int num_tags = 1;
1134 
1135  if (model_name)
1136  {
1137  tag_names[num_tags] = "Product";
1138  tags[num_tags] = model_name;
1139  num_tags++;
1140  }
1141 
1142  if (device_serial)
1143  {
1144  tag_names[num_tags] = "Serial";
1145  tags[num_tags] = device_serial;
1146  num_tags++;
1147  }
1148 
1149  // Retrieve all tag permutations
1150  for (int combos=1; combos<=num_tags; combos++)
1151  {
1152  for (int i=0; i<(num_tags - combos + 1); i++)
1153  {
1154  JSON* vals = FindTaggedData(data, tag_names+i, tags+i, combos);
1155  if (vals)
1156  {
1157  if (i==0) // This tag-combination contains a user match
1158  user_found = true;
1159 
1160  // Add the values to the Profile. More specialized multi-tag values
1161  // will take precedence over and overwrite generalized ones
1162  // For example: ("Me","RiftDK1").IPD would overwrite ("Me").IPD
1163  JSON* item = vals->GetFirstItem();
1164  while (item)
1165  {
1166  //printf("Add %s, %s\n", item->Name.ToCStr(), item->Value.ToCStr());
1167  //Settings.Set(item->Name, item->Value);
1168  SetValue(item);
1169  item = vals->GetNextItem(item);
1170  }
1171  }
1172  }
1173  }
1174  }
1175 
1176  if (user_found)
1177  SetValue(OVR_KEY_USER, user);
1178 
1179  return user_found;
1180 }
1181 
1182 
1183 //-----------------------------------------------------------------------------
1185  const char* user,
1186  const char* device_model,
1187  const char* device_serial)
1188 {
1189  if (!LoadUser(root, user, device_model, device_serial))
1190  return false;
1191 
1192  return true;
1193 }
1194 
1195 
1196 //-----------------------------------------------------------------------------
1197 char* Profile::GetValue(const char* key, char* val, int val_length) const
1198 {
1199  JSON* value = NULL;
1200  if (ValMap.Get(key, &value))
1201  {
1202  OVR_strcpy(val, val_length, value->Value.ToCStr());
1203  return val;
1204  }
1205  else
1206  {
1207  val[0] = 0;
1208  return NULL;
1209  }
1210 }
1211 
1212 //-----------------------------------------------------------------------------
1213 const char* Profile::GetValue(const char* key)
1214 {
1215  // Non-reentrant query. The returned buffer can only be used until the next call
1216  // to GetValue()
1217  JSON* value = NULL;
1218  if (ValMap.Get(key, &value))
1219  {
1220  TempVal = value->Value;
1221  return TempVal.ToCStr();
1222  }
1223  else
1224  {
1225  return NULL;
1226  }
1227 }
1228 
1229 //-----------------------------------------------------------------------------
1230 int Profile::GetNumValues(const char* key) const
1231 {
1232  JSON* value = NULL;
1233  if (ValMap.Get(key, &value))
1234  {
1235  if (value->Type == JSON_Array)
1236  return value->GetArraySize();
1237  else
1238  return 1;
1239  }
1240  else
1241  return 0;
1242 }
1243 
1244 //-----------------------------------------------------------------------------
1245 bool Profile::GetBoolValue(const char* key, bool default_val) const
1246 {
1247  JSON* value = NULL;
1248  if (ValMap.Get(key, &value) && value->Type == JSON_Bool)
1249  return (value->dValue != 0);
1250  else
1251  return default_val;
1252 }
1253 
1254 //-----------------------------------------------------------------------------
1255 int Profile::GetIntValue(const char* key, int default_val) const
1256 {
1257  JSON* value = NULL;
1258  if (ValMap.Get(key, &value) && value->Type == JSON_Number)
1259  return (int)(value->dValue);
1260  else
1261  return default_val;
1262 }
1263 
1264 //-----------------------------------------------------------------------------
1265 float Profile::GetFloatValue(const char* key, float default_val) const
1266 {
1267  JSON* value = NULL;
1268  if (ValMap.Get(key, &value) && value->Type == JSON_Number)
1269  return (float)(value->dValue);
1270  else
1271  return default_val;
1272 }
1273 
1274 //-----------------------------------------------------------------------------
1275 int Profile::GetFloatValues(const char* key, float* values, int num_vals) const
1276 {
1277  JSON* value = NULL;
1278  if (ValMap.Get(key, &value) && value->Type == JSON_Array)
1279  {
1280  int val_count = Alg::Min(value->GetArraySize(), num_vals);
1281  JSON* item = value->GetFirstItem();
1282  int count=0;
1283  while (item && count < val_count)
1284  {
1285  if (item->Type == JSON_Number)
1286  values[count] = (float)item->dValue;
1287  else
1288  break;
1289 
1290  count++;
1291  item = value->GetNextItem(item);
1292  }
1293 
1294  return count;
1295  }
1296  else
1297  {
1298  return 0;
1299  }
1300 }
1301 
1302 //-----------------------------------------------------------------------------
1303 double Profile::GetDoubleValue(const char* key, double default_val) const
1304 {
1305  JSON* value = NULL;
1306  if (ValMap.Get(key, &value) && value->Type == JSON_Number)
1307  return value->dValue;
1308  else
1309  return default_val;
1310 }
1311 
1312 //-----------------------------------------------------------------------------
1313 int Profile::GetDoubleValues(const char* key, double* values, int num_vals) const
1314 {
1315  JSON* value = NULL;
1316  if (ValMap.Get(key, &value) && value->Type == JSON_Array)
1317  {
1318  int val_count = Alg::Min(value->GetArraySize(), num_vals);
1319  JSON* item = value->GetFirstItem();
1320  int count=0;
1321  while (item && count < val_count)
1322  {
1323  if (item->Type == JSON_Number)
1324  values[count] = item->dValue;
1325  else
1326  break;
1327 
1328  count++;
1329  item = value->GetNextItem(item);
1330  }
1331 
1332  return count;
1333  }
1334  else
1335  {
1336  return 0;
1337  }
1338 }
1339 
1340 //-----------------------------------------------------------------------------
1342 {
1343  if (val->Type == JSON_Number)
1344  SetDoubleValue(val->Name, val->dValue);
1345  else if (val->Type == JSON_Bool)
1346  SetBoolValue(val->Name, (val->dValue != 0));
1347  else if (val->Type == JSON_String)
1348  SetValue(val->Name, val->Value);
1349  else if (val->Type == JSON_Array)
1350  {
1351  if (val == NULL)
1352  return;
1353 
1354  // Create a copy of the array
1355  JSON* value = val->Copy();
1356  Values.PushBack(value);
1357  ValMap.Set(value->Name, value);
1358  }
1359 }
1360 
1361 //-----------------------------------------------------------------------------
1362 void Profile::SetValue(const char* key, const char* val)
1363 {
1364  if (key == NULL || val == NULL)
1365  return;
1366 
1367  JSON* value = NULL;
1368  if (ValMap.Get(key, &value))
1369  {
1370  value->Value = val;
1371  }
1372  else
1373  {
1374  value = JSON::CreateString(val);
1375  value->Name = key;
1376 
1377  Values.PushBack(value);
1378  ValMap.Set(key, value);
1379  }
1380 }
1381 
1382 //-----------------------------------------------------------------------------
1383 void Profile::SetBoolValue(const char* key, bool val)
1384 {
1385  if (key == NULL)
1386  return;
1387 
1388  JSON* value = NULL;
1389  if (ValMap.Get(key, &value))
1390  {
1391  value->dValue = val;
1392  }
1393  else
1394  {
1395  value = JSON::CreateBool(val);
1396  value->Name = key;
1397 
1398  Values.PushBack(value);
1399  ValMap.Set(key, value);
1400  }
1401 }
1402 
1403 //-----------------------------------------------------------------------------
1404 void Profile::SetIntValue(const char* key, int val)
1405 {
1406  SetDoubleValue(key, val);
1407 }
1408 
1409 //-----------------------------------------------------------------------------
1410 void Profile::SetFloatValue(const char* key, float val)
1411 {
1412  SetDoubleValue(key, val);
1413 }
1414 
1415 //-----------------------------------------------------------------------------
1416 void Profile::SetFloatValues(const char* key, const float* vals, int num_vals)
1417 {
1418  JSON* value = NULL;
1419  int val_count = 0;
1420  if (ValMap.Get(key, &value))
1421  {
1422  if (value->Type == JSON_Array)
1423  {
1424  // truncate the existing array if fewer entries provided
1425  int num_existing_vals = value->GetArraySize();
1426  for (int i=num_vals; i<num_existing_vals; i++)
1427  value->RemoveLast();
1428 
1429  JSON* item = value->GetFirstItem();
1430  while (item && val_count < num_vals)
1431  {
1432  if (item->Type == JSON_Number)
1433  item->dValue = vals[val_count];
1434 
1435  item = value->GetNextItem(item);
1436  val_count++;
1437  }
1438  }
1439  else
1440  {
1441  return; // Maybe we should change the data type?
1442  }
1443  }
1444  else
1445  {
1446  value = JSON::CreateArray();
1447  value->Name = key;
1448 
1449  Values.PushBack(value);
1450  ValMap.Set(key, value);
1451  }
1452 
1453  for (; val_count < num_vals; val_count++)
1454  value->AddArrayNumber(vals[val_count]);
1455 }
1456 
1457 //-----------------------------------------------------------------------------
1458 void Profile::SetDoubleValue(const char* key, double val)
1459 {
1460  JSON* value = NULL;
1461  if (ValMap.Get(key, &value))
1462  {
1463  value->dValue = val;
1464  }
1465  else
1466  {
1467  value = JSON::CreateNumber(val);
1468  value->Name = key;
1469 
1470  Values.PushBack(value);
1471  ValMap.Set(key, value);
1472  }
1473 }
1474 
1475 //-----------------------------------------------------------------------------
1476 void Profile::SetDoubleValues(const char* key, const double* vals, int num_vals)
1477 {
1478  JSON* value = NULL;
1479  int val_count = 0;
1480  if (ValMap.Get(key, &value))
1481  {
1482  if (value->Type == JSON_Array)
1483  {
1484  // truncate the existing array if fewer entries provided
1485  int num_existing_vals = value->GetArraySize();
1486  for (int i=num_vals; i<num_existing_vals; i++)
1487  value->RemoveLast();
1488 
1489  JSON* item = value->GetFirstItem();
1490  while (item && val_count < num_vals)
1491  {
1492  if (item->Type == JSON_Number)
1493  item->dValue = vals[val_count];
1494 
1495  item = value->GetNextItem(item);
1496  val_count++;
1497  }
1498  }
1499  else
1500  {
1501  return; // Maybe we should change the data type?
1502  }
1503  }
1504  else
1505  {
1506  value = JSON::CreateArray();
1507  value->Name = key;
1508 
1509  Values.PushBack(value);
1510  ValMap.Set(key, value);
1511  }
1512 
1513  for (; val_count < num_vals; val_count++)
1514  value->AddArrayNumber(vals[val_count]);
1515 }
1516 
1517 } // OVR
virtual bool GetDeviceInfo(DeviceInfo *info) const
void SetDoubleValues(const char *key, const double *vals, int num_vals)
void LoadCache(bool create)
void AddArrayNumber(double n)
Definition: OVR_JSON.h:134
bool CreateUser(const char *user, const char *name)
virtual Profile * CreateProfile()
const char * GetValue(const char *key)
float GetFloatValue(const char *key, float default_val) const
bool LoadUser(JSON *root, const char *user, const char *device_name, const char *device_serial)
#define OVR_KEY_IPD
Definition: OVR_CAPI.h:744
int GetArraySize()
Definition: OVR_JSON.cpp:1076
int GetNumValues(const char *key) const
unsigned GetItemCount() const
Definition: OVR_JSON.cpp:864
#define NULL
int GetIntValue(const char *key, int default_val) const
OVR::Hash< String, JSON *, String::HashFunctor > ValMap
Definition: OVR_Profile.h:116
void InsertArrayElement(int index, JSON *item)
Definition: OVR_JSON.cpp:1050
static ProfileManager * Create()
unsigned Version
Definition: OVR_Device.h:156
#define OVR_KEY_NECK_TO_EYE_DISTANCE
Definition: OVR_Profile.h:182
String GetProfilePath(bool create_dir)
UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char *putf8str, SPInt bytesLen)
virtual DeviceType GetType() const
#define OVR_UNUSED(a)
String Name
Definition: OVR_JSON.h:65
void SetBoolValue(const char *key, bool val)
#define OVR_KEY_GENDER
Definition: OVR_CAPI.h:741
OVR::Array< JSON * > Values
Definition: OVR_Profile.h:117
String GetBaseOVRPath(bool create_dir)
Definition: OVR_Profile.cpp:64
void AddBoolItem(const char *name, bool b)
Definition: OVR_JSON.h:122
String Value
Definition: OVR_JSON.h:66
virtual void Release()
#define OVR_KEY_NAME
Definition: OVR_CAPI.h:740
char *OVR_CDECL OVR_strcpy(char *dest, UPInt destsize, const char *src)
Definition: OVR_Std.h:148
#define OVR_DEFAULT_NECK_TO_EYE_VERTICAL
Definition: OVR_CAPI.h:753
const char * GetDefaultUser(const DeviceBase *device)
Profile * GetProfile(const DeviceBase *device, const char *user)
const char * ToCStr() const
Definition: OVR_String.h:186
void RemoveNode()
Definition: OVR_List.h:58
bool LoadDeviceFile(unsigned int device_id, const char *serial)
const char * GetUser(unsigned int index)
Ptr< JSON > ProfileCache
Definition: OVR_Profile.h:73
static JSON * FindTaggedData(JSON *data, const char **tag_names, const char **qtags, int num_qtags)
JSONItemType Type
Definition: OVR_JSON.h:64
static JSON * Load(const char *path, const char **perror=0)
Definition: OVR_JSON.cpp:1132
static void FilterTaggedData(JSON *data, const char *tag_name, const char *qtag, Array< JSON * > &items)
String ProductName
Definition: OVR_Device.h:154
String SerialNumber
Definition: OVR_Device.h:489
#define OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL
Definition: OVR_CAPI.h:752
static JSON * CreateObject()
Definition: OVR_JSON.h:74
JSON * GetFirstItem()
Definition: OVR_JSON.h:100
#define OVR_ASSERT(p)
static int BCDByte(unsigned int byte)
void AddArrayElement(JSON *item)
Definition: OVR_JSON.cpp:1041
void AddItem(const char *string, JSON *item)
Definition: OVR_JSON.cpp:921
OVR::String TempVal
Definition: OVR_Profile.h:118
static JSON * CreateArray()
Definition: OVR_JSON.h:76
void SetValue(const char *key, const char *val)
static JSON * CreateNumber(double num)
Definition: OVR_JSON.h:78
void SetIntValue(const char *key, int val)
int GetFloatValues(const char *key, float *values, int num_vals) const
bool GetBoolValue(const char *key, bool default_val) const
void SetDoubleValue(const char *key, double val)
Profile * GetDefaultProfile(const DeviceBase *device)
void RemoveLast()
Definition: OVR_JSON.cpp:970
bool IsEmpty() const
Definition: OVR_String.h:191
void LoadV1Profiles(JSON *v1)
JSON * GetItemByIndex(unsigned i)
Definition: OVR_JSON.cpp:872
int OVR_CDECL OVR_strcmp(const char *dest, const char *src)
Definition: OVR_Std.h:181
JSON * GetNextItem(JSON *item)
Definition: OVR_JSON.h:115
void SetFloatValues(const char *key, const float *vals, int num_vals)
#define OVR_DEFAULT_PLAYER_HEIGHT
Definition: OVR_CAPI.h:749
HmdTypeEnum HmdType
Definition: OVR_Device.h:323
bool SetTaggedProfile(const char **key_names, const char **keys, int num_keys, Profile *profile)
void CopyItems(JSON *root, String prefix)
void AddNumberItem(const char *name, double n)
Definition: OVR_JSON.h:123
void AddStringItem(const char *name, const char *s)
Definition: OVR_JSON.h:124
bool LoadDeviceProfile(const DeviceBase *device)
#define OVR_DEFAULT_IPD
Definition: OVR_CAPI.h:751
#define OVR_DEFAULT_GENDER
Definition: OVR_CAPI.h:748
static JSON * CreateString(const char *s)
Definition: OVR_JSON.h:79
OVR_FORCE_INLINE const T Min(const T a, const T b)
Definition: OVR_Alg.h:46
#define OVR_KEY_USER
Definition: OVR_CAPI.h:739
int GetDoubleValues(const char *key, double *values, int num_vals) const
const int MAX_DEVICE_PROFILE_MAJOR_VERSION
virtual SensorDevice * GetSensor()=0
int char * index(const char *__s, int __c) __THROW __attribute_pure__ __nonnull((1))
void AppendChar(UInt32 ch)
Definition: OVR_String.cpp:214
#define OVR_KEY_PLAYER_HEIGHT
Definition: OVR_CAPI.h:742
static bool LoadProfile(const DeviceBase *device, const char *user, Profile **profile)
bool RemoveUser(const char *user)
void SetFloatValue(const char *key, float val)
Profile * GetTaggedProfile(const char **key_names, const char **keys, int num_keys)
#define OVR_KEY_EYE_HEIGHT
Definition: OVR_CAPI.h:743
double dValue
Definition: OVR_JSON.h:67
static JSON * CreateBool(bool b)
Definition: OVR_JSON.h:77
UPInt OVR_CDECL OVR_strlen(const char *str)
Definition: OVR_Std.h:143
__END_NAMESPACE_STD __BEGIN_NAMESPACE_STD size_t size_t char char * strstr(const char *__haystack, const char *__needle) __THROW __attribute_pure__ __nonnull((1
bool SetDefaultUser(const DeviceBase *device, const char *user)
JSON * GetItemByName(const char *name)
Definition: OVR_JSON.cpp:897
JSON * Copy()
Definition: OVR_JSON.cpp:1112
bool GetDeviceTags(const DeviceBase *device, String &product, String &serial)
UInt16 ProductId
Definition: OVR_Device.h:485
double GetDoubleValue(const char *key, double default_val) const