Add-in development tools for fx-9860G and fx-CG 50, to use with GCC and gint.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <time.h>
  4. #include <getopt.h>
  5. #include <fxg1a.h>
  6. #include <g1a.h>
  7. static const char *help_string =
  8. "usage: %1$s [-g] <binary file> [options...]\n"
  9. " %1$s -e <g1a file> [options...]\n"
  10. " %1$s -d <g1a file>\n"
  11. " %1$s -r <g1a file> [-o <g1a file>]\n"
  12. " %1$s -x <g1a file> [-o <png file>]\n"
  13. "\n"
  14. "fxg1a creates or edits g1a files (add-in applications for Casio fx9860g\n"
  15. "calculator series) that consist of a g1a header followed by binary code.\n"
  16. "\n"
  17. "Operating modes:\n"
  18. " -g, --g1a Generate a g1a file (default)\n"
  19. " -e, --edit Edit header of an existing g1a file\n"
  20. " -d, --dump Dump header of an existing g1a file\n"
  21. " -r, --repair Recalculate control bytes and checksums\n"
  22. " -x, --extract Extract icon into a PNG file\n"
  23. "\n"
  24. "General options:\n"
  25. " -o, --output=<file> Output file (default: input file with .g1a suffix\n"
  26. " [-g]; with .png suffix [-x]; input file [-e, -r])\n"
  27. "\n"
  28. "Generation and edition options:\n"
  29. " -i, --icon=<png> Program icon, in PNG format (default: blank icon)\n"
  30. " -n, --name=<name> Add-in name, 8 bytes (default: output file name)\n"
  31. " --version=<text> Program version, MM.mm.pppp format (default: empty)\n"
  32. " --internal=<name> Internal name, eg. '@NAME' (default: empty)\n"
  33. " --date=<date> Date of build, yyyy.MMdd.hhmm (default: now)\n";
  34. /*
  35. ** Field customization
  36. */
  37. /* A set of user-defined fields, often taken on the command-line
  38. Default values are NULL and indicate "no value" (-g) or "no change" (-e). */
  39. struct fields
  40. {
  41. /* New values for basic fields */
  42. const char *name;
  43. const char *version;
  44. const char *internal;
  45. const char *date;
  46. /* Icon file name */
  47. const char *icon;
  48. };
  49. /* fields_edit(): Set the value of some fields altogether
  50. @header Header to edit, is assumed checksumed and filled
  51. @fields New values for fields, any members can be NULL */
  52. void fields_edit(struct g1a *header, struct fields const *fields)
  53. {
  54. /* For easy fields, just call the appropriate edition function */
  55. if(fields->name) edit_name(header, fields->name);
  56. if(fields->version) edit_version(header, fields->version);
  57. if(fields->internal) edit_internal(header, fields->internal);
  58. if(fields->date) edit_date(header, fields->date);
  59. /* Load icon from PNG file */
  60. if(fields->icon)
  61. {
  62. size_t width, height;
  63. uint8_t *data = icon_load(fields->icon, &width, &height);
  64. if(!data) return;
  65. uint8_t *mono = icon_conv_8to1(data, width, height);
  66. free(data);
  67. if(!mono) return;
  68. edit_icon(header, mono);
  69. }
  70. }
  71. /*
  72. ** Tool implementation
  73. */
  74. int main(int argc, char **argv)
  75. {
  76. /* Result of option parsing */
  77. int mode = 'g', error = 0;
  78. struct fields fields = { 0 };
  79. const char *output = NULL;
  80. const struct option longs[] = {
  81. { "help", no_argument, NULL, 'h' },
  82. { "g1a", no_argument, NULL, 'g' },
  83. { "edit", no_argument, NULL, 'e' },
  84. { "dump", no_argument, NULL, 'd' },
  85. { "repair", no_argument, NULL, 'r' },
  86. { "extract", no_argument, NULL, 'x' },
  87. { "output", required_argument, NULL, 'o' },
  88. { "icon", required_argument, NULL, 'i' },
  89. { "name", required_argument, NULL, 'n' },
  90. { "version", required_argument, NULL, 'v' },
  91. { "internal", required_argument, NULL, 't' },
  92. { "date", required_argument, NULL, 'a' },
  93. { NULL, 0, NULL, 0 },
  94. };
  95. int option = 0;
  96. while(option >= 0 && option != '?')
  97. switch((option = getopt_long(argc, argv, "hgedrxo:i:n:", longs, NULL)))
  98. {
  99. case 'h':
  100. fprintf(stderr, help_string, argv[0]);
  101. return 0;
  102. case 'g':
  103. case 'e':
  104. case 'd':
  105. case 'r':
  106. case 'x':
  107. mode = option;
  108. break;
  109. case 'o':
  110. output = optarg;
  111. break;
  112. case 'i':
  113. fields.icon = optarg;
  114. break;
  115. case 'n':
  116. fields.name = optarg;
  117. break;
  118. case 'v':
  119. fields.version = optarg;
  120. break;
  121. case 't':
  122. fields.internal = optarg;
  123. break;
  124. case 'a':
  125. fields.date = optarg;
  126. break;
  127. case '?':
  128. error = 1;
  129. break;
  130. }
  131. if(error) return 1;
  132. if(argv[optind] == NULL)
  133. {
  134. fprintf(stderr, help_string, argv[0]);
  135. return 1;
  136. }
  137. if(mode == 'g')
  138. {
  139. /* Load binary file into memory */
  140. size_t size;
  141. struct g1a *g1a = load_binary(argv[optind], &size);
  142. if(!g1a) return 1;
  143. /* If [output] is set, use it, otherwise compute a default */
  144. char *alloc = NULL;
  145. if(!output)
  146. {
  147. alloc = malloc(strlen(argv[optind]) + 5);
  148. if(!alloc) {fprintf(stderr, "error: %m\n"); return 1;}
  149. default_output(argv[optind], ".g1a", alloc);
  150. }
  151. /* Start with output file name as application name */
  152. edit_name(g1a, output ? output : alloc);
  153. /* Start with "now" as build date */
  154. char date[15];
  155. time_t t = time(NULL);
  156. struct tm *now = localtime(&t);
  157. strftime(date, 15, "%Y.%m%d.%H%M", now);
  158. edit_date(g1a, date);
  159. /* Edit the fields with user-customized values */
  160. fields_edit(g1a, &fields);
  161. /* Set fixed fields and calculate checksums */
  162. sign(g1a, size);
  163. save_g1a(output ? output : alloc, g1a, size);
  164. free(alloc);
  165. /* Write output file */
  166. free(g1a);
  167. }
  168. if(mode == 'e')
  169. {
  170. /* Load g1a file into memory */
  171. size_t size;
  172. struct g1a *g1a = load_g1a(argv[optind], &size);
  173. if(!g1a) return 1;
  174. /* Edit the fields with user-customized values */
  175. fields_edit(g1a, &fields);
  176. /* We don't reset fixed fields or recalculate checksums because
  177. we only want to edit what was requested by the user.
  178. Besides, the control bytes and checksums do *not* depend on
  179. the value of user-customizable fields. */
  180. /* Regenerate input file, or output somewhere else */
  181. if(!output) output = argv[optind];
  182. save_g1a(output, g1a, size);
  183. free(g1a);
  184. }
  185. if(mode == 'd')
  186. {
  187. /* Load and dump the g1a */
  188. size_t size;
  189. struct g1a *g1a = load_g1a(argv[optind], &size);
  190. if(!g1a) return 1;
  191. dump(g1a, size);
  192. free(g1a);
  193. }
  194. if(mode == 'r')
  195. {
  196. /* Load g1a file into memory */
  197. size_t size;
  198. struct g1a *g1a = load_g1a(argv[optind], &size);
  199. if(!g1a) return 1;
  200. /* Repair file by recalculating fixed fields and checksums */
  201. sign(g1a, size);
  202. /* Regenerate input file, or output somewhere else */
  203. if(!output) output = argv[optind];
  204. save_g1a(output, g1a, size);
  205. free(g1a);
  206. }
  207. if(mode == 'x')
  208. {
  209. /* Load g1a file into memory */
  210. size_t size;
  211. struct g1a *g1a = load_g1a(argv[optind], &size);
  212. if(!g1a) return 1;
  213. /* Generate 8-bit icon from g1a 1-bit */
  214. uint8_t *data = icon_conv_1to8(g1a->header.icon);
  215. if(!data)
  216. {
  217. fprintf(stderr, "error: %m\n");
  218. return 1;
  219. }
  220. /* Calculate a default output name if none is provided */
  221. if(output)
  222. {
  223. icon_save(output, data, 30, 17);
  224. }
  225. else
  226. {
  227. char *alloc = malloc(strlen(argv[optind]) + 5);
  228. if(!alloc) {fprintf(stderr, "error: %m\n"); return 1;}
  229. default_output(argv[optind], ".png", alloc);
  230. icon_save(alloc, data, 30, 17);
  231. free(alloc);
  232. }
  233. }
  234. return 0;
  235. }