Parse XPM without SDL_image
We encounter some problems with SDL2_image on MSYS2 (Windows), so implement our own XPM parsing which does not depend on SDL_image. The input XPM is considered safe (it's in our source repo), so do not check XPM format errors. This implies that read_xpm() is not safe to call on any unsafe input. Although less straightforward, use SDL_CreateRGBSurfaceFrom() instead of SDL_CreateRGBSurfaceWithFormatFrom() because it is available with SDL versions older than 2.0.5.
This commit is contained in:
parent
920bafce73
commit
71c2bfdd22
5 changed files with 109 additions and 7 deletions
|
@ -7,13 +7,13 @@ This project displays screens of Android devices plugged on USB in live.
|
||||||
|
|
||||||
### Runtime requirements
|
### Runtime requirements
|
||||||
|
|
||||||
This projects requires _FFmpeg_, _LibSDL2_, _LibSDL2-image_ and _LibSDL2-net_.
|
This projects requires _FFmpeg_, _LibSDL2_ and _LibSDL2-net_.
|
||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
|
|
||||||
Install the packages from your package manager. For example, on Debian:
|
Install the packages from your package manager. For example, on Debian:
|
||||||
|
|
||||||
sudo apt install ffmpeg libsdl2-2.0.0 libsdl2-image-2.0.0 libsdl2-net-2.0.0
|
sudo apt install ffmpeg libsdl2-2.0.0 libsdl2-net-2.0.0
|
||||||
|
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
@ -21,7 +21,6 @@ Install the packages from your package manager. For example, on Debian:
|
||||||
From [MSYS2]:
|
From [MSYS2]:
|
||||||
|
|
||||||
pacman -S mingw-w64-x86_64-SDL2
|
pacman -S mingw-w64-x86_64-SDL2
|
||||||
pacman -S mingw-w64-x86_64-SDL2_image
|
|
||||||
pacman -S mingw-w64-x86_64-SDL2_net
|
pacman -S mingw-w64-x86_64-SDL2_net
|
||||||
pacman -S mingw-w64-x86_64-ffmpeg
|
pacman -S mingw-w64-x86_64-ffmpeg
|
||||||
|
|
||||||
|
@ -65,7 +64,7 @@ described below.
|
||||||
|
|
||||||
sudo apt install make gcc openjdk-8-jdk pkg-config meson zip \
|
sudo apt install make gcc openjdk-8-jdk pkg-config meson zip \
|
||||||
libavcodec-dev libavformat-dev libavutil-dev \
|
libavcodec-dev libavformat-dev libavutil-dev \
|
||||||
libsdl2-dev libsdl2-image-dev libsdl2-net-dev
|
libsdl2-dev libsdl2-net-dev
|
||||||
|
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
|
@ -13,6 +13,7 @@ src = [
|
||||||
'src/scrcpy.c',
|
'src/scrcpy.c',
|
||||||
'src/server.c',
|
'src/server.c',
|
||||||
'src/strutil.c',
|
'src/strutil.c',
|
||||||
|
'src/tinyxpm.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
if host_machine.system() == 'windows'
|
if host_machine.system() == 'windows'
|
||||||
|
@ -26,7 +27,6 @@ dependencies = [
|
||||||
dependency('libavcodec'),
|
dependency('libavcodec'),
|
||||||
dependency('libavutil'),
|
dependency('libavutil'),
|
||||||
dependency('sdl2'),
|
dependency('sdl2'),
|
||||||
dependency('SDL2_image'),
|
|
||||||
dependency('SDL2_net'),
|
dependency('SDL2_net'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <SDL2/SDL_image.h>
|
|
||||||
#include <SDL2/SDL_net.h>
|
#include <SDL2/SDL_net.h>
|
||||||
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
@ -19,6 +18,7 @@
|
||||||
#include "lockutil.h"
|
#include "lockutil.h"
|
||||||
#include "netutil.h"
|
#include "netutil.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#include "tinyxpm.h"
|
||||||
|
|
||||||
#include "icon.xpm"
|
#include "icon.xpm"
|
||||||
|
|
||||||
|
@ -651,7 +651,7 @@ SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 max_size, Uint32 b
|
||||||
goto screen_finally_destroy_renderer;
|
goto screen_finally_destroy_renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface *icon = IMG_ReadXPMFromArray(icon_xpm);
|
SDL_Surface *icon = read_xpm(icon_xpm);
|
||||||
if (!icon) {
|
if (!icon) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Could not load icon: %s", SDL_GetError());
|
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Could not load icon: %s", SDL_GetError());
|
||||||
ret = SDL_FALSE;
|
ret = SDL_FALSE;
|
||||||
|
|
100
app/src/tinyxpm.c
Normal file
100
app/src/tinyxpm.c
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
#include "tinyxpm.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct index {
|
||||||
|
char c;
|
||||||
|
Uint32 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SDL_bool find_color(struct index *index, int len, char c, Uint32 *color) {
|
||||||
|
// there are typically very few color, so it's ok to iterate over the array
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
if (index[i].c == c) {
|
||||||
|
*color = index[i].color;
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*color = 0;
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We encounter some problems with SDL2_image on MSYS2 (Windows),
|
||||||
|
// so here is our own XPM parsing not to depend on SDL_image.
|
||||||
|
//
|
||||||
|
// We do not hardcode the binary image to keep some flexibility to replace the
|
||||||
|
// icon easily (just by replacing icon.xpm).
|
||||||
|
//
|
||||||
|
// Parameter is not "const char *" because XPM formats are generally stored in a
|
||||||
|
// (non-const) "char *"
|
||||||
|
SDL_Surface *read_xpm(char *xpm[]) {
|
||||||
|
char *endptr;
|
||||||
|
// *** No error handling, assume the XPM source is valid ***
|
||||||
|
// (it's in our source repo)
|
||||||
|
// Assertions are only checked in debug
|
||||||
|
Uint32 width = strtol(xpm[0], &endptr, 10);
|
||||||
|
Uint32 height = strtol(endptr + 1, &endptr, 10);
|
||||||
|
Uint32 colors = strtol(endptr + 1, &endptr, 10);
|
||||||
|
Uint32 chars = strtol(endptr + 1, &endptr, 10);
|
||||||
|
|
||||||
|
// sanity checks
|
||||||
|
SDL_assert(width < 256);
|
||||||
|
SDL_assert(height < 256);
|
||||||
|
SDL_assert(colors < 256);
|
||||||
|
SDL_assert(chars == 1); // this implementation does not support more
|
||||||
|
|
||||||
|
// init index
|
||||||
|
struct index index[colors];
|
||||||
|
for (int i = 0; i < colors; ++i) {
|
||||||
|
const char *line = xpm[1+i];
|
||||||
|
index[i].c = line[0];
|
||||||
|
SDL_assert(line[1] == '\t');
|
||||||
|
SDL_assert(line[2] == 'c');
|
||||||
|
SDL_assert(line[3] == ' ');
|
||||||
|
if (line[4] == '#') {
|
||||||
|
index[i].color = 0xff000000 | strtol(&line[5], &endptr, 0x10);
|
||||||
|
SDL_assert(*endptr == '\0');
|
||||||
|
} else {
|
||||||
|
SDL_assert(!strcmp("None", &line[4]));
|
||||||
|
index[i].color = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse image
|
||||||
|
Uint32 *pixels = SDL_malloc(4 * width * height);
|
||||||
|
if (!pixels) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Could not allocate icon memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
const char *line = xpm[1 + colors + y];
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
char c = line[x];
|
||||||
|
Uint32 color;
|
||||||
|
SDL_bool color_found = find_color(index, colors, c, &color);
|
||||||
|
SDL_assert(color_found);
|
||||||
|
pixels[y * width + x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||||
|
Uint32 amask = 0x000000ff;
|
||||||
|
Uint32 rmask = 0x0000ff00;
|
||||||
|
Uint32 gmask = 0x00ff0000;
|
||||||
|
Uint32 bmask = 0xff000000;
|
||||||
|
#else // little endian, like x86
|
||||||
|
Uint32 amask = 0xff000000;
|
||||||
|
Uint32 rmask = 0x00ff0000;
|
||||||
|
Uint32 gmask = 0x0000ff00;
|
||||||
|
Uint32 bmask = 0x000000ff;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(pixels,
|
||||||
|
width, height,
|
||||||
|
32, 4 * width,
|
||||||
|
rmask, gmask, bmask, amask);
|
||||||
|
// make the surface own the raw pixels
|
||||||
|
surface->flags &= ~SDL_PREALLOC;
|
||||||
|
return surface;
|
||||||
|
}
|
3
app/src/tinyxpm.h
Normal file
3
app/src/tinyxpm.h
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
SDL_Surface *read_xpm(char *xpm[]);
|
Loading…
Reference in a new issue