src/events/SDL_touch.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 18 Feb 2019 07:50:33 -0800
changeset 12612 07c39cbbeacf
parent 12503 806492103856
child 12676 994f7540d7f3
permissions -rw-r--r--
Fixed bug 4500 - Heap-Buffer Overflow in Map1toN pertaining to SDL_pixels.c

Petr Pisar

The reproducer has these data in BITMAPINFOHEADER:

biSize = 40
biBitCount = 8
biClrUsed = 131075

SDL_LoadBMP_RW() function passes biBitCount as a color depth to SDL_CreateRGBSurface(), thus 256-color pallete is allocated. But then biClrUsed colors are read from a file and stored into the palette. SDL_LoadBMP_RW should report an error if biClrUsed is greater than 2^biBitCount.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../SDL_internal.h"
    22 
    23 /* General touch handling code for SDL */
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_events.h"
    27 #include "SDL_events_c.h"
    28 #include "../video/SDL_sysvideo.h"
    29 
    30 
    31 static int SDL_num_touch = 0;
    32 static SDL_Touch **SDL_touchDevices = NULL;
    33 
    34 
    35 /* Public functions */
    36 int
    37 SDL_TouchInit(void)
    38 {
    39     return (0);
    40 }
    41 
    42 int
    43 SDL_GetNumTouchDevices(void)
    44 {
    45     return SDL_num_touch;
    46 }
    47 
    48 SDL_TouchID
    49 SDL_GetTouchDevice(int index)
    50 {
    51     if (index < 0 || index >= SDL_num_touch) {
    52         SDL_SetError("Unknown touch device index %d", index);
    53         return 0;
    54     }
    55     return SDL_touchDevices[index]->id;
    56 }
    57 
    58 static int
    59 SDL_GetTouchIndex(SDL_TouchID id)
    60 {
    61     int index;
    62     SDL_Touch *touch;
    63 
    64     for (index = 0; index < SDL_num_touch; ++index) {
    65         touch = SDL_touchDevices[index];
    66         if (touch->id == id) {
    67             return index;
    68         }
    69     }
    70     return -1;
    71 }
    72 
    73 SDL_Touch *
    74 SDL_GetTouch(SDL_TouchID id)
    75 {
    76     int index = SDL_GetTouchIndex(id);
    77     if (index < 0 || index >= SDL_num_touch) {
    78         if (SDL_GetVideoDevice()->ResetTouch != NULL) {
    79             SDL_SetError("Unknown touch id %d, resetting", (int) id);
    80             (SDL_GetVideoDevice()->ResetTouch)(SDL_GetVideoDevice());
    81         } else {
    82             SDL_SetError("Unknown touch device id %d, cannot reset", (int) id);
    83         }
    84         return NULL;
    85     }
    86     return SDL_touchDevices[index];
    87 }
    88 
    89 SDL_TouchDeviceType
    90 SDL_GetTouchDeviceType(SDL_TouchID id)
    91 {
    92     SDL_Touch *touch = SDL_GetTouch(id);
    93     if (touch) {
    94         return touch->type;
    95     }
    96     return SDL_TOUCH_DEVICE_INVALID;
    97 }
    98 
    99 static int
   100 SDL_GetFingerIndex(const SDL_Touch * touch, SDL_FingerID fingerid)
   101 {
   102     int index;
   103     for (index = 0; index < touch->num_fingers; ++index) {
   104         if (touch->fingers[index]->id == fingerid) {
   105             return index;
   106         }
   107     }
   108     return -1;
   109 }
   110 
   111 static SDL_Finger *
   112 SDL_GetFinger(const SDL_Touch * touch, SDL_FingerID id)
   113 {
   114     int index = SDL_GetFingerIndex(touch, id);
   115     if (index < 0 || index >= touch->num_fingers) {
   116         return NULL;
   117     }
   118     return touch->fingers[index];
   119 }
   120 
   121 int
   122 SDL_GetNumTouchFingers(SDL_TouchID touchID)
   123 {
   124     SDL_Touch *touch = SDL_GetTouch(touchID);
   125     if (touch) {
   126         return touch->num_fingers;
   127     }
   128     return 0;
   129 }
   130 
   131 SDL_Finger *
   132 SDL_GetTouchFinger(SDL_TouchID touchID, int index)
   133 {
   134     SDL_Touch *touch = SDL_GetTouch(touchID);
   135     if (!touch) {
   136         return NULL;
   137     }
   138     if (index < 0 || index >= touch->num_fingers) {
   139         SDL_SetError("Unknown touch finger");
   140         return NULL;
   141     }
   142     return touch->fingers[index];
   143 }
   144 
   145 int
   146 SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
   147 {
   148     SDL_Touch **touchDevices;
   149     int index;
   150 
   151     index = SDL_GetTouchIndex(touchID);
   152     if (index >= 0) {
   153         return index;
   154     }
   155 
   156     /* Add the touch to the list of touch */
   157     touchDevices = (SDL_Touch **) SDL_realloc(SDL_touchDevices,
   158                                       (SDL_num_touch + 1) * sizeof(*touchDevices));
   159     if (!touchDevices) {
   160         return SDL_OutOfMemory();
   161     }
   162 
   163     SDL_touchDevices = touchDevices;
   164     index = SDL_num_touch;
   165 
   166     SDL_touchDevices[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchDevices[index]));
   167     if (!SDL_touchDevices[index]) {
   168         return SDL_OutOfMemory();
   169     }
   170 
   171     /* Added touch to list */
   172     ++SDL_num_touch;
   173 
   174     /* we're setting the touch properties */
   175     SDL_touchDevices[index]->id = touchID;
   176     SDL_touchDevices[index]->type = type;
   177     SDL_touchDevices[index]->num_fingers = 0;
   178     SDL_touchDevices[index]->max_fingers = 0;
   179     SDL_touchDevices[index]->fingers = NULL;
   180 
   181     /* Record this touch device for gestures */
   182     /* We could do this on the fly in the gesture code if we wanted */
   183     SDL_GestureAddTouch(touchID);
   184 
   185     return index;
   186 }
   187 
   188 static int
   189 SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure)
   190 {
   191     SDL_Finger *finger;
   192 
   193     if (touch->num_fingers == touch->max_fingers) {
   194         SDL_Finger **new_fingers;
   195         new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers+1)*sizeof(*touch->fingers));
   196         if (!new_fingers) {
   197             return SDL_OutOfMemory();
   198         }
   199         touch->fingers = new_fingers;
   200         touch->fingers[touch->max_fingers] = (SDL_Finger *)SDL_malloc(sizeof(*finger));
   201         if (!touch->fingers[touch->max_fingers]) {
   202             return SDL_OutOfMemory();
   203         }
   204         touch->max_fingers++;
   205     }
   206 
   207     finger = touch->fingers[touch->num_fingers++];
   208     finger->id = fingerid;
   209     finger->x = x;
   210     finger->y = y;
   211     finger->pressure = pressure;
   212     return 0;
   213 }
   214 
   215 static int
   216 SDL_DelFinger(SDL_Touch* touch, SDL_FingerID fingerid)
   217 {
   218     SDL_Finger *temp;
   219 
   220     int index = SDL_GetFingerIndex(touch, fingerid);
   221     if (index < 0) {
   222         return -1;
   223     }
   224 
   225     touch->num_fingers--;
   226     temp = touch->fingers[index];
   227     touch->fingers[index] = touch->fingers[touch->num_fingers];
   228     touch->fingers[touch->num_fingers] = temp;
   229     return 0;
   230 }
   231 
   232 int
   233 SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
   234               SDL_bool down, float x, float y, float pressure)
   235 {
   236     int posted;
   237     SDL_Finger *finger;
   238 
   239     SDL_Touch* touch = SDL_GetTouch(id);
   240     if (!touch) {
   241         return -1;
   242     }
   243 
   244     finger = SDL_GetFinger(touch, fingerid);
   245     if (down) {
   246         if (finger) {
   247             /* This finger is already down */
   248             return 0;
   249         }
   250 
   251         if (SDL_AddFinger(touch, fingerid, x, y, pressure) < 0) {
   252             return 0;
   253         }
   254 
   255         posted = 0;
   256         if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
   257             SDL_Event event;
   258             event.tfinger.type = SDL_FINGERDOWN;
   259             event.tfinger.touchId = id;
   260             event.tfinger.fingerId = fingerid;
   261             event.tfinger.x = x;
   262             event.tfinger.y = y;
   263             event.tfinger.dx = 0;
   264             event.tfinger.dy = 0;
   265             event.tfinger.pressure = pressure;
   266             posted = (SDL_PushEvent(&event) > 0);
   267         }
   268     } else {
   269         if (!finger) {
   270             /* This finger is already up */
   271             return 0;
   272         }
   273 
   274         posted = 0;
   275         if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
   276             SDL_Event event;
   277             event.tfinger.type = SDL_FINGERUP;
   278             event.tfinger.touchId =  id;
   279             event.tfinger.fingerId = fingerid;
   280             /* I don't trust the coordinates passed on fingerUp */
   281             event.tfinger.x = finger->x;
   282             event.tfinger.y = finger->y;
   283             event.tfinger.dx = 0;
   284             event.tfinger.dy = 0;
   285             event.tfinger.pressure = pressure;
   286             posted = (SDL_PushEvent(&event) > 0);
   287         }
   288 
   289         SDL_DelFinger(touch, fingerid);
   290     }
   291     return posted;
   292 }
   293 
   294 int
   295 SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
   296                     float x, float y, float pressure)
   297 {
   298     SDL_Touch *touch;
   299     SDL_Finger *finger;
   300     int posted;
   301     float xrel, yrel, prel;
   302 
   303     touch = SDL_GetTouch(id);
   304     if (!touch) {
   305         return -1;
   306     }
   307 
   308     finger = SDL_GetFinger(touch,fingerid);
   309     if (!finger) {
   310         return SDL_SendTouch(id, fingerid, SDL_TRUE, x, y, pressure);
   311     }
   312 
   313     xrel = x - finger->x;
   314     yrel = y - finger->y;
   315     prel = pressure - finger->pressure;
   316 
   317     /* Drop events that don't change state */
   318     if (xrel == 0.0f && yrel == 0.0f && prel == 0.0f) {
   319 #if 0
   320         printf("Touch event didn't change state - dropped!\n");
   321 #endif
   322         return 0;
   323     }
   324 
   325     /* Update internal touch coordinates */
   326     finger->x = x;
   327     finger->y = y;
   328     finger->pressure = pressure;
   329 
   330     /* Post the event, if desired */
   331     posted = 0;
   332     if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
   333         SDL_Event event;
   334         event.tfinger.type = SDL_FINGERMOTION;
   335         event.tfinger.touchId = id;
   336         event.tfinger.fingerId = fingerid;
   337         event.tfinger.x = x;
   338         event.tfinger.y = y;
   339         event.tfinger.dx = xrel;
   340         event.tfinger.dy = yrel;
   341         event.tfinger.pressure = pressure;
   342         posted = (SDL_PushEvent(&event) > 0);
   343     }
   344     return posted;
   345 }
   346 
   347 void
   348 SDL_DelTouch(SDL_TouchID id)
   349 {
   350     int i;
   351     int index = SDL_GetTouchIndex(id);
   352     SDL_Touch *touch = SDL_GetTouch(id);
   353 
   354     if (!touch) {
   355         return;
   356     }
   357 
   358     for (i = 0; i < touch->max_fingers; ++i) {
   359         SDL_free(touch->fingers[i]);
   360     }
   361     SDL_free(touch->fingers);
   362     SDL_free(touch);
   363 
   364     SDL_num_touch--;
   365     SDL_touchDevices[index] = SDL_touchDevices[SDL_num_touch];
   366 
   367     /* Delete this touch device for gestures */
   368     SDL_GestureDelTouch(id);
   369 }
   370 
   371 void
   372 SDL_TouchQuit(void)
   373 {
   374     int i;
   375 
   376     for (i = SDL_num_touch; i--; ) {
   377         SDL_DelTouch(SDL_touchDevices[i]->id);
   378     }
   379     SDL_assert(SDL_num_touch == 0);
   380 
   381     SDL_free(SDL_touchDevices);
   382     SDL_touchDevices = NULL;
   383     SDL_GestureQuit();
   384 }
   385 
   386 /* vi: set ts=4 sw=4 expandtab: */