summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorYaniv Kamay <ykamay@redhat.com>2009-09-19 21:25:46 +0300
committerYaniv Kamay <ykamay@redhat.com>2009-10-14 15:06:41 +0200
commitc1b79eb035fa158fb2ac3bc8e559809611070016 (patch)
tree3348dd749a700dedf87c9b16fe8be77c62928df8 /tools
downloadspice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.gz
spice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.xz
spice-c1b79eb035fa158fb2ac3bc8e559809611070016.zip
fresh start
Diffstat (limited to 'tools')
-rw-r--r--tools/bitmap_to_c.c396
-rw-r--r--tools/icon_to_c.c369
-rw-r--r--tools/reds_stat.c132
3 files changed, 897 insertions, 0 deletions
diff --git a/tools/bitmap_to_c.c b/tools/bitmap_to_c.c
new file mode 100644
index 00000000..3329d5ed
--- /dev/null
+++ b/tools/bitmap_to_c.c
@@ -0,0 +1,396 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+#define TRUE 1
+#define FALSE 0
+
+#define ERROR(str) printf("%s: error: %s\n", prog_name, str); exit(-1);
+
+static char *prog_name = NULL;
+
+static size_t read_input(const char *file_name, uint8_t** out_buf)
+{
+ int fd = open(file_name, O_RDONLY);
+ if (fd == -1) {
+ ERROR("open source file failed");
+ return 0;
+ }
+ struct stat file_stat;
+ if (fstat(fd, &file_stat) == -1) {
+ ERROR("fstat on source file failed");
+ return 0;
+ }
+
+ uint8_t *buf = malloc(file_stat.st_size);
+
+ if (!buf) {
+ close(fd);
+ ERROR("alloc mem failed");
+ return 0;
+ }
+
+ size_t to_read = file_stat.st_size;
+ uint8_t *buf_pos = buf;
+ while (to_read) {
+ int n = read(fd, buf_pos, to_read);
+ if (n <= 0) {
+ ERROR("read from source file failed");
+ close(fd);
+ free(buf);
+ return 0;
+ }
+ to_read -= n;
+ buf_pos += n;
+ }
+ close(fd);
+ *out_buf = buf;
+ return file_stat.st_size;
+}
+
+typedef struct __attribute__ ((__packed__)) BitmpaHeader {
+ uint32_t header_size;
+ uint32_t width;
+ uint32_t height;
+ uint16_t plans;
+ uint16_t bpp;
+ uint32_t compression;
+ uint32_t image_size;
+ uint32_t horizontal_resolution;
+ uint32_t vertical_resolution;
+ uint32_t num_colors;
+ uint32_t important_colors;
+} BitmpaHeader;
+
+typedef struct __attribute__ ((__packed__)) BMPFileHeader {
+ uint16_t magic;
+ uint32_t file_size;
+ uint32_t reserved;
+ uint32_t data_offset;
+ BitmpaHeader header;
+} BMPFileHeader;
+
+#define BI_RGB 0
+
+typedef struct Pixmap {
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t bpp;
+ uint8_t* data;
+} Pixmap;
+
+static Pixmap *init_bitmap(size_t input_size, uint8_t *buf)
+{
+ BMPFileHeader *file_header;
+ uint8_t *pixels;
+ Pixmap *pixmap;
+ uint32_t stride;
+
+
+ if (input_size < sizeof(BMPFileHeader)) {
+ ERROR("invalid source file");
+ return NULL;
+ }
+
+ file_header = (BMPFileHeader *)buf;
+
+ if (file_header->magic != 0x4d42) {
+ ERROR("bad bitmap magic");
+ return NULL;
+ }
+
+ if (file_header->file_size != input_size) {
+ ERROR("invalid source file");
+ return NULL;
+ }
+
+ if (file_header->header.header_size != 40 || file_header->header.plans != 1 ||
+ file_header->header.compression != BI_RGB ||
+ !file_header->header.width ||
+ !file_header->header.height) {
+ ERROR("invalid bitmap header");
+ return NULL;
+ }
+
+ if (file_header->header.bpp == 32) {
+ stride = file_header->header.width * sizeof(uint32_t);
+ } else if (file_header->header.bpp == 24) {
+ stride = ALIGN(file_header->header.width * 3, 4);
+ } else {
+ ERROR("unsupported bpp");
+ return NULL;
+ }
+
+ if (file_header->header.height * stride > file_header->header.image_size) {
+ ERROR("image size is to small");
+ return NULL;
+ }
+ pixels = buf + file_header->data_offset;
+ if (pixels < (uint8_t *)(file_header + 1) ||
+ pixels + file_header->header.image_size > buf + input_size) {
+ ERROR("bad data offset");
+ return NULL;
+ }
+
+ if (!(pixmap = (Pixmap *)malloc(sizeof(*pixmap)))) {
+ ERROR("alloc mem failed");
+ return NULL;
+ }
+
+ pixmap->width = file_header->header.width;
+ pixmap->height = file_header->header.height;
+ pixmap->stride = stride;
+ pixmap->bpp = file_header->header.bpp;
+ pixmap->data = pixels;
+ return pixmap;
+}
+
+static inline void put_char(FILE* f, uint8_t val)
+{
+ fprintf(f, "0x%.2x,", val);
+}
+
+static void do_dump_with_alpha_conversion(const Pixmap *pixmap, FILE *f)
+{
+ uint8_t *line = (uint8_t *)(pixmap->data + ((pixmap->height - 1) * pixmap->stride));
+ int line_size = 0;
+ int i, j;
+
+ for (i = 0; i < pixmap->height; i++) {
+ uint8_t *now = line;
+ for (j = 0; j < pixmap->width; j++, now += 4) {
+ if ((line_size++ % 6) == 0) {
+ fprintf(f, "\n\t\t");
+ }
+ double alpha = (double)now[3] / 0xff;
+ put_char(f, alpha * now[0]);
+ put_char(f, alpha * now[1]);
+ put_char(f, alpha * now[2]);
+ put_char(f, now[3]);
+ }
+ line -= pixmap->stride;
+ }
+}
+
+static void do_dump_32bpp(const Pixmap *pixmap, FILE *f)
+{
+ uint8_t *line = (uint8_t *)(pixmap->data + ((pixmap->height - 1) * pixmap->stride));
+ int line_size = 0;
+ int i, j;
+
+ for (i = 0; i < pixmap->height; i++) {
+ uint8_t *now = line;
+ for (j = 0; j < pixmap->width; j++, now += 4) {
+ if ((line_size++ % 6) == 0) {
+ fprintf(f, "\n\t\t");
+ }
+ put_char(f, now[0]);
+ put_char(f, now[1]);
+ put_char(f, now[2]);
+ put_char(f, now[3]);
+ }
+ line -= pixmap->stride;
+ }
+}
+
+static void do_dump_24bpp(const Pixmap *pixmap, FILE *f)
+{
+ uint8_t *line = (uint8_t *)(pixmap->data + ((pixmap->height - 1) * pixmap->stride));
+ int line_size = 0;
+ int i, j;
+
+ for (i = 0; i < pixmap->height; i++) {
+ uint8_t *now = line;
+ for (j = 0; j < pixmap->width; j++, now += 3) {
+ if ((line_size++ % 6) == 0) {
+ fprintf(f, "\n\t\t");
+ }
+ put_char(f, now[0]);
+ put_char(f, now[1]);
+ put_char(f, now[2]);
+ put_char(f, 0);
+ }
+ line -= pixmap->stride;
+ }
+}
+
+static int pixmap_to_c_struct(const Pixmap *pixmap, const char *dest_file, const char *image_name,
+ int alpha_convertion)
+{
+ int fd;
+ FILE *f;
+
+ if ((fd = open(dest_file, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
+ ERROR("open dest file failed");
+ return -1;
+ }
+
+ if (!(f = fdopen(fd, "w"))) {
+ ERROR("fdopen failed");
+ close(fd);
+ return -1;
+ }
+
+ uint32_t data_size = pixmap->width * sizeof(uint32_t) * pixmap->height;
+ fprintf(f, "static const struct {\n"
+ "\tuint32_t width;\n"
+ "\tuint32_t height;\n"
+ "\tuint8_t pixel_data[%u];\n"
+ "} %s = { %u, %u, {",
+ data_size, image_name, pixmap->width, pixmap->height);
+
+ if (alpha_convertion) {
+ if (pixmap->bpp != 32) {
+ ERROR("32 bpp is requred for alpha option")
+ }
+ do_dump_with_alpha_conversion(pixmap, f);
+ } else if (pixmap->bpp == 32) {
+ do_dump_32bpp(pixmap, f);
+ } else {
+ do_dump_24bpp(pixmap, f);
+ }
+
+ fseek(f, -1, SEEK_CUR);
+ fprintf(f, "}\n};\n");
+ fclose(f);
+ close(fd);
+ return 0;
+}
+
+enum {
+ ALPHA_OPT = 'a',
+ HELP_OPT = 'h',
+ NAME_OPT = 'n',
+};
+
+static void usage()
+{
+ printf("usage: %s [--alpha] [--name <struct name>] SOURCE [DEST]\n", prog_name);
+ printf(" %s --help\n", prog_name);
+}
+
+const struct option longopts[] = {
+ {"help", no_argument, NULL, HELP_OPT},
+ {"alpha", no_argument, NULL, ALPHA_OPT},
+ {"name", required_argument, NULL, NAME_OPT},
+ {NULL, 0, NULL, 0},
+};
+
+int main(int argc, char **argv)
+{
+ size_t input_size;
+ uint8_t* buf;
+ Pixmap *pixmap;
+ int opt;
+ int alpha_convertion = FALSE;
+ char *struct_name = NULL;
+ char *src = NULL;
+ char *dest = NULL;
+
+
+ if (!(prog_name = strrchr(argv[0], '/'))) {
+ prog_name = argv[0];
+ } else {
+ prog_name++;
+ }
+
+
+ while ((opt = getopt_long(argc, argv, "ah", longopts, NULL)) != -1) {
+ switch (opt) {
+ case 0:
+ case '?':
+ usage();
+ exit(-1);
+ case ALPHA_OPT:
+ alpha_convertion = TRUE;
+ break;
+ case HELP_OPT:
+ usage();
+ exit(0);
+ case NAME_OPT:
+ struct_name = optarg;
+ break;
+ }
+ }
+
+ int more = argc - optind;
+ switch (more) {
+ case 1: {
+ char *slash;
+ char *dot;
+
+ dest = malloc(strlen(argv[optind]) + 3);
+ strcpy(dest, argv[optind]);
+ dot = strrchr(dest, '.');
+ slash = strrchr(dest, '/');
+ if (!dot || (slash && slash > dot)) {
+ strcat(dest, ".c");
+ } else {
+ strcpy(dot, ".c");
+ }
+ break;
+ }
+ case 2:
+ dest = argv[optind + 1];
+ //todo: if dir strcat src name
+ break;
+ default:
+ usage();
+ exit(-1);
+ }
+
+ src = argv[optind];
+
+ if (!struct_name) {
+ char *struct_name_src;
+ char *dot;
+
+ struct_name_src = strrchr(dest, '/');
+ if (!struct_name_src) {
+ struct_name_src = dest;
+ } else {
+ ++struct_name_src;
+ }
+ struct_name = malloc(strlen(struct_name_src) + 1);
+ strcpy(struct_name, struct_name_src);
+ if ((dot = strchr(struct_name, '.'))) {
+ *dot = 0;
+ }
+ }
+
+ if (!(input_size = read_input(src, &buf))) {
+ return -1;
+ }
+
+ if (!(pixmap = init_bitmap(input_size, buf))) {
+ return -1;
+ }
+ return pixmap_to_c_struct(pixmap, dest, struct_name, alpha_convertion);
+}
+
diff --git a/tools/icon_to_c.c b/tools/icon_to_c.c
new file mode 100644
index 00000000..79ae5fac
--- /dev/null
+++ b/tools/icon_to_c.c
@@ -0,0 +1,369 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+#define TRUE 1
+#define FALSE 0
+
+#define ERROR(str) printf("%s: error: %s\n", prog_name, str); exit(-1);
+
+static char *prog_name = NULL;
+
+static size_t read_input(const char *file_name, uint8_t** out_buf)
+{
+ int fd = open(file_name, O_RDONLY);
+ if (fd == -1) {
+ ERROR("open source file failed");
+ return 0;
+ }
+ struct stat file_stat;
+ if (fstat(fd, &file_stat) == -1) {
+ ERROR("fstat on source file failed");
+ return 0;
+ }
+
+ uint8_t *buf = malloc(file_stat.st_size);
+
+ if (!buf) {
+ close(fd);
+ ERROR("alloc mem failed");
+ return 0;
+ }
+
+ size_t to_read = file_stat.st_size;
+ uint8_t *buf_pos = buf;
+ while (to_read) {
+ int n = read(fd, buf_pos, to_read);
+ if (n <= 0) {
+ ERROR("read from source file failed");
+ close(fd);
+ free(buf);
+ return 0;
+ }
+ to_read -= n;
+ buf_pos += n;
+ }
+ close(fd);
+ *out_buf = buf;
+ return file_stat.st_size;
+}
+
+typedef struct __attribute__ ((__packed__)) BitmpaHeader {
+ uint32_t header_size;
+ uint32_t width;
+ uint32_t height;
+ uint16_t plans;
+ uint16_t bpp;
+ uint32_t compression;
+ uint32_t image_size;
+ uint32_t horizontal_resolution;
+ uint32_t vertical_resolution;
+ uint32_t num_colors;
+ uint32_t important_colors;
+} BitmpaHeader;
+
+
+typedef struct __attribute__ ((__packed__)) ICOHeader {
+ uint8_t width;
+ uint8_t height;
+ uint8_t colors_count;
+ uint8_t reserved;
+ uint16_t plans;
+ uint16_t bpp;
+ uint32_t bitmap_size;
+ uint32_t bitmap_offset;
+} ICOHeader;
+
+typedef struct __attribute__ ((__packed__)) ICOFileHeader {
+ uint16_t reserved;
+ uint16_t type;
+ uint16_t image_count;
+ ICOHeader directory[0];
+} ICOFileHeader;
+
+
+typedef struct Icon {
+ int width;
+ int height;
+ uint8_t* pixmap;
+ uint8_t* mask;
+} Icon;
+
+
+static Icon *init_icon(uint8_t *buf, size_t buf_size)
+{
+ ICOFileHeader *file_header;
+ int i;
+
+ uint8_t *buf_end = buf + buf_size;
+
+ if (buf_size < sizeof(ICOFileHeader)) {
+ ERROR("invalid source file");
+ return NULL;
+ }
+
+ file_header = (ICOFileHeader *)buf;
+
+ if (file_header->reserved != 0 || file_header->type != 1) {
+ ERROR("invalid icon");
+ return NULL;
+ }
+
+ if (sizeof(ICOFileHeader) + file_header->image_count * sizeof(ICOHeader) > buf_size) {
+ ERROR("invalid source file");
+ }
+
+ for (i = 0; i < file_header->image_count; i++) {
+ int j;
+
+ ICOHeader *ico = &file_header->directory[i];
+ printf("%ux%ux%u size %u\n", (unsigned)ico->width, (unsigned)ico->height,
+ (unsigned)ico->bpp, ico->bitmap_size);
+
+ if (ico->bitmap_offset + ico->bitmap_size > buf_size) {
+ ERROR("invalid source file");
+ }
+ BitmpaHeader *bitmap = (BitmpaHeader *)(buf + ico->bitmap_offset);
+ if (bitmap->header_size != 40) {
+ ERROR("invalid bitmap header");
+ }
+ if (bitmap->width != ico->width || bitmap->height != ico->height * 2 ||
+ bitmap->plans != ico->plans || bitmap->bpp != ico->bpp || !bitmap->image_size) {
+ ERROR("invalid bitmap header");
+ }
+
+ if (bitmap->compression || bitmap->horizontal_resolution || bitmap->vertical_resolution ||
+ bitmap->num_colors || bitmap->important_colors) {
+ ERROR("invalid bitmap header");
+ }
+
+ if (ico->width != 32 || ico->height != 32 || ico->bpp != 32) {
+ continue;
+ }
+
+ int pixmap_size = bitmap->width * sizeof(uint32_t) * ico->height;
+ int mask_size = ALIGN(bitmap->width, 8) / 8 * ico->height;
+ Icon* icon = malloc(sizeof(*icon) + pixmap_size + mask_size);
+ icon->width = ico->width;
+ icon->height = ico->height;
+ icon->pixmap = (uint8_t *)(icon + 1);
+ icon->mask = icon->pixmap + pixmap_size;
+
+ if ((uint8_t *)(bitmap + 1) + pixmap_size + mask_size > buf_end) {
+ ERROR("invalid source file");
+ }
+ memcpy(icon->pixmap, bitmap + 1, pixmap_size);
+ memcpy(icon->mask, (uint8_t *)(bitmap + 1) + pixmap_size, mask_size);
+ for (j = 0; j < mask_size; j++) {
+ icon->mask[j] = ~icon->mask[j];
+ }
+ return icon;
+ }
+ printf("%s: missing 32x32x32\n", prog_name);
+ return NULL;
+}
+
+static inline void put_char(FILE* f, uint8_t val)
+{
+ fprintf(f, "0x%.2x,", val);
+}
+
+static int icon_to_c_struct(const Icon *icon, const char *dest_file, const char *image_name)
+{
+ int i, j;
+ int fd;
+ FILE *f;
+
+ if ((fd = open(dest_file, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
+ ERROR("open dest file failed");
+ return -1;
+ }
+
+ if (!(f = fdopen(fd, "w"))) {
+ ERROR("fdopen failed");
+ close(fd);
+ return -1;
+ }
+ uint32_t pixmap_stride = icon->width * sizeof(uint32_t);
+ uint32_t pixmap_size = pixmap_stride * icon->height;
+ uint32_t mask_stride = ALIGN(icon->width, 8) / 8;
+ uint32_t mask_size = mask_stride * icon->height;
+ fprintf(f, "static const struct {\n"
+ "\tuint32_t width;\n"
+ "\tuint32_t height;\n"
+ "\tuint8_t pixmap[%u];\n"
+ "\tuint8_t mask[%u];\n"
+ "} %s = { %u, %u, {",
+ pixmap_size, mask_size, image_name, icon->width, icon->height);
+
+ uint8_t *line = (uint8_t *)(icon->pixmap + ((icon->height - 1) * pixmap_stride));
+ int line_size = 0;
+
+ for (i = 0; i < icon->height; i++) {
+ uint8_t *now = line;
+ for (j = 0; j < icon->width; j++, now += 4) {
+ if ((line_size++ % 6) == 0) {
+ fprintf(f, "\n\t\t");
+ }
+ put_char(f, now[0]);
+ put_char(f, now[1]);
+ put_char(f, now[2]);
+ put_char(f, now[3]);
+ }
+ line -= pixmap_stride;
+ }
+
+
+ fseek(f, -1, SEEK_CUR);
+ fprintf(f, "},\n\n\t\t{");
+
+ line = (uint8_t *)(icon->mask + ((icon->height - 1) * mask_stride));
+ line_size = 0;
+ for (i = 0; i < icon->height; i++) {
+ for (j = 0; j < mask_stride; j++) {
+ if (line_size && (line_size % 12) == 0) {
+ fprintf(f, "\n\t\t ");
+ }
+ line_size++;
+ put_char(f, line[j]);
+ }
+ line -= mask_stride;
+ }
+
+ fseek(f, -1, SEEK_CUR);
+ fprintf(f, "}\n};\n");
+ fclose(f);
+ close(fd);
+ return 0;
+}
+
+enum {
+ HELP_OPT = 'h',
+ NAME_OPT = 'n',
+};
+
+static void usage()
+{
+ printf("usage: %s [--name <struct name>] SOURCE [DEST]\n", prog_name);
+ printf(" %s --help\n", prog_name);
+}
+
+const struct option longopts[] = {
+ {"help", no_argument, NULL, HELP_OPT},
+ {"name", required_argument, NULL, NAME_OPT},
+ {NULL, 0, NULL, 0},
+};
+
+int main(int argc, char **argv)
+{
+ size_t input_size;
+ uint8_t* buf;
+ Icon *icon;
+ int opt;
+ char *struct_name = NULL;
+ char *src = NULL;
+ char *dest = NULL;
+
+
+ if (!(prog_name = strrchr(argv[0], '/'))) {
+ prog_name = argv[0];
+ } else {
+ prog_name++;
+ }
+
+
+ while ((opt = getopt_long(argc, argv, "ah", longopts, NULL)) != -1) {
+ switch (opt) {
+ case 0:
+ case '?':
+ usage();
+ exit(-1);
+ case HELP_OPT:
+ usage();
+ exit(0);
+ case NAME_OPT:
+ struct_name = optarg;
+ break;
+ }
+ }
+
+ int more = argc - optind;
+ switch (more) {
+ case 1: {
+ char *slash;
+ char *dot;
+
+ dest = malloc(strlen(argv[optind]) + 3);
+ strcpy(dest, argv[optind]);
+ dot = strrchr(dest, '.');
+ slash = strrchr(dest, '/');
+ if (!dot || (slash && slash > dot)) {
+ strcat(dest, ".c");
+ } else {
+ strcpy(dot, ".c");
+ }
+ break;
+ }
+ case 2:
+ dest = argv[optind + 1];
+ //todo: if dir strcat src name
+ break;
+ default:
+ usage();
+ exit(-1);
+ }
+
+ src = argv[optind];
+
+ if (!struct_name) {
+ char *struct_name_src;
+ char *dot;
+
+ struct_name_src = strrchr(dest, '/');
+ if (!struct_name_src) {
+ struct_name_src = dest;
+ } else {
+ ++struct_name_src;
+ }
+ struct_name = malloc(strlen(struct_name_src) + 1);
+ strcpy(struct_name, struct_name_src);
+ if ((dot = strchr(struct_name, '.'))) {
+ *dot = 0;
+ }
+ }
+
+ if (!(input_size = read_input(src, &buf))) {
+ return -1;
+ }
+
+ if (!(icon = init_icon(buf, input_size))) {
+ return -1;
+ }
+
+ return icon_to_c_struct(icon, dest, struct_name);
+}
+
diff --git a/tools/reds_stat.c b/tools/reds_stat.c
new file mode 100644
index 00000000..76541579
--- /dev/null
+++ b/tools/reds_stat.c
@@ -0,0 +1,132 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "reds_stat.h"
+
+#define TAB_LEN 4
+#define VALUE_TABS 7
+#define INVALID_STAT_REF (~(uint32_t)0)
+
+static RedsStat *reds_stat = NULL;
+static uint64_t *values = NULL;
+
+void print_stat_tree(int32_t node_index, int depth)
+{
+ StatNode *node = &reds_stat->nodes[node_index];
+ int i;
+
+ if ((node->flags & STAT_NODE_MASK_SHOW) == STAT_NODE_MASK_SHOW) {
+ printf("%*s%s", depth * TAB_LEN, "", node->name);
+ if (node->flags & STAT_NODE_FLAG_VALUE) {
+ printf(":%*s%llu (%llu)\n", (VALUE_TABS - depth) * TAB_LEN - strlen(node->name) - 1, "",
+ node->value, node->value - values[node_index]);
+ values[node_index] = node->value;
+ } else {
+ printf("\n");
+ if (node->first_child_index != INVALID_STAT_REF) {
+ print_stat_tree(node->first_child_index, depth + 1);
+ }
+ }
+ }
+ if (node->next_sibling_index != INVALID_STAT_REF) {
+ print_stat_tree(node->next_sibling_index, depth);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ char *shm_name;
+ pid_t kvm_pid;
+ uint64_t *val;
+ uint32_t num_of_nodes = 0;
+ size_t shm_size;
+ size_t shm_old_size;
+ int shm_name_len;
+ int ret = -1;
+ int fd;
+
+ if (argc != 2 || !(kvm_pid = atoi(argv[1]))) {
+ printf("usage: reds_stat [qemu_pid] (e.g. `pgrep qemu`)\n");
+ return -1;
+ }
+ shm_name_len = strlen(REDS_STAT_SHM_NAME) + strlen(argv[1]);
+ if (!(shm_name = (char *)malloc(shm_name_len))) {
+ perror("malloc");
+ return -1;
+ }
+ snprintf(shm_name, shm_name_len, REDS_STAT_SHM_NAME, kvm_pid);
+ if ((fd = shm_open(shm_name, O_RDONLY, 0444)) == -1) {
+ perror("shm_open");
+ free(shm_name);
+ return -1;
+ }
+ shm_size = sizeof(RedsStat);
+ reds_stat = mmap(NULL, shm_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (reds_stat == (RedsStat *)MAP_FAILED) {
+ perror("mmap");
+ goto error1;
+ }
+ if (reds_stat->magic != REDS_STAT_MAGIC) {
+ printf("bad magic %u\n", reds_stat->magic);
+ goto error2;
+ }
+ if (reds_stat->version != REDS_STAT_VERSION) {
+ printf("bad version %u\n", reds_stat->version);
+ goto error2;
+ }
+ while (1) {
+ system("clear");
+ printf("spice statistics\n\n");
+ if (num_of_nodes != reds_stat->num_of_nodes) {
+ num_of_nodes = reds_stat->num_of_nodes;
+ shm_old_size = shm_size;
+ shm_size = sizeof(RedsStat) + num_of_nodes * sizeof(StatNode);
+ reds_stat = mremap(reds_stat, shm_old_size, shm_size, MREMAP_MAYMOVE);
+ if (reds_stat == (RedsStat *)MAP_FAILED) {
+ perror("mremap");
+ goto error3;
+ }
+ values = (uint64_t *)realloc(values, num_of_nodes * sizeof(uint64_t));
+ if (values == NULL) {
+ perror("realloc");
+ goto error3;
+ }
+ memset(values, 0, num_of_nodes * sizeof(uint64_t));
+ }
+ print_stat_tree(reds_stat->root_index, 0);
+ sleep(1);
+ }
+ ret = 0;
+
+error3:
+ free(values);
+error2:
+ munmap(reds_stat, shm_size);
+error1:
+ shm_unlink(shm_name);
+ free(shm_name);
+ return ret;
+}
+