added setup values to store system and player UUID
[rocksndiamonds.git] / src / libgame / misc.c
index 8dda88bcf6a700392953cf0ae77c71f929647e96..bd93e1ce170af1cc4f74a2a2a37b5869f11e50f6 100644 (file)
@@ -549,6 +549,61 @@ boolean getTokenValueFromString(char *string, char **token, char **value)
 }
 
 
+// ----------------------------------------------------------------------------
+// UUID functions
+// ----------------------------------------------------------------------------
+
+#define UUID_BYTES             16
+#define UUID_CHARS             (UUID_BYTES * 2)
+#define UUID_LENGTH            (UUID_CHARS + 4)
+
+static char *getUUID(void)
+{
+  static char uuid[UUID_LENGTH + 1];
+  int data[UUID_BYTES];
+  int count = 0;
+  int i;
+
+  for (i = 0; i < UUID_BYTES; i++)
+    data[i] = GetSimpleRandom(256);
+
+  data[6] = 0x40 | (data[6] & 0x0f);
+  data[8] = 0x80 | (data[8] & 0x3f);
+
+  for (i = 0; i < UUID_BYTES; i++)
+  {
+    sprintf(&uuid[count], "%02x", data[i]);
+    count += 2;
+
+    if (i == 3 || i == 5 || i == 7 || i == 9)
+      strcat(&uuid[count++], "-");
+  }
+
+  return uuid;
+}
+
+char *GetPlayerUUID(void)
+{
+  return getUUID();
+}
+
+char *GetSystemUUID(void)
+{
+  if (program.system_uuid != NULL)
+    return program.system_uuid;
+
+  return getUUID();
+}
+
+void SetSystemUUID(char *uuid)
+{
+  if (program.system_uuid != NULL)
+    checked_free(program.system_uuid);
+
+  program.system_uuid = getStringCopy(uuid);
+}
+
+
 // ----------------------------------------------------------------------------
 // counter functions
 // ----------------------------------------------------------------------------
@@ -1240,8 +1295,7 @@ void GetOptions(int argc, char *argv[],
                void (*print_usage_function)(void),
                void (*print_version_function)(void))
 {
-  char *ro_base_path = getProgramMainDataPath(argv[0], RO_BASE_PATH);
-  char *rw_base_path = getProgramMainDataPath(argv[0], RW_BASE_PATH);
+  char *base_path = getProgramMainDataPath(argv[0], BASE_PATH);
   char **argvplus = checked_calloc((argc + 1) * sizeof(char **));
   char **options_left = &argvplus[1];
 
@@ -1253,16 +1307,17 @@ void GetOptions(int argc, char *argv[],
   options.server_host = NULL;
   options.server_port = 0;
 
-  options.ro_base_directory = ro_base_path;
-  options.rw_base_directory = rw_base_path;
-  options.level_directory    = getPath2(ro_base_path, LEVELS_DIRECTORY);
-  options.graphics_directory = getPath2(ro_base_path, GRAPHICS_DIRECTORY);
-  options.sounds_directory   = getPath2(ro_base_path, SOUNDS_DIRECTORY);
-  options.music_directory    = getPath2(ro_base_path, MUSIC_DIRECTORY);
-  options.docs_directory     = getPath2(ro_base_path, DOCS_DIRECTORY);
-  options.conf_directory     = getPath2(ro_base_path, CONF_DIRECTORY);
+  options.base_directory = base_path;
+
+  options.level_directory    = getPath2(base_path, LEVELS_DIRECTORY);
+  options.graphics_directory = getPath2(base_path, GRAPHICS_DIRECTORY);
+  options.sounds_directory   = getPath2(base_path, SOUNDS_DIRECTORY);
+  options.music_directory    = getPath2(base_path, MUSIC_DIRECTORY);
+  options.docs_directory     = getPath2(base_path, DOCS_DIRECTORY);
+  options.conf_directory     = getPath2(base_path, CONF_DIRECTORY);
 
   options.execute_command = NULL;
+  options.tape_log_filename = NULL;
   options.special_flags = NULL;
   options.debug_mode = NULL;
 
@@ -1334,19 +1389,17 @@ void GetOptions(int argc, char *argv[],
       if (option_arg == NULL)
        FailWithHelp("option '%s' requires an argument", option_str);
 
-      // this should be extended to separate options for ro and rw data
-      options.ro_base_directory = ro_base_path = getStringCopy(option_arg);
-      options.rw_base_directory = rw_base_path = getStringCopy(option_arg);
+      options.base_directory = base_path = getStringCopy(option_arg);
       if (option_arg == next_option)
        options_left++;
 
       // adjust paths for sub-directories in base directory accordingly
-      options.level_directory    = getPath2(ro_base_path, LEVELS_DIRECTORY);
-      options.graphics_directory = getPath2(ro_base_path, GRAPHICS_DIRECTORY);
-      options.sounds_directory   = getPath2(ro_base_path, SOUNDS_DIRECTORY);
-      options.music_directory    = getPath2(ro_base_path, MUSIC_DIRECTORY);
-      options.docs_directory     = getPath2(ro_base_path, DOCS_DIRECTORY);
-      options.conf_directory     = getPath2(ro_base_path, CONF_DIRECTORY);
+      options.level_directory    = getPath2(base_path, LEVELS_DIRECTORY);
+      options.graphics_directory = getPath2(base_path, GRAPHICS_DIRECTORY);
+      options.sounds_directory   = getPath2(base_path, SOUNDS_DIRECTORY);
+      options.music_directory    = getPath2(base_path, MUSIC_DIRECTORY);
+      options.docs_directory     = getPath2(base_path, DOCS_DIRECTORY);
+      options.conf_directory     = getPath2(base_path, CONF_DIRECTORY);
     }
     else if (strncmp(option, "-levels", option_len) == 0)
     {
@@ -1431,6 +1484,15 @@ void GetOptions(int argc, char *argv[],
       // when doing batch processing, always enable verbose mode (warnings)
       options.verbose = TRUE;
     }
+    else if (strncmp(option, "-tape_logfile", option_len) == 0)
+    {
+      if (option_arg == NULL)
+       FailWithHelp("option '%s' requires an argument", option_str);
+
+      options.tape_log_filename = getStringCopy(option_arg);
+      if (option_arg == next_option)
+       options_left++;
+    }
 #if defined(PLATFORM_MACOSX)
     else if (strPrefix(option, "-psn"))
     {
@@ -1843,6 +1905,49 @@ char *getLatin1FromUTF8(char *utf8)
 }
 
 
+// ----------------------------------------------------------------------------
+// functions for JSON handling
+// ----------------------------------------------------------------------------
+
+char *getEscapedJSON(char *s)
+{
+  int max_json_size = 2 * strlen(s) + 1;
+  char *json = checked_calloc(max_json_size);
+  unsigned char *src = (unsigned char *)s;
+  unsigned char *dst = (unsigned char *)json;
+  char *escaped[256] =
+  {
+    ['\b'] = "\\b",
+    ['\f'] = "\\f",
+    ['\n'] = "\\n",
+    ['\r'] = "\\r",
+    ['\t'] = "\\t",
+    ['\"'] = "\\\"",
+    ['\\'] = "\\\\",
+  };
+
+  while (*src)
+  {
+    if (escaped[*src] != NULL)
+    {
+      char *esc = escaped[*src++];
+
+      while (*esc)
+       *dst++ = *esc++;
+    }
+    else
+    {
+      *dst++ = *src++;
+    }
+  }
+
+  // only use the smallest possible string buffer size
+  json = checked_realloc(json, strlen(json) + 1);
+
+  return json;
+}
+
+
 // ----------------------------------------------------------------------------
 // functions to translate key identifiers between different format
 // ----------------------------------------------------------------------------
@@ -3772,6 +3877,11 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
   char *basename = file_list_entry->filename;
   char *filename = getCustomArtworkFilename(basename, artwork_info->type);
 
+  // mark all images from non-default graphics directory as "redefined"
+  if (artwork_info->type == ARTWORK_TYPE_GRAPHICS &&
+      !strPrefix(filename, options.graphics_directory))
+    file_list_entry->redefined = TRUE;
+
   if (filename == NULL)
   {
     Warn("cannot find artwork file '%s'", basename);