mirror of
https://github.com/archr-linux/Arch-R.git
synced 2026-03-31 14:41:55 -07:00
System daemons: hotkeys (volume/brightness), automount, bluetooth agent, memory manager, sleep/suspend, USB gadget mode, save-config persistence. Boot splash: initramfs SVG renderer (fbsplash + svg_parser) for 0.7s splash. Panel tools: generate-panel-dtbos.sh rewrite, convert-panel.py for ROCKNIX panel data extraction, archr-dtbo.py for runtime overlay management. Input: archr-gptokeyb.c gamepad-to-keyboard mapper via uinput. Launch wrappers: emulationstation.sh and retroarch-launch.sh updated for KMS/DRM + Mesa 26 Panfrost environment. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
242 lines
6.7 KiB
C
242 lines
6.7 KiB
C
/*
|
|
* Arch R — SVG path parser
|
|
* SVG path parser for initramfs boot splash
|
|
* Removed stdio.h (crashes in static glibc PID 1 initramfs)
|
|
* Replaced sscanf with manual rgb() parsing
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "svg_parser.h"
|
|
|
|
#define INITIAL_CAPACITY 100
|
|
#define MAX_SUBPATHS 10
|
|
|
|
static Point current_point = {0, 0};
|
|
static Point start_point = {0, 0};
|
|
|
|
typedef struct {
|
|
Path paths[MAX_SUBPATHS];
|
|
int num_paths;
|
|
} CompoundPath;
|
|
|
|
static float parse_number(const char **str)
|
|
{
|
|
while (isspace(**str) || **str == ',')
|
|
(*str)++;
|
|
|
|
char *end;
|
|
float num = strtof(*str, &end);
|
|
*str = end;
|
|
return num;
|
|
}
|
|
|
|
static void add_point_to_path(Path *path, float x, float y)
|
|
{
|
|
if (path->num_points >= path->capacity) {
|
|
path->capacity *= 2;
|
|
Point *new_points = realloc(path->points, path->capacity * sizeof(Point));
|
|
if (!new_points)
|
|
return;
|
|
path->points = new_points;
|
|
}
|
|
path->points[path->num_points].x = x;
|
|
path->points[path->num_points].y = y;
|
|
path->num_points++;
|
|
}
|
|
|
|
static void add_compound_path_to_svg(SVGPath *svg, CompoundPath *compound)
|
|
{
|
|
for (int i = 0; i < compound->num_paths; i++) {
|
|
if (svg->num_paths >= svg->capacity) {
|
|
svg->capacity *= 2;
|
|
Path *new_paths = realloc(svg->paths, svg->capacity * sizeof(Path));
|
|
if (!new_paths)
|
|
return;
|
|
svg->paths = new_paths;
|
|
}
|
|
svg->paths[svg->num_paths] = compound->paths[i];
|
|
svg->paths[svg->num_paths].is_hole = (i > 0);
|
|
svg->num_paths++;
|
|
}
|
|
}
|
|
|
|
/* Manual rgb(r,g,b) parser — replaces sscanf (stdio.h not available) */
|
|
static int parse_int(const char **p)
|
|
{
|
|
while (**p && !isdigit(**p) && **p != '-')
|
|
(*p)++;
|
|
int sign = 1;
|
|
if (**p == '-') { sign = -1; (*p)++; }
|
|
int val = 0;
|
|
while (isdigit(**p)) {
|
|
val = val * 10 + (**p - '0');
|
|
(*p)++;
|
|
}
|
|
return sign * val;
|
|
}
|
|
|
|
Color parse_color(const char *color_str)
|
|
{
|
|
Color color = {0, 0, 0, 255};
|
|
|
|
if (color_str[0] == 'r' && color_str[1] == 'g' && color_str[2] == 'b' && color_str[3] == '(') {
|
|
const char *p = color_str + 4;
|
|
int r = parse_int(&p);
|
|
int g = parse_int(&p);
|
|
int b = parse_int(&p);
|
|
color.r = (uint8_t)(r < 0 ? 0 : (r > 255 ? 255 : r));
|
|
color.g = (uint8_t)(g < 0 ? 0 : (g > 255 ? 255 : g));
|
|
color.b = (uint8_t)(b < 0 ? 0 : (b > 255 ? 255 : b));
|
|
}
|
|
|
|
return color;
|
|
}
|
|
|
|
SVGPath* parse_svg_path(const char *path_data, const char *style)
|
|
{
|
|
SVGPath *svg = malloc(sizeof(SVGPath));
|
|
if (!svg) return NULL;
|
|
|
|
svg->paths = malloc(INITIAL_CAPACITY * sizeof(Path));
|
|
if (!svg->paths) {
|
|
free(svg);
|
|
return NULL;
|
|
}
|
|
|
|
svg->num_paths = 0;
|
|
svg->capacity = INITIAL_CAPACITY;
|
|
svg->fill_color = parse_color(style);
|
|
|
|
CompoundPath compound = {0};
|
|
compound.num_paths = 0;
|
|
|
|
Path *current_path = &compound.paths[0];
|
|
current_path->points = malloc(INITIAL_CAPACITY * sizeof(Point));
|
|
if (!current_path->points) {
|
|
free(svg->paths);
|
|
free(svg);
|
|
return NULL;
|
|
}
|
|
current_path->num_points = 0;
|
|
current_path->capacity = INITIAL_CAPACITY;
|
|
current_path->is_hole = 0;
|
|
|
|
const char *p = path_data;
|
|
char command = 'M';
|
|
float x1, y1, x2, y2, x3, y3;
|
|
bool new_subpath = true;
|
|
|
|
while (*p) {
|
|
if (isalpha(*p)) {
|
|
if (*p == 'M' && !new_subpath) {
|
|
if (current_path->num_points > 0) {
|
|
compound.num_paths++;
|
|
if (compound.num_paths < MAX_SUBPATHS) {
|
|
current_path = &compound.paths[compound.num_paths];
|
|
current_path->points = malloc(INITIAL_CAPACITY * sizeof(Point));
|
|
current_path->num_points = 0;
|
|
current_path->capacity = INITIAL_CAPACITY;
|
|
current_path->is_hole = 1;
|
|
}
|
|
}
|
|
}
|
|
command = *p++;
|
|
new_subpath = (command == 'M');
|
|
}
|
|
|
|
switch (command) {
|
|
case 'M':
|
|
x1 = parse_number(&p);
|
|
y1 = parse_number(&p);
|
|
add_point_to_path(current_path, x1, y1);
|
|
current_point.x = start_point.x = x1;
|
|
current_point.y = start_point.y = y1;
|
|
command = 'L';
|
|
break;
|
|
|
|
case 'L':
|
|
x1 = parse_number(&p);
|
|
y1 = parse_number(&p);
|
|
add_point_to_path(current_path, x1, y1);
|
|
current_point.x = x1;
|
|
current_point.y = y1;
|
|
break;
|
|
|
|
case 'H':
|
|
x1 = parse_number(&p);
|
|
add_point_to_path(current_path, x1, current_point.y);
|
|
current_point.x = x1;
|
|
break;
|
|
|
|
case 'V':
|
|
y1 = parse_number(&p);
|
|
add_point_to_path(current_path, current_point.x, y1);
|
|
current_point.y = y1;
|
|
break;
|
|
|
|
case 'Z':
|
|
case 'z':
|
|
if (current_path->num_points > 0)
|
|
add_point_to_path(current_path, start_point.x, start_point.y);
|
|
break;
|
|
|
|
case 'C':
|
|
x1 = parse_number(&p);
|
|
y1 = parse_number(&p);
|
|
x2 = parse_number(&p);
|
|
y2 = parse_number(&p);
|
|
x3 = parse_number(&p);
|
|
y3 = parse_number(&p);
|
|
|
|
for (float t = 0; t <= 1; t += 0.1f) {
|
|
float t2 = t * t;
|
|
float t3 = t2 * t;
|
|
float mt = 1 - t;
|
|
float mt2 = mt * mt;
|
|
float mt3 = mt2 * mt;
|
|
|
|
float px = current_point.x * mt3 +
|
|
3 * x1 * mt2 * t +
|
|
3 * x2 * mt * t2 +
|
|
x3 * t3;
|
|
|
|
float py = current_point.y * mt3 +
|
|
3 * y1 * mt2 * t +
|
|
3 * y2 * mt * t2 +
|
|
y3 * t3;
|
|
|
|
add_point_to_path(current_path, px, py);
|
|
}
|
|
|
|
current_point.x = x3;
|
|
current_point.y = y3;
|
|
break;
|
|
|
|
default:
|
|
while (*p && !isalpha(*p)) p++;
|
|
break;
|
|
}
|
|
|
|
while (isspace(*p)) p++;
|
|
}
|
|
|
|
if (current_path->num_points > 0)
|
|
compound.num_paths++;
|
|
|
|
add_compound_path_to_svg(svg, &compound);
|
|
|
|
return svg;
|
|
}
|
|
|
|
void free_svg_path(SVGPath *svg)
|
|
{
|
|
if (svg) {
|
|
for (uint32_t i = 0; i < svg->num_paths; i++)
|
|
free(svg->paths[i].points);
|
|
free(svg->paths);
|
|
free(svg);
|
|
}
|
|
}
|