--- /dev/null
+/* VRL run-length debugging tool.\r
+ *\r
+ * For sparky4 / Project 16 and anyone else needing to debug the VRL structure */\r
+\r
+#include <stdio.h>\r
+#include <fcntl.h>\r
+#include <ctype.h>\r
+#include <errno.h>\r
+#include <assert.h>\r
+#include <stdint.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+\r
+#include "src/lib/doslib/hw/vga/vrl.h"\r
+#include "src/lib/doslib/hw/vga/vrs.h"\r
+#include "src/lib/doslib/hw/vga/pcxfmt.h"\r
+#include "src/lib/doslib/hw/vga/comshtps.h"\r
+\r
+#ifndef O_BINARY\r
+#define O_BINARY (0)\r
+#endif\r
+\r
+static void help() {\r
+ fprintf(stderr,"VRLDBG (C) 2016 Jonathan Campbell\n");\r
+ fprintf(stderr,"\n");\r
+ fprintf(stderr,"vrldbg file\n");\r
+}\r
+\r
+int main(int argc,char **argv) {\r
+ unsigned char *base,*raw,*fence;\r
+ struct vrl1_vgax_header *hdr;\r
+ unsigned int x,y,cc;\r
+ size_t rawlen;\r
+ long l;\r
+ int fd;\r
+\r
+ if (argc < 2) {\r
+ help();\r
+ return 1;\r
+ }\r
+\r
+ fd = open(argv[1],O_RDONLY|O_BINARY);\r
+ if (fd < 0) return 1;\r
+ l = (long)lseek(fd,0,SEEK_END);\r
+ if (l < 16 || l > VRL_MAX_SIZE) return 1;\r
+ rawlen = (size_t)l;\r
+\r
+ base = raw = malloc(rawlen);\r
+ if (raw == NULL) return 1;\r
+ if (lseek(fd,0,SEEK_SET) != 0) return 1;\r
+ if (read(fd,raw,rawlen) != rawlen) return 1;\r
+ close(fd);\r
+ fence = raw + rawlen;\r
+\r
+ hdr = (struct vrl1_vgax_header*)raw;\r
+ if (memcmp(hdr->vrl_sig,"VRL1",4)) return 1;\r
+ if (memcmp(hdr->fmt_sig,"VGAX",4)) return 1;\r
+\r
+#if 0\r
+#pragma pack(push,1)\r
+struct vrl1_vgax_header {\r
+ uint8_t vrl_sig[4]; // +0x00 "VRL1"\r
+ uint8_t fmt_sig[4]; // +0x04 "VGAX"\r
+ uint16_t height; // +0x08 Sprite height\r
+ uint16_t width; // +0x0A Sprite width\r
+ int16_t hotspot_x; // +0x0C Hotspot offset (X) for programmer's reference\r
+ int16_t hotspot_y; // +0x0E Hotspot offset (Y) for programmer's reference\r
+}; // =0x10\r
+#pragma pack(pop)\r
+#endif\r
+ printf("VRL header:\n");\r
+ printf(" vrl_sig: \"VRL1\"\n"); // already validated\r
+ printf(" fmt_sig: \"VGAX\"\n"); // already validated\r
+ printf(" height: %u pixels\n",hdr->height);\r
+ printf(" width: %u pixels\n",hdr->width);\r
+ printf(" hotspot_x: %d pixels\n",hdr->hotspot_x);\r
+ printf(" hotspot_y: %d pixels\n",hdr->hotspot_y);\r
+\r
+ /* strips are encoded in column order, top to bottom.\r
+ * each column ends with a special code, which is a cue to begin the next column and decode more.\r
+ * each strip has a length and a skip count. the skip count is there to allow for sprite\r
+ * transparency by skipping pixels.\r
+ *\r
+ * the organization of this format is optimized for display on VGA hardware in "mode x"\r
+ * unchained 256-color mode (where the planar memory organization of the VGA is exposed) */\r
+ raw = base + sizeof(*hdr);\r
+ for (x=0;x < hdr->width;x++) {/* for each column */\r
+ printf("Begin column x=%u\n",x);\r
+ y=0;\r
+\r
+ if (raw >= fence) {\r
+ printf("* unexpected end of data\n");\r
+ break;\r
+ }\r
+\r
+ /* each column is a series of vertical strips with a two byte header, until\r
+ * the first occurrence where the first byte is 0xFF. */\r
+ do {\r
+ if (raw >= fence) {\r
+ printf("* unexpected end of data in column x=%u at y=%u\n",x,y);\r
+ break;\r
+ }\r
+\r
+ if (*raw == 0xFF) {/* end of column */\r
+ raw++;\r
+ break;\r
+ }\r
+\r
+ if (*raw >= 0x80) { /* single-color run */\r
+ if ((raw+3) > fence) {\r
+ printf("* unexpected end of data in column x=%u at y=%u with %u byte(s) left\n",x,y,(unsigned int)(fence-raw));\r
+ break;\r
+ }\r
+\r
+ {\r
+ /* <run length + 0x80)> <skip length> <color value> */\r
+ unsigned char strip_len = (*raw++) - 0x80;\r
+ unsigned char skip_len = (*raw++);\r
+ unsigned char color = (*raw++);\r
+\r
+ printf(" y=%u. after skip, y=%u. single-color strip length=%u + skip=%u with color=0x%02x\n",\r
+ y,y+skip_len,strip_len,skip_len,color);\r
+\r
+ y += strip_len + skip_len;\r
+ }\r
+ }\r
+ else { /* copy strip */\r
+ if ((raw+2) > fence) {\r
+ printf("* unexpected end of data in column x=%u at y=%u with %u byte(s) left\n",x,y,(unsigned int)(fence-raw));\r
+ break;\r
+ }\r
+\r
+ {\r
+ /* <run length> <skip length> [strip of pixels] */\r
+ unsigned char strip_len = (*raw++);\r
+ unsigned char skip_len = (*raw++);\r
+\r
+ printf(" y=%u. after skip, y=%u. strip length=%u + skip=%u\n",\r
+ y,y+skip_len,strip_len,skip_len);\r
+\r
+ if ((raw+strip_len) > fence) {\r
+ printf("* unexpected end of data in strip x=%u at y=%u with %u byte(s) left\n",x,y,(unsigned int)(fence-raw));\r
+ break;\r
+ }\r
+\r
+ if (strip_len != 0) {\r
+ printf(" pixels: ");\r
+ for (cc=0;cc < strip_len;cc++) printf("0x%02x ",raw[cc]);\r
+ printf("\n");\r
+ }\r
+\r
+ y += strip_len + skip_len;\r
+ raw += strip_len;\r
+ }\r
+ }\r
+ } while(1);\r
+\r
+ if (y > hdr->height)\r
+ printf("* warning: y coordinate y=%u overruns height of VRL height=%u\n",(unsigned int)y,(unsigned int)hdr->height);\r
+ }\r
+\r
+ if (raw < fence) {\r
+ printf("* warning: %u bytes remain after decoding\n",(unsigned int)(fence-raw));\r
+ }\r
+\r
+ free(base);\r
+ return 0;\r
+}\r