1 /* esc-m.c - try to parse minolta pagepro 1200 w printer data files
2  *
3  * Copyright (C) 2004, 2005 Manuel Tobias Schiller <mala@hinterbergen.de>
4  *
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  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 /*
20  * this little program was meant to make understanding the output
21  * of the printer driver easier. i guess it might sometimes still
22  * be useful...
23  *
24  * this is a quick and _dirty_ hack based on looking at the windoze
25  * driver output and some of the windoze driver plaintext files
26  * (most notably msdmlt_c.sdd for the paper format codes - this
27  * file might contain other valuable information I do not understand
28  * yet...)
29  *
30  * this thing may or may not provide you with accurate information
31  * the purpose of some of the data sent to the printer is still not
32  * understood - have a look at format.txt and look for entries which
33  * do not satisfy a curious mind...
34  * the raster data is hex dumped by this utility
35  */
36 
37 #include <stdio.h>
38 
39 /* file position ans sequence number */
40 static int i = 0, sq = 0;
41 /* current resolution */
42 static int gl_res = -1, gl_res_h = -1;
43 /* page dimensions in dots at current resolution */
44 static int gl_x, gl_y;
45 /* paper tray */
46 static int gl_tray = -1;
47 /* paper format */
48 static int gl_pformat = -1;
49 
getdword(unsigned char * data)50 static int getdword(unsigned char *data)
51 {
52 	int retVal;
53 
54 	retVal = ((int) data[1]) << 24;
55 	retVal |= ((int) data[0]) << 16;
56 	retVal |= ((int) data[3]) << 8;
57 	retVal |= ((int) data[2]);
58 
59 	return retVal;
60 }
61 
dumpraw(unsigned char * data)62 static void dumpraw(unsigned char *data)
63 {
64 	int tmp, lb;
65 	/* raw data dump */
66 	printf("ESC %02x: raw data dump:", data[1]);
67 
68 	lb = data[3];
69 	data += 6;
70 
71 	for (tmp = 0; tmp < lb; tmp++) {
72 		if ((tmp & 0xf) == 0) printf("\n\t");
73 		printf("%02x ", (int) *data++);
74 	}
75 	printf("\n\n");
76 }
77 
dump50(unsigned char * data)78 static void dump50(unsigned char *data)
79 {
80 	char *res, *ptype, *rmstr;
81        	unsigned char r, p, rm;
82 	int lb;
83 
84 	lb = data[3];
85 
86 	/* dump ESC 50 data */
87 	printf("ESC 50: select resolution and paper type:\n");
88 
89 	if (lb != 8) {
90 		printf("\tExpected 8 data bytes for ESC 0x50 command, recieved %d.\n", lb);
91 		dumpraw(data);
92 		return;
93 	}
94 	/* we dump the raw data nevertheless to make is easier to spot
95 	 * format changes when Minolta introduces a new model... */
96 	dumpraw(data);
97 
98 	data += 6;
99 
100 	switch (r = *data++) {
101 	case 0:
102 		res = "300 dpi"; gl_res = 300;
103 		break;
104 	case 1:
105 		res = "600 dpi"; gl_res = 600;
106 		break;
107 	case 2:
108 		res = "1200 dpi"; gl_res = 1200;
109 		break;
110 	default:
111 		res = "unknown"; gl_res = -1;
112 		break;
113 	}
114 	switch (rm = *data++) {
115 	case 0:
116 		rmstr = "none";
117 		gl_res_h = gl_res;
118 		break;
119 	case 1:
120 		rmstr = "double horizontal resolution";
121 		gl_res_h = gl_res * 2;
122 		break;
123 	default:
124 		rmstr = "unknown horizontal resolution modifier";
125 		gl_res_h = -1;
126 		break;
127 	}
128 	data += 1; /* next two bytes seem to be don't care data */
129 	switch (p = *data++) {
130 	case 0:
131 		ptype = "normal paper";
132 		break;
133 	case 1:
134 		ptype = "thick paper";
135 		break;
136 	case 2:
137 		ptype = "transparency";
138 		break;
139 	case 3:
140 		ptype = "envelope/postcard";
141 		break;
142 	default:
143 		ptype = "unknown paper";
144 		break;
145 	}
146 	/* next four bytes seem to be don't care data */
147 
148 	printf("\tresolution code %02x (%s)\n", r, res);
149 	printf("\thorizontal resolution modifier: %02x (%s)\n", rm, rmstr);
150 	printf("\teffective resolution is %d x %d dpi\n", gl_res_h, gl_res);
151 	printf("\tpaper code %02x (%s)\n\n", p, ptype);
152 }
153 
dump51(unsigned char * data)154 static void dump51(unsigned char *data)
155 {
156 	unsigned char lb;
157        	char *tray, *pformat;
158 
159 	lb = data[3];
160 
161 	/* dump ESC 51 data */
162 	printf("ESC 51: start new page and set paper format:\n");
163 
164 	if (lb != 22) {
165 		printf("\tExpected 22 data bytes for ESC 0x51 command, recieved %d.\n", lb);
166 		dumpraw(data);
167 		return;
168 	}
169 	/* we dump the raw data nevertheless to make is easier to spot
170 	 * format changes when Minolta introduces a new model... */
171 	dumpraw(data);
172 	data += 6;
173 
174 	data += 2; /* seems to be don't care data */
175 	gl_x = getdword(data); data += 4;
176 	gl_y = getdword(data); data += 4;
177 	data += 4; /* seems to be don't care data */
178 	switch (gl_tray = *data++) {
179 	case 0xff:
180 		tray = "auto"; break;
181 	case 0x00:
182 		tray = "tray 1"; break;
183 	case 0x01:
184 		tray = "tray 2"; break;
185 	case 0x80:
186 		tray = "manual feed"; break;
187 	default:
188 		tray = "unknown"; break;
189 	}
190 	switch (gl_pformat = *data) {
191 	default:
192 		pformat = "unknown"; break;
193 	case 0x04:
194 		pformat = "a4"; break;
195 	case 0x06:
196 		pformat = "b5"; break;
197 	case 0x08:
198 		pformat = "a5"; break;
199 	case 0x0c:
200 		pformat = "j-post"; break;
201 	case 0x0d:
202 		pformat = "cor. post"; break;
203 	case 0x10:
204 		pformat = "jis y6"; break;
205 	case 0x11:
206 		pformat = "jis y0"; break;
207 	case 0x13:
208 		pformat = "chinese 16k"; break;
209 	case 0x15:
210 		pformat = "chinese 32k"; break;
211 	case 0x19:
212 		pformat = "legal"; break;
213 	case 0x1a:
214 		pformat = "g. legal"; break;
215 	case 0x1b:
216 		pformat = "letter"; break;
217 	case 0x1d:
218 		pformat = "g. letter"; break;
219 	case 0x1f:
220 		pformat = "executive"; break;
221 	case 0x21:
222 		pformat = "half letter"; break;
223 	case 0x24:
224 		pformat = "env monarch"; break;
225 	case 0x25:
226 		pformat = "env #10"; break;
227 	case 0x26:
228 		pformat = "env dl"; break;
229 	case 0x27:
230 		pformat = "env c5"; break;
231 	case 0x28:
232 		pformat = "env c6"; break;
233 	case 0x29:
234 		pformat = "env b5"; break;
235 	case 0x2d:
236 		pformat = "choukei-3gou"; break;
237 	case 0x2e:
238 		pformat = "choukei-4gou"; break;
239 	case 0x31:
240 		pformat = "custom"; break;
241 	}
242 	/* rest seems to be don't care data... */
243 
244 	printf("\tpaper format is %02x (%s).\n", gl_pformat, pformat);
245 	printf("\tpage size is %d x %d dots (%.3lf x %.3lf \" or %.2lf x %.2lf mm).\n",
246 		gl_x, gl_y,
247 		(double) gl_x / (double) gl_res_h,
248 		(double) gl_y / (double) gl_res,
249 		25.4 * (double) gl_x / (double) gl_res_h,
250 		25.4 * (double) gl_y / (double) gl_res);
251 	printf("\tpaper tray id %02x (%s)\n\n", gl_tray, tray);
252 }
253 
dump52(unsigned char * data)254 static void dump52(unsigned char *data)
255 {
256 	int tmp2, tmp;
257 	unsigned char lb = data[3];
258 
259 	/* dump ESC 52 data */
260 	printf("ESC 52: send raster data:\n");
261 
262 	if (lb != 6) {
263 		printf("\tExpected 6 data bytes for ESC 0x52 command, recieved %d.\n", lb);
264 		dumpraw(data);
265 		return;
266 	}
267 	data += 6;
268 
269 	/* copy further data bytes */
270 	/* get length out of data array */
271 	tmp2 = data[3]; tmp2 <<= 8;
272 	tmp2 |= data[2]; tmp2 <<= 8;
273 	tmp2 |= data[1]; tmp2 <<= 8;
274 	tmp2 |= data[0];
275 	/* get number of lines */
276 	tmp = data[5]; tmp <<= 8;
277 	tmp |= data[4];
278 	printf("\tdumping %d raster data bytes (%d lines):", tmp2, tmp);
279 	for (tmp = 0; tmp < tmp2; tmp++) {
280 		if ((tmp & 0xf) == 0) printf("\n\t");
281 		printf("%02x ", getchar());
282 		i++;
283 	}
284 	printf("\n\n");
285 }
286 
readesc(unsigned char * data)287 static int readesc(unsigned char *data)
288 {
289 	unsigned char *p = data, lb, ck;
290 
291 	ck = *p = getchar();
292 	if (feof(stdin)) {
293 		printf("Reached EOF at %08x.\n", i);
294 		return -1;
295 	}
296 	if (*p++ != 0x1b) {
297 		printf("Expected start of a ESC sequence at %08x.\n", i);
298 		return -2;
299 	}
300 	i++;
301 	/* cmd byte */
302 	ck += *p++ = getchar(); i++;
303 	ck += *p = getchar();
304 	if (*p != sq++) {
305 		/* ESC 0x51 seems to set sequence numbers, also make
306 		 * concatetnations of print files work */
307 		if ((*p != 0) && (data[1] != 0x51)) {
308 			printf("Sequence error (is %02x, should be %02x) at %08x.\n",
309 				(int) *p, sq - 1, i);
310 			return -3;
311 		} else {
312 			printf("Sequence restarts at %08x.\n", i);
313 			sq = *p + 1;
314 		}
315 	}
316 	p++;
317 	i++;
318 	ck += lb = *p++ = getchar(); i++;
319 	*p = getchar();
320 	if (*p++ != 0) {
321 		printf("Expected zero byte at %08x.\n", i);
322 		return -4;
323 	}
324 	i++;
325 	ck += *p = getchar();
326 	if (*p++ != (~data[1] & 0xff)) {
327 		printf("Command %02x not terminated at %08x.\n", data[1], i);
328 		return -5;
329 	}
330 	i++;
331 
332 	while (lb--) {
333 		ck += *p++ = getchar();
334 		i++;
335 	}
336 
337 	*p = getchar();
338 	if (*p != ck) {
339 		printf("Checksum error at %08x.\n", i);
340 		return -6;
341 	}
342 
343 	return data[1];
344 }
345 
main()346 int main()
347 {
348 	unsigned char data[300];
349 	int c;
350 
351 	while (!feof(stdin)) {
352 		c = readesc(data);
353 		if (c < 0) return c;
354 
355 		switch (c) {
356 		case 0x50:
357 			dump50(data); break;
358 		case 0x51:
359 			dump51(data); break;
360 		case 0x52:
361 			dump52(data); break;
362 		default:
363 			dumpraw(data); break;
364 		}
365 	}
366 
367 	return 0;
368 }
369