cake
/
p7utils
Archived
1
0
Fork 0

Initial commit for g1a-wrapper.

This commit is contained in:
Thomas Touhey 2017-03-27 19:40:42 +02:00
parent f0379d18fd
commit d871026f8b
6 changed files with 443 additions and 0 deletions

1
.gitignore vendored
View File

@ -3,5 +3,6 @@
/man
/p7*
/mcsfile*
/g1a-wrapper*
.*.swp

194
src/g1a-wrapper/args.c Normal file
View File

@ -0,0 +1,194 @@
/* *****************************************************************************
* g1a-wrapper/args.c -- g1a-wrapper command-line argument parsing.
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of p7utils.
* p7utils 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.0 of the License,
* or (at your option) any later version.
*
* p7utils 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 p7utils; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include "main.h"
#include <getopt.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
/* ************************************************************************** */
/* Help and version messages */
/* ************************************************************************** */
/* Version message */
static const char version_message[] =
QUOTE(BIN) " - from " QUOTE(NAME) " v" QUOTE(VERSION)
" (licensed under GPLv2)\n"
"Maintained by " QUOTE(MAINTAINER) ".\n"
"\n"
"This is free software; see the source for copying conditions.\n"
"There is NO warranty; not even for MERCHANTABILITY or\n"
"FITNESS FOR A PARTICULAR PURPOSE.";
/* Main help message */
static const char help_message[] =
"Usage: " QUOTE(BIN) " [-v] [--help|-h] <addin.bin>\n"
" [-o <output>] [-i <icon>] [-n <name>]\n"
" [--version <MM.mm.pppp>] [--internal <@ADDIN>]\n"
" [--date <yyyy.MMdd.hhmm]\n"
"\n"
"General options:\n"
" -h, --help Display the help page of the (sub)command and quit.\n"
" -v, --ver Display the version message and quit.\n"
" -o <output> Output file name, default is 'addin.g1a'.\n"
" -i <icon file> The application icon, must be 30x19.\n"
" Default is blank.\n"
" -n <name> The application name. '[A-Z]{,8}' formatted.\n"
" Default name is the truncated output filename.\n"
" --version <ver> The application version, 'MM.mm.pppp' formatted.\n"
" Default is '00.00.0000'.\n"
" --internal <int> The application internal name. '@[A-Z]{,7}' formatted.\n"
" Default is '@ADDIN'.\n"
" --date <date> The application build date. 'yyyy.MMdd.hhmm' formatted.\n"
" Default is the current time.\n"
"\n"
"Report bugs to " QUOTE(MAINTAINER) ".";
/* ************************************************************************** */
/* Main function */
/* ************************************************************************** */
/**
* parse_args:
* Args parsing main function.
*
* Was my very first experiment with getopt.
* Then I took an arrow in the knee.
*
* @arg ac the arguments count
* @arg av the arguments values
* @arg args the parsed args pointer
* @return if it was successfully parsed
*/
int parse_args(int ac, char **av, args_t *args)
{
/* initialize args */
static char name[9];
*args = (args_t){
.outfile = "addin.g1a", .iconfile = NULL,
.name = name, .intname = "@ADDIN",
.version = {0, 0, 0}, .date = time(NULL)};
/* define options */
const char *short_options = "hvo:i:n:";
struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"version", required_argument, NULL, 'V'},
{"internal", required_argument, NULL, 'I'},
{"date", required_argument, NULL, 'D'},
{NULL, 0, NULL, 0},
};
/* get all options */
int c; opterr = 0;
int help = 0;
const char *s_ver = NULL, *s_date = NULL;
while ((c = getopt_long(ac, av, short_options, long_options, NULL)) != -1)
switch (c) {
/* help, version */
case 'h': help = 1; break;
case 'v': puts(version_message); return (0); break;
/* general options */
case 'o': args->outfile = optarg; break;
case 'i': args->iconfile = optarg; break;
/* build options */
case 'n': args->name = optarg; break;
case 'V': s_ver = optarg; break;
case 'I': args->intname = optarg; break;
case 'D': s_date = optarg; break;
/* in case of error */
case '?': switch (optopt) {
case 'o': err("-o: expected an argument"); break;
case 'i': err("-i: expected an argument"); break;
case 'n': err("-n: expected an argument"); break;
case 'V': err("--version: expected an argument"); break;
case 'I': err("--internal: expected an argument"); break;
case 'D': err("--date: expected an argument"); break;
} break;
}
/* get non-option arguments (subcommand and parameters) */
int pc = ac - optind; char **pv = &av[optind];
if (pc != 1) help = 1;
args->infile = pv[0];
/* put help */
if (help) { puts(help_message); return (0); }
/* get name */
const char *p = strrchr(pv[0], '/');
if (!p) p = pv[0];
/* TODO: MS-Windows */
const char *e = strrchr(p, '.');
name[0] = 0;
for (int i = 0; p < e && i < 8; p++) {
if (isupper(*p)) {
name[i++] = *p;
name[i] = 0;
}
} if (!name[0])
strcpy(name, "ADDIN");
/* check internal name */
if (args->intname[0] != '@') {
err("internal name should start with an '@'");
return (0);
} for (int i = 1; args->intname[i]; i++) {
if (i >= 8) {
err("internal name should be up to 8 characters only!");
return (0);
}
if (!isupper(args->intname[i])) {
err("internal name should be an '@' then up to seven uppercase "
"letters!");
return (0);
}
}
/* get version */
if (s_ver) {
if (g1m_check_version(s_ver)) {
err("version string '%s' does not have "
"expected format 'MM.mm.ffff'", s_ver);
return (0);
}
/* decode! */
g1m_decode_version(s_ver, &args->version);
}
/* get date */
if (s_date) {
if (g1m_check_date(s_date)) {
err("date string '%s' does not have "
"expected format 'yyyy.MMdd.hhmm'", s_date);
return (0);
}
/* decode! */
g1m_decode_date(s_date, &args->date);
}
/* everything went well */
return (1);
}

94
src/g1a-wrapper/icon.c Normal file
View File

@ -0,0 +1,94 @@
/* *****************************************************************************
* g1a-wrapper/icon.c -- g1a-wrapper icon decoding function.
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of p7utils.
* p7utils 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.0 of the License,
* or (at your option) any later version.
*
* p7utils 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 p7utils; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include "main.h"
#include <string.h>
#include <magick/MagickCore.h>
/**
* open_icon:
* Open the icon.
*
* @arg path the image path.
* @arg icon the image.
*/
int open_icon(const char *path, uint32_t **icon)
{
int ret = 1;
Image *images = NULL, *image = NULL;
ImageInfo *info = NULL;
ExceptionInfo *exception = NULL;
/* initialize */
MagickCoreGenesis("g1a-wrapper", MagickTrue);
/* read source image and image info */
exception = AcquireExceptionInfo();
info = CloneImageInfo((ImageInfo*)NULL);
strcpy(info->filename, path);
images = ReadImage(info, exception);
if (!images) {
err("unable to open the icon: %s", exception->reason);
goto fail;
}
/* get the first frame */
image = RemoveFirstImageFromList(&images);
if (!image) goto fail;
/* check the dimensions */
unsigned int width = image->columns, height = image->rows;
if (width != 30 || height < 17 || height > 19) {
err("icon must be between 30x17 and 30x19 pixels, is %ux%u",
width, height);
goto fail;
}
/* get the pixels */
const Quantum *pixels = GetVirtualPixels(image, 0, 0, width, height,
exception);
if (!pixels) {
err("unable to access icon pixels.");
goto fail;
}
/* skip the first line */
if (height == 19) pixels += width * 4;
/* get the pixels */
for (size_t y = 0; y < 17; y++) for (size_t x = 0; x < 30; x++) {
/* get the total */
float r = *pixels++;
float g = *pixels++;
float b = *pixels++;
pixels++;
/* check the total */
icon[y][x] = (r + g + b > 0x198) ? 0xFFFFFF : 0x000000;
}
ret = 0;
fail:
if (info) DestroyImageInfo(info);
if (exception) DestroyExceptionInfo(exception);
if (image) DestroyImage(image);
if (images) DestroyImage(images);
MagickCoreTerminus();
return (ret);
}

100
src/g1a-wrapper/main.c Normal file
View File

@ -0,0 +1,100 @@
/* *****************************************************************************
* g1a-wrapper/main.c -- g1a-wrapper main source.
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of p7utils.
* p7utils 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.0 of the License,
* or (at your option) any later version.
*
* p7utils 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 p7utils; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include "main.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libg1m.h>
/* ************************************************************************** */
/* Main function */
/* ************************************************************************** */
/**
* main:
* User entry point of the program.
*
* @arg ac arguments count.
* @arg av arguments values.
* @return return code (0 if ok)
*/
int main(int ac, char **av)
{
int ret = 1; FILE *in = NULL;
g1m_handle_t *handle = NULL;
/* Parse args */
args_t args;
if (!parse_args(ac, av, &args))
return (0);
/* get file length */
in = fopen(args.infile, "r");
if (!in) {
err("couldn't open input file: %s", strerror(errno));
goto fail;
}
if (fseek(in, 0L, SEEK_END) < 0) {
err("couldn't seek in file.");
goto fail;
}
long off = ftell(in);
if (off < 0L)
goto fail;
size_t sz = (off < 0) ? SIZE_MAX : (size_t)off;
if (fseek(in, 0L, SEEK_SET))
goto fail;
/* make the handle */
int err = g1m_make_addin(&handle, g1m_platform_fx, sz,
args.name, args.intname, &args.version, &args.date);
if (err) {
err("couldn't make libg1m handle: %s", g1m_strerror(err));
goto fail;
}
/* decode the icon */
open_icon(args.iconfile, handle->icon_unsel);
/* copy the file content */
unsigned char *p = handle->content;
while (sz) {
size_t rd = fread(p, 1, sz, in);
if (!rd) {
err("couldn't read binary data: %s", strerror(errno));
goto fail;
}
sz -= rd; p += rd;
}
/* encode */
err = g1m_write(handle, args.outfile);
if (err) {
err("couldn't write to output file: %s",
err == g1m_error_nostream ? strerror(errno) : g1m_strerror(err));
goto fail;
}
/* we're good */
ret = 0;
fail:
if (in) fclose(in);
if (handle) g1m_free(handle);
return (ret);
}

50
src/g1a-wrapper/main.h Normal file
View File

@ -0,0 +1,50 @@
/* *****************************************************************************
* g1a-wrapper/main.h -- g1a-wrapper main header.
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of p7utils.
* p7utils 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.0 of the License,
* or (at your option) any later version.
*
* p7utils 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 p7utils; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#ifndef MAIN_H
# define MAIN_H
# define Q(x) #x
# define QUOTE(x) Q(x)
# include <stdio.h>
# include <libg1m.h>
# define warn(M, ...) \
fprintf(stderr, "g1a-wrapper: warning: " M "\n", ##__VA_ARGS__)
# define err(M, ...) \
fprintf(stderr, "g1a-wrapper: error: " M "\n", ##__VA_ARGS__)
/* Arguments */
typedef struct {
/* general options */
const char *infile; /* path to the input file */
const char *outfile; /* default: addin.g1a */
const char *iconfile; /* icon file, default is blank */
/* build options */
const char *name; /* default: truncated output filename */
const char *intname; /* default: @ADDIN */
g1m_version_t version; /* default: 00.00.0000 */
time_t date; /* default: current time */
} args_t;
/* Command-line arguments parsing function */
extern int parse_args(int ac, char **av, args_t *args);
/* Icon decoding function */
extern int open_icon(const char *path, uint32_t **icon);
#endif /* MAIN_H */

4
src/g1a-wrapper/vars.mk Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/make -f
disable:
libs:
@echo libg1m MagickCore