lynx.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. lynx.c - Atari Lynx support for uCON64
  3. Copyright (c) 1999 - 2001 NoisyB <noisyb@gmx.net>
  4. Copyright (c) 2002 - 2003 dbjh
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. #include "config.h"
  19. #endif
  20. #include <fcntl.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #ifdef HAVE_UNISTD_H
  25. #include <unistd.h>
  26. #endif
  27. #include "misc/bswap.h"
  28. #include "misc/file.h"
  29. #include "misc/misc.h"
  30. #ifdef USE_ZLIB
  31. #include "misc/archive.h"
  32. #endif
  33. #include "misc/getopt2.h" // st_getopt2_t
  34. #include "ucon64.h"
  35. #include "ucon64_misc.h"
  36. #include "lynx.h"
  37. const st_getopt2_t lynx_usage[] =
  38. {
  39. {
  40. NULL, 0, 0, 0,
  41. NULL, "Handy (prototype)/Lynx/Lynx II"/*"1987 Epyx/1989 Atari/1991 Atari"*/,
  42. NULL
  43. },
  44. {
  45. "lynx", 0, 0, UCON64_LYNX,
  46. NULL, "force recognition",
  47. &ucon64_wf[WF_OBJ_LYNX_SWITCH]
  48. },
  49. {
  50. "lyx", 0, 0, UCON64_LYX,
  51. NULL, "convert to LYX/RAW (strip 64 Bytes LNX header)",
  52. &ucon64_wf[WF_OBJ_LYNX_DEFAULT]
  53. },
  54. {
  55. "lnx", 0, 0, UCON64_LNX,
  56. NULL, "convert to LNX (uses default values for the header);\n"
  57. "adjust the LNX header with the following options",
  58. &ucon64_wf[WF_OBJ_LYNX_DEFAULT]
  59. },
  60. {
  61. "n", 1, 0, UCON64_N,
  62. "NEW_NAME", "change internal ROM name to NEW_NAME (LNX only)",
  63. &ucon64_wf[WF_OBJ_ALL_DEFAULT]
  64. },
  65. {
  66. "nrot", 0, 0, UCON64_NROT,
  67. NULL, "set no rotation (LNX only)",
  68. &ucon64_wf[WF_OBJ_LYNX_DEFAULT]
  69. },
  70. {
  71. "rotl", 0, 0, UCON64_ROTL,
  72. NULL, "set rotation left (LNX only)",
  73. &ucon64_wf[WF_OBJ_LYNX_DEFAULT]
  74. },
  75. {
  76. "rotr", 0, 0, UCON64_ROTR,
  77. NULL, "set rotation right (LNX only)",
  78. &ucon64_wf[WF_OBJ_LYNX_DEFAULT]
  79. },
  80. {
  81. "b0", 1, 0, UCON64_B0,
  82. "N", "change Bank0 kBytes size to N={0,64,128,256,512} (LNX only)",
  83. &ucon64_wf[WF_OBJ_LYNX_DEFAULT]
  84. },
  85. {
  86. "b1", 1, 0, UCON64_B1,
  87. "N", "change Bank1 kBytes size to N={0,64,128,256,512} (LNX only)",
  88. &ucon64_wf[WF_OBJ_LYNX_DEFAULT]
  89. },
  90. {NULL, 0, 0, 0, NULL, NULL, NULL}
  91. };
  92. const char *lynx_lyx_desc = "convert to LYX/RAW (strip 64 Bytes LNX header)";
  93. //static const char *lnx_usage[] = "LNX header";
  94. #define LNX_HEADER_START 0
  95. #define LNX_HEADER_LEN (sizeof (st_lnx_header_t))
  96. st_lnx_header_t lnx_header;
  97. int
  98. lynx_lyx (st_rominfo_t *rominfo)
  99. {
  100. char dest_name[FILENAME_MAX];
  101. if (!rominfo->buheader_len)
  102. {
  103. fprintf (stderr, "ERROR: This is no LNX file\n\n");
  104. return -1;
  105. }
  106. strcpy (dest_name, ucon64.rom);
  107. set_suffix (dest_name, ".lyx");
  108. ucon64_file_handler (dest_name, NULL, 0);
  109. fcopy (ucon64.rom, rominfo->buheader_len, ucon64.file_size, dest_name, "wb");
  110. printf (ucon64_msg[WROTE], dest_name);
  111. return 0;
  112. }
  113. int
  114. lynx_lnx (st_rominfo_t *rominfo)
  115. {
  116. st_lnx_header_t header;
  117. char dest_name[FILENAME_MAX];
  118. int size = ucon64.file_size;
  119. if (rominfo->buheader_len != 0)
  120. {
  121. fprintf (stderr, "ERROR: This seems to already be an LNX file\n\n");
  122. return -1;
  123. }
  124. header.page_size_bank0 = size > 4 * MBIT ? 4 * MBIT / 256 : size / 256;
  125. header.page_size_bank1 = size > 4 * MBIT ? (size - (4 * MBIT)) / 256 : 0;
  126. #ifdef WORDS_BIGENDIAN
  127. header.page_size_bank0 = bswap_16 (header.page_size_bank0);
  128. header.page_size_bank1 = bswap_16 (header.page_size_bank1);
  129. #endif
  130. memset (header.cartname, 0, sizeof (header.cartname));
  131. memset (header.manufname, 0, sizeof (header.manufname));
  132. memset (header.spare, 0, sizeof (header.spare));
  133. #ifdef WORDS_BIGENDIAN
  134. header.version = bswap_16 (1);
  135. #else
  136. header.version = 1;
  137. #endif
  138. memcpy (header.magic, "LYNX", 4);
  139. header.rotation = 0;
  140. strncpy (header.cartname, ucon64.rom, sizeof (header.cartname));
  141. strcpy (header.manufname, "Atari");
  142. strcpy (dest_name, ucon64.rom);
  143. set_suffix (dest_name, ".lnx");
  144. ucon64_file_handler (dest_name, NULL, 0);
  145. ucon64_fwrite (&header, 0, sizeof (st_lnx_header_t), dest_name, "wb");
  146. fcopy (ucon64.rom, 0, ucon64.file_size, dest_name, "ab");
  147. printf (ucon64_msg[WROTE], dest_name);
  148. return 0;
  149. }
  150. static int
  151. lynx_rot (st_rominfo_t *rominfo, int rotation)
  152. {
  153. st_lnx_header_t header;
  154. char dest_name[FILENAME_MAX];
  155. if (!rominfo->buheader_len)
  156. {
  157. fprintf (stderr, "ERROR: This is no LNX file\n\n");
  158. return -1;
  159. }
  160. ucon64_fread (&header, 0, sizeof (st_lnx_header_t), ucon64.rom);
  161. header.rotation = rotation; // header.rotation is an 8-bit field
  162. strcpy (dest_name, ucon64.rom);
  163. ucon64_file_handler (dest_name, NULL, 0);
  164. fcopy (ucon64.rom, 0, ucon64.file_size, dest_name, "wb");
  165. ucon64_fwrite (&header, 0, sizeof (st_lnx_header_t), dest_name, "r+b");
  166. printf (ucon64_msg[WROTE], dest_name);
  167. return 0;
  168. }
  169. int
  170. lynx_nrot (st_rominfo_t *rominfo)
  171. {
  172. return lynx_rot (rominfo, 0); // no rotation
  173. }
  174. int
  175. lynx_rotl (st_rominfo_t *rominfo)
  176. {
  177. return lynx_rot (rominfo, 1); // rotate left
  178. }
  179. int
  180. lynx_rotr (st_rominfo_t *rominfo)
  181. {
  182. return lynx_rot (rominfo, 2); // rotate right
  183. }
  184. int
  185. lynx_n (st_rominfo_t *rominfo, const char *name)
  186. {
  187. st_lnx_header_t header;
  188. char dest_name[FILENAME_MAX];
  189. if (!rominfo->buheader_len)
  190. {
  191. fprintf (stderr, "ERROR: This is no LNX file\n\n");
  192. return -1;
  193. }
  194. ucon64_fread (&header, 0, sizeof (st_lnx_header_t), ucon64.rom);
  195. memset (header.cartname, 0, sizeof (header.cartname));
  196. strncpy (header.cartname, name, sizeof (header.cartname));
  197. strcpy (dest_name, ucon64.rom);
  198. ucon64_file_handler (dest_name, NULL, 0);
  199. fcopy (ucon64.rom, 0, ucon64.file_size, dest_name, "wb");
  200. ucon64_fwrite (&header, 0, sizeof (st_lnx_header_t), dest_name, "r+b");
  201. printf (ucon64_msg[WROTE], dest_name);
  202. return 0;
  203. }
  204. static int
  205. lynx_b (st_rominfo_t *rominfo, int bank, const char *value)
  206. {
  207. st_lnx_header_t header;
  208. short int *bankvar;
  209. char dest_name[FILENAME_MAX];
  210. if (!rominfo->buheader_len)
  211. {
  212. fprintf (stderr, "ERROR: This is no LNX file\n\n");
  213. return -1;
  214. }
  215. ucon64_fread (&header, 0, sizeof (st_lnx_header_t), ucon64.rom);
  216. bankvar = (bank == 0 ? &header.page_size_bank0 : &header.page_size_bank1);
  217. if ((atol (value) % 64) != 0 || (atol (value) > 512))
  218. *bankvar = 0;
  219. else
  220. #ifdef WORDS_BIGENDIAN
  221. *bankvar = bswap_16 (atol (value) * 4);
  222. #else
  223. *bankvar = atol (value) * 4;
  224. #endif
  225. strcpy (dest_name, ucon64.rom);
  226. ucon64_file_handler (dest_name, NULL, 0);
  227. fcopy (ucon64.rom, 0, ucon64.file_size, dest_name, "wb");
  228. ucon64_fwrite (&header, 0, sizeof (st_lnx_header_t), dest_name, "r+b");
  229. printf (ucon64_msg[WROTE], dest_name);
  230. return 0;
  231. }
  232. int
  233. lynx_b0 (st_rominfo_t *rominfo, const char *value)
  234. {
  235. return lynx_b (rominfo, 0, value);
  236. }
  237. int
  238. lynx_b1 (st_rominfo_t *rominfo, const char *value)
  239. {
  240. return lynx_b (rominfo, 1, value);
  241. }
  242. int
  243. lynx_init (st_rominfo_t *rominfo)
  244. {
  245. int result = -1;
  246. rominfo->console_usage = lynx_usage[0].help;
  247. rominfo->copier_usage = unknown_usage[0].help;
  248. ucon64_fread (&lnx_header, 0, LNX_HEADER_LEN, ucon64.rom);
  249. if (!strncmp (lnx_header.magic, "LYNX", 4))
  250. result = 0;
  251. else
  252. result = -1;
  253. if (ucon64.console == UCON64_LYNX)
  254. result = 0;
  255. if (!strncmp (lnx_header.magic, "LYNX", 4))
  256. {
  257. rominfo->buheader_len = UCON64_ISSET (ucon64.buheader_len) ?
  258. ucon64.buheader_len : (int) LNX_HEADER_LEN;
  259. if (UCON64_ISSET (ucon64.buheader_len) && !ucon64.buheader_len)
  260. return ucon64.console == UCON64_LYNX ? 0 : result;
  261. ucon64_fread (&lnx_header, 0, LNX_HEADER_LEN, ucon64.rom);
  262. rominfo->buheader = &lnx_header;
  263. // internal ROM name
  264. strcpy (rominfo->name, lnx_header.cartname);
  265. // ROM maker
  266. rominfo->maker = lnx_header.manufname;
  267. // misc stuff
  268. sprintf (rominfo->misc,
  269. "Internal Size: Bank0 %hd Bytes (%.4f Mb)\n"
  270. " Bank1 %hd Bytes (%.4f Mb)\n"
  271. "Version: %hd\n"
  272. "Rotation: %s",
  273. #ifdef WORDS_BIGENDIAN
  274. bswap_16 (lnx_header.page_size_bank0) * 256,
  275. TOMBIT_F (bswap_16 (lnx_header.page_size_bank0) * 256),
  276. bswap_16 (lnx_header.page_size_bank1) * 256,
  277. TOMBIT_F (bswap_16 (lnx_header.page_size_bank1) * 256),
  278. bswap_16 (lnx_header.version),
  279. #else
  280. lnx_header.page_size_bank0 * 256,
  281. TOMBIT_F (lnx_header.page_size_bank0 * 256),
  282. lnx_header.page_size_bank1 * 256,
  283. TOMBIT_F (lnx_header.page_size_bank1 * 256),
  284. lnx_header.version,
  285. #endif
  286. (!lnx_header.rotation) ? "No" : ((lnx_header.rotation == 1) ? "Left" : "Right"));
  287. }
  288. return result;
  289. }