/************************************************************************** * * (C) 1998 by Marcin Dalecki <dalecki@cs.net.pl> * * This file is part of the okicrack. * * MARCIN DALECKI ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE * ANY OF THIS SOFTWARE . THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY * OF ANY KIND, AND MARCIN DALECKI EXPRESSLY DISCLAIMS ALL IMPLIED * WARRANTIES, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * **************************************************************************/ /* * The only purpose of this program is to document the protocal * used by the OKI4w GDI printer to transfer the data from the computer * to the printer. * * It's simple like hell! * The only thing, which took me significant time (4h) to find out was the * compression mechanism used by it. * * All the units and value settings are modelled after those provided by * Windows-NT. */ #include <stdio.h> #include <string.h> /* * This accounts for 600 dpi data for 64*40 dots on the engines led line */ #define WIDTH 5120 static int reverse(int n) { int i; int mask = 0x80; int put = 0x01; int result = 0x00; for (i = 0; i < 8; ++i) { if (n & mask) result |= put; mask >>= 1; put <<= 1; } return result; } int render(char *name) { FILE *fd; unsigned char buf[5120]; int ch; char *paper; char *weight; char *source; char *darkness; char *render; long page_start; int lines; int page; printf("PROCESSING: %s\n", name); fd = fopen(name, "r"); if (!fd) { puts("Can't open file"); return 1; } /* * Read the paper feed command and the magic header. */ fread(buf, 1, 17, fd); if (memcmp(buf, "\033&B\033\%-98765X\034\024\003Ai", 17)) { fprintf(stderr, "This isn't a RIP file or maybe the formats are slightly different!\n"); exit(1); } /* * Paper weight information. */ fread(buf, 1, 1, fd); switch (*buf) { case 16: weight = "medium heavy"; break; case 17: weight = "heavy"; break; case 18: weight = "very heavy"; break; case 19: weight = "medium"; break; case 20: weight = "light"; break; default: printf("weight code: %d\n", *buf); weight = "unknown"; } printf("weight: \t%s\n", weight); /* * Get some unknown information. */ fread(buf, 1, 5, fd); if (memcmp(buf, "\034\024\007Ba", 5)) { fprintf(stderr, "This isn't a RIP file or maybe the formats are slightly different!\n"); exit(1); } /* * Darkness information */ fread(buf, 1, 1, fd); switch (*buf) { case 0: darkness = "medium"; break; case 1: darkness = "medium dark"; break; case 2: darkness = "dark"; break; case 3: darkness = "medium light"; break; case 4: darkness = "light"; break; default: printf("darkness code: %d\n", *buf); darkness = "unknown"; } printf("darkness: \t%s\n", darkness); /* * Render information */ fread(buf, 1, 3, fd); if (memcmp(buf, "b\002c", 3)) { fprintf(stderr, "This isn't a RIP file or maybe the formats are slightly different!\n"); exit(1); } fread(buf, 1, 1, fd); switch (*buf) { case 000: render = "text"; break; case 001: render = "graphics"; break; default: printf("render code: %d\n", *buf); render = "unknown"; } printf("render: \t%s\n", render); /* * Get some unknown data... */ fread(buf, 1, 3, fd); if (memcmp(buf, "\034\177\000", 3)) { fprintf(stderr, "This isn't a RIP file or maybe the formats are slightly different!\n"); exit(1); } /* * Paper source information */ fread(buf, 1, 5, fd); if (memcmp(buf, "\033&A\001\000", 5)) { fprintf(stderr, "No paper source information found!\n"); exit(1); } fread(buf, 1, 1, fd); switch (*buf) { case 001: source = "automatic"; break; case 002: source = "manual"; break; default: printf("source code: %d\n", *buf); source = "unknown"; } printf("source: \t%s\n", source); /* * Get paper size information... */ fread(buf, 1, 5, fd); if (memcmp(buf, "\033&A\002\000", 5)) { fprintf(stderr, "No paper size specification found!\n"); exit(1); } fread(buf, 1, 2, fd); switch (buf[1] + 256 * buf[0]) { case 1: paper = "executive"; break; case 2: paper = "letter"; break; case 3: paper = "legal"; break; case 24: paper = "A6"; break; case 25: paper = "A5"; break; case 26: paper = "A4"; break; case 100: paper = "B5"; break; case 258: paper = "209x296mm"; break; case 592: paper = "monarch"; break; case 593: paper = "envelop #10"; break; case 602: paper = "envelop DL"; break; case 603: paper = "C5"; break; default: printf("size code: %d\n", buf[1] + 256 * buf[0]); paper = "unknown"; } printf("size: \t\t%s\n", paper); fread(buf, 1, 8, fd); if (memcmp(buf, "\033&A\003\000\000\000\001", 8)) { fprintf(stderr, "Unknown 2!\n"); exit(1); } /* * Read resolution data */ fread(buf, 1, 9, fd); if (memcmp(buf, "\033&A\007\000\000\000\000\000", 9)) { fprintf(stderr, "No resolution data found!\n"); exit(1); } fread(buf, 1, 2, fd); printf("resolution: \t"); if (buf[0] == 7 && buf[1] == 7) printf("600x600dpi\n"); else if (buf[0] = 3 && buf[1] == 3) printf("150x150dpi\n"); else printf("unknown %dx%dcode\n", buf[0], buf[1]); fread(buf, 1, 1, fd); if (memcmp(buf, "\000", 1)) { fprintf(stderr, "No terminator found\n"); exit(1); } /* * Read the actual image data page by page! */ page = 0; for (;;) { int lines; FILE *out; /* * First scan the number of lines we will need. */ lines = 0; /* Read the page start marker! */ fread(buf, 1, 3, fd); if (!memcmp(buf, "\033$A", 3)) { fread(buf, 1, 6, fd); if (memcmp(buf, "\033!A\000\000\020", 6)) { fprintf(stderr, "Ill formed page start marker found!\n"); exit(1); } } else if (!memcmp(buf, "\033&B", 3)) { /* end of printed text we are ready with this pass */ return 0; } else { fprintf(stderr, "No page start found!\n"); fprintf(stderr, "%02x %c %c\n", buf[0], buf[1], buf[2]); exit(1); } page_start = ftell(fd); /* remember page start */ /* * Now count the number of bit lines. */ lines = 0; for (;;) { fread(buf, 1, 3, fd); if (!memcmp(buf, "\033$B", 3)) { /* end of page data */ break; } else if (!memcmp(buf, "\033*B", 3)) { /* insert n blank lines */ int n; fread(buf, 1, 2, fd); n = 0x100 * buf[1] + buf[0]; lines += n; } else if (!memcmp(buf, "\033*A", 3)) { /* raster line data */ int n; fread(buf, 1, 3, fd); if (buf[0] != '\002') { fprintf(stderr, "Unknown compression method!\n"); exit(1); } ++lines; n = 0x100 * buf[2] + buf[1]; fread(buf, 1, n, fd); } else { fprintf(stderr, "Unknown escape sequence found!\n"); exit(1); } } /* * Output the data in the second pass and complete parsing. */ fseek(fd, page_start, SEEK_SET); sprintf(buf, "page%d.xbm", page); printf("generating: %s\n", buf); out = fopen(buf, "w+"); if (!out) printf("BANG\n"); fprintf(out, "#define page%d_width %d\n", page, WIDTH); fprintf(out, "#define page%d_height %d \n", page, lines); fprintf(out, "static unsigned char page_bits[] = {"); lines = 0; for (;;) { fread(buf, 1, 3, fd); if (!memcmp(buf, "\033$B", 3)) { /* end of page data */ fprintf(out, "};\n"); ++page; fclose(out); break; } else if (!memcmp(buf, "\033*B", 3)) { /* insert n blank lines */ int n; int i; fread(buf, 1, 2, fd); n = 0x100 * buf[1] + buf[0]; lines += n; for (i = 0; i < n; ++i) { int j; fprintf(out, "\n "); for (j = 0; j < WIDTH / 8; ++j) fprintf(out, "0x00, "); } } else if (!memcmp(buf, "\033*A", 3)) { /* raster line data */ int i; int c; int len; int sum; // printf("---\n"); fread(buf, 1, 3, fd); if (buf[0] != '\002') { fprintf(stderr, "Unknown compression method!\n"); exit(1); } ++lines; fprintf(out, "\n "); c = 0; len = 0x100 * buf[2] + buf[1]; fread(buf, 1, len, fd); c = 0; i = 0; sum = 0; while (i < len) { int n; n = buf[i]; ++i; if (n <= 127) { int j; printf("%d != %0.2x %0.3d-\n", lines, buf[i], n + 1); sum += n + 1; for (j = 0; j <= n; ++j) { if (c < WIDTH / 8) fprintf(out, "0x%02x, ", reverse(buf[i + j])); ++c; } i += (n + 1); } else { int j; printf("%d == %0.2x %0.3d-\n", lines, buf[i], 256 - n + 1); sum += 256 - n + 1; for (j = 0; j <= (256 - n); ++j) { if (c < WIDTH / 8) fprintf(out, "0x%02x, ", reverse(buf[i])); ++c; } ++i; } } printf("SUM: %d %d\n", sum, len); while (c < WIDTH / 8) { fprintf(out, "0x00, "); ++c; } } else { fprintf(stderr, "Unknown escape sequence found!\n"); exit(1); } } } return 0; } int main(int argc, char *argv[]) { int i; if (argc < 2) { puts("Usage: oki4linux 'filename' ..."); return 1; } for (i = 1; i < argc; ++i) { render(argv[i]); } }