Commit 45ae148aef0cabaab967bbe1565280638252225f

Gabriel Jacobo 2013-12-02T19:34:08

Adds SDL_GameControllerAddMappingsFromFile

diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h
index e55749c..84d58d8 100644
--- a/include/SDL_gamecontroller.h
+++ b/include/SDL_gamecontroller.h
@@ -109,6 +109,14 @@ typedef struct SDL_GameControllerButtonBind
  */
 
 /**
+ *  Load a set of mappings from a file, filtered by the current SDL_GetPlatform()
+ *  A community sourced database of controllers is available at https://raw.github.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt
+ *
+ * \return number of mappings added, -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerAddMappingsFromFile( const char* mapDB );
+
+/**
  *  Add or update an existing mapping configuration
  *
  * \return 1 if mapping is added, 0 if updated, -1 on error
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 26769b8..1563f51 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -33,6 +33,7 @@
 #endif
 #define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
 
+#define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
 
 /* a list of currently opened game controllers */
 static SDL_GameController *SDL_gamecontrollers = NULL;
@@ -657,6 +658,73 @@ void SDL_PrivateGameControllerRefreshMapping( ControllerMapping_t *pControllerMa
  * Add or update an entry into the Mappings Database
  */
 int
+SDL_GameControllerAddMappingsFromFile( const char* mapDB )
+{
+    const char *platform = SDL_GetPlatform();
+    SDL_RWops *rw;
+    int controllers = 0;
+    char *buf, *line, *line_end, *tmp, *comma, line_platform[64];
+    size_t db_size, platform_len;
+    
+    rw = SDL_RWFromFile(mapDB, "rb");
+    if (rw == NULL) {
+        return SDL_SetError("Could not open %s", mapDB);
+    }
+    db_size = SDL_RWsize(rw);
+    
+    buf = (char *) SDL_malloc(db_size + 1);
+    if (buf == NULL) {
+        SDL_RWclose(rw);
+        return SDL_SetError("Could allocate space to not read DB into memory");
+    }
+    
+    if (SDL_RWread(rw, buf, db_size, 1) != 1) {
+        SDL_RWclose(rw);
+        SDL_free(buf);
+        return SDL_SetError("Could not read DB");
+    }
+    SDL_RWclose(rw);
+    
+    buf[db_size] = '\0';
+    line = buf;
+    
+    while (line < buf + db_size) {
+        line_end = SDL_strchr( line, '\n' );
+        if (line_end != NULL) {
+            *line_end = '\0';
+        }
+        else {
+            line_end = buf + db_size;
+        }
+        
+        /* Extract and verify the platform */
+        tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD);
+        if ( tmp != NULL ) {
+            tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD);
+            comma = SDL_strchr(tmp, ',');
+            if (comma != NULL) {
+                platform_len = comma - tmp + 1;
+                if (platform_len + 1 < SDL_arraysize(line_platform)) {
+                    SDL_strlcpy(line_platform, tmp, platform_len);
+                    if(SDL_strncasecmp(line_platform, platform, platform_len) == 0
+                        && SDL_GameControllerAddMapping(line) > 0) {
+                        controllers++;
+                    }
+                }
+            }
+        }
+        
+        line = line_end + 1;
+    }
+
+    SDL_free(buf);
+    return controllers;
+}
+
+/*
+ * Add or update an entry into the Mappings Database
+ */
+int
 SDL_GameControllerAddMapping( const char *mappingString )
 {
     char *pchGUID;