1/*
2 * "$Id: print-escp2-data.c,v 1.273 2010/08/04 00:33:56 rlk Exp $"
3 *
4 *   Print plug-in EPSON ESC/P2 driver for the GIMP.
5 *
6 *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
7 *	Robert Krawitz (rlk@alum.mit.edu)
8 *
9 *   This program is free software; you can redistribute it and/or modify it
10 *   under the terms of the GNU General Public License as published by the Free
11 *   Software Foundation; either version 2 of the License, or (at your option)
12 *   any later version.
13 *
14 *   This program is distributed in the hope that it will be useful, but
15 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 *   for more details.
18 *
19 *   You should have received a copy of the GNU General Public License
20 *   along with this program; if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27#include <gutenprint/gutenprint.h>
28#include "gutenprint-internal.h"
29#include <gutenprint/gutenprint-intl-internal.h>
30#include "print-escp2.h"
31#include <limits.h>
32
33typedef struct
34{
35  const char *attr_name;
36  short bit_shift;
37  short bit_width;
38} escp2_printer_attr_t;
39
40static const escp2_printer_attr_t escp2_printer_attrs[] =
41{
42  { "command_mode",		0, 4 },
43  { "zero_margin",		4, 3 },
44  { "variable_mode",		7, 1 },
45  { "graymode",		 	8, 1 },
46  { "fast_360",			9, 1 },
47  { "send_zero_advance",       10, 1 },
48  { "supports_ink_change",     11, 1 },
49  { "packet_mode",             12, 1 },
50  { "interchangeable_ink",     13, 1 },
51  { "envelope_landscape",      14, 1 },
52};
53
54static stpi_escp2_printer_t *escp2_model_capabilities;
55
56static int escp2_model_count = 0;
57
58static void
59load_model_from_file(const stp_vars_t *v, stp_mxml_node_t *xmod, int model)
60{
61  stp_mxml_node_t *tmp = xmod->child;
62  stpi_escp2_printer_t *p = stp_escp2_get_printer(v);
63  int found_black_head_config = 0;
64  int found_fast_head_config = 0;
65  p->max_black_resolution = -1;
66  p->cd_x_offset = -1;
67  p->cd_y_offset = -1;
68  p->duplex_left_margin = SHRT_MIN;
69  p->duplex_right_margin = SHRT_MIN;
70  p->duplex_top_margin = SHRT_MIN;
71  p->duplex_bottom_margin = SHRT_MIN;
72  while (tmp)
73    {
74      if (tmp->type == STP_MXML_ELEMENT)
75	{
76	  const char *name = tmp->value.element.name;
77	  const char *target = stp_mxmlElementGetAttr(tmp, "src");
78	  if (target)
79	    {
80	      if (!strcmp(name, "media"))
81		stp_escp2_load_media(v, target);
82	      else if (!strcmp(name, "inputSlots"))
83		stp_escp2_load_input_slots(v, target);
84	      else if (!strcmp(name, "mediaSizes"))
85		stp_escp2_load_media_sizes(v, target);
86	      else if (!strcmp(name, "printerWeaves"))
87		stp_escp2_load_printer_weaves(v, target);
88	      else if (!strcmp(name, "qualityPresets"))
89		stp_escp2_load_quality_presets(v, target);
90	      else if (!strcmp(name, "resolutions"))
91		stp_escp2_load_resolutions(v, target);
92	      else if (!strcmp(name, "inkGroup"))
93		stp_escp2_load_inkgroup(v, target);
94	    }
95	  else if (tmp->child && tmp->child->type == STP_MXML_TEXT)
96	    {
97	      stp_mxml_node_t *child = tmp->child;
98	      const char *val = child->value.text.string;
99	      if (!strcmp(name, "verticalBorderlessSequence"))
100		{
101		  STPI_ASSERT(!p->vertical_borderless_sequence, NULL);
102		  p->vertical_borderless_sequence = stp_xmlstrtoraw(val);
103		}
104	      else if (!strcmp(name, "preinitSequence"))
105		{
106		  STPI_ASSERT(!p->preinit_sequence, NULL);
107		  p->preinit_sequence = stp_xmlstrtoraw(val);
108		}
109	      else if (!strcmp(name, "preinitRemoteSequence"))
110		{
111		  STPI_ASSERT(!p->preinit_remote_sequence, NULL);
112		  p->preinit_remote_sequence = stp_xmlstrtoraw(val);
113		}
114	      else if (!strcmp(name, "postinitRemoteSequence"))
115		{
116		  STPI_ASSERT(!p->postinit_remote_sequence, NULL);
117		  p->postinit_remote_sequence = stp_xmlstrtoraw(val);
118		}
119	      else if (!strcmp(name, "commandSet"))
120		{
121		  if (!strcmp(val, "1998"))
122		    p->flags |= MODEL_COMMAND_1998;
123		  else if (!strcmp(val, "1999"))
124		    p->flags |= MODEL_COMMAND_1999;
125		  else if (!strcmp(val, "2000"))
126		    p->flags |= MODEL_COMMAND_2000;
127		  else if (!strcmp(val, "Pro"))
128		    p->flags |= MODEL_COMMAND_PRO;
129		}
130	      else if (!strcmp(name, "borderless"))
131		{
132		  if (!strcmp(val, "No"))
133		    p->flags |= MODEL_ZEROMARGIN_NO;
134		  else if (!strcmp(val, "Yes"))
135		    p->flags |= MODEL_ZEROMARGIN_YES;
136		  else if (!strcmp(val, "Full"))
137		    p->flags |= MODEL_ZEROMARGIN_FULL;
138		  else if (!strcmp(val, "VerticalRestricted"))
139		    p->flags |= MODEL_ZEROMARGIN_RESTR;
140		  else if (!strcmp(val, "HorizontalOnly"))
141		    p->flags |= MODEL_ZEROMARGIN_H_ONLY;
142		}
143	      else if (!strcmp(name, "preferredEnvelopeOrientation") &&
144		       !strcmp(val, "Landscape"))
145		p->flags |= MODEL_ENVELOPE_LANDSCAPE_YES;
146	      else if (!strcmp(name, "headConfiguration"))
147		{
148		  const char *htype = stp_mxmlElementGetAttr(tmp, "type");
149		  unsigned long data[4] = { 0, 0, 0, 0 };
150		  while (child)
151		    {
152		      if (child->type == STP_MXML_ELEMENT && child->child &&
153			  child->child->type == STP_MXML_TEXT)
154			{
155			  const char *cname = child->value.element.name;
156			  const char *cval = child->child->value.text.string;
157			  if (!strcmp(cname, "Nozzles"))
158			    data[0] = stp_xmlstrtoul(cval);
159			  else if (!strcmp(cname, "MinNozzles"))
160			    data[1] = stp_xmlstrtoul(cval);
161			  else if (!strcmp(cname, "FirstNozzle"))
162			    data[2] = stp_xmlstrtoul(cval);
163			  else if (!strcmp(cname, "NozzleSeparation"))
164			    data[3] = stp_xmlstrtoul(cval);
165			}
166		      child = child->next;
167		    }
168		  if (!strcmp(htype, "default"))
169		    {
170		      p->nozzles = data[0];
171		      p->min_nozzles = data[1];
172		      p->nozzle_start = data[2];
173		      p->nozzle_separation = data[3];
174		      if (!found_black_head_config)
175			{
176			  p->black_nozzles = data[0];
177			  p->min_black_nozzles = data[1];
178			  p->black_nozzle_start = data[2];
179			  p->black_nozzle_separation = data[3];
180			}
181		      if (!found_fast_head_config)
182			{
183			  p->fast_nozzles = data[0];
184			  p->min_fast_nozzles = data[1];
185			  p->fast_nozzle_start = data[2];
186			  p->fast_nozzle_separation = data[3];
187			}
188		    }
189		  else if (!strcmp(htype, "black"))
190		    {
191		      p->black_nozzles = data[0];
192		      p->min_black_nozzles = data[1];
193		      p->black_nozzle_start = data[2];
194		      p->black_nozzle_separation = data[3];
195		      found_black_head_config = 1;
196		    }
197		  else if (!strcmp(htype, "fast"))
198		    {
199		      p->fast_nozzles = data[0];
200		      p->min_fast_nozzles = data[1];
201		      p->fast_nozzle_start = data[2];
202		      p->fast_nozzle_separation = data[3];
203		      found_fast_head_config = 1;
204		    }
205		}
206	      else if (!strcmp(name, "margins"))
207		{
208		  const char *itype = stp_mxmlElementGetAttr(tmp, "interleave");
209		  const char *mtype = stp_mxmlElementGetAttr(tmp, "media");
210		  const char *dtype = stp_mxmlElementGetAttr(tmp, "duplex");
211		  unsigned long data[4];
212		  int i = 0;
213		  while (child && i < 4)
214		    {
215		      if (child->type == STP_MXML_TEXT)
216			data[i++] = stp_xmlstrtoul(child->value.text.string);
217		      child = child->next;
218		    }
219		  if (dtype && !strcmp(dtype, "duplex"))
220		    {
221		      p->duplex_left_margin = data[0];
222		      p->duplex_right_margin = data[1];
223		      p->duplex_top_margin = data[2];
224		      p->duplex_bottom_margin = data[3];
225		    }
226		  else if (itype && !strcmp(itype, "soft") &&
227			   mtype && !strcmp(mtype, "sheet"))
228		    {
229		      p->left_margin = data[0];
230		      p->right_margin = data[1];
231		      p->top_margin = data[2];
232		      p->bottom_margin = data[3];
233		    }
234		  else if (itype && !strcmp(itype, "printer") &&
235			   mtype && !strcmp(mtype, "sheet"))
236		    {
237		      p->m_left_margin = data[0];
238		      p->m_right_margin = data[1];
239		      p->m_top_margin = data[2];
240		      p->m_bottom_margin = data[3];
241		    }
242		  else if (itype && !strcmp(itype, "soft") &&
243			   mtype && !strcmp(mtype, "roll"))
244		    {
245		      p->roll_left_margin = data[0];
246		      p->roll_right_margin = data[1];
247		      p->roll_top_margin = data[2];
248		      p->roll_bottom_margin = data[3];
249		    }
250		  else if (itype && !strcmp(itype, "printer") &&
251			   mtype && !strcmp(mtype, "roll"))
252		    {
253		      p->m_roll_left_margin = data[0];
254		      p->m_roll_right_margin = data[1];
255		      p->m_roll_top_margin = data[2];
256		      p->m_roll_bottom_margin = data[3];
257		    }
258		}
259	      else if (!strcmp(name, "physicalChannels"))
260		p->physical_channels = stp_xmlstrtoul(val);
261	      else if (!strcmp(name, "baseSeparation"))
262		p->base_separation = stp_xmlstrtoul(val);
263	      else if (!strcmp(name, "resolutionScale"))
264		p->resolution_scale = stp_xmlstrtoul(val);
265	      else if (!strcmp(name, "maxBlackResolution"))
266		p->max_black_resolution = stp_xmlstrtoul(val);
267	      else if (!strcmp(name, "minimumResolution"))
268		{
269		  p->min_hres = stp_xmlstrtoul(child->value.text.string);
270		  child = child->next;
271		  p->min_vres = stp_xmlstrtoul(child->value.text.string);
272		}
273	      else if (!strcmp(name, "maximumResolution"))
274		{
275		  p->max_hres = stp_xmlstrtoul(child->value.text.string);
276		  child = child->next;
277		  p->max_vres = stp_xmlstrtoul(child->value.text.string);
278		}
279	      else if (!strcmp(name, "extraVerticalFeed"))
280		p->extra_feed = stp_xmlstrtoul(val);
281	      else if (!strcmp(name, "separationRows"))
282		p->separation_rows = stp_xmlstrtoul(val);
283	      else if (!strcmp(name, "pseudoSeparationRows"))
284		p->pseudo_separation_rows = stp_xmlstrtoul(val);
285	      else if (!strcmp(name, "zeroMarginOffset"))
286		p->zero_margin_offset = stp_xmlstrtoul(val);
287	      else if (!strcmp(name, "microLeftMargin"))
288		p->micro_left_margin = stp_xmlstrtoul(val);
289	      else if (!strcmp(name, "initialVerticalOffset"))
290		p->initial_vertical_offset = stp_xmlstrtoul(val);
291	      else if (!strcmp(name, "blackInitialVerticalOffset"))
292		p->black_initial_vertical_offset = stp_xmlstrtoul(val);
293	      else if (!strcmp(name, "extra720DPISeparation"))
294		p->extra_720dpi_separation = stp_xmlstrtoul(val);
295	      else if (!strcmp(name, "minHorizontalAlignment"))
296		p->min_horizontal_position_alignment = stp_xmlstrtoul(val);
297	      else if (!strcmp(name, "baseHorizontalAlignment"))
298		p->base_horizontal_position_alignment = stp_xmlstrtoul(val);
299	      else if (!strcmp(name, "bidirectionalAutoUpperLimit"))
300		p->bidirectional_upper_limit = stp_xmlstrtoul(val);
301	      else if (!strcmp(name, "minimumMediaSize"))
302		{
303		  p->min_paper_width = stp_xmlstrtoul(child->value.text.string);
304		  child = child->next;
305		  p->min_paper_height = stp_xmlstrtoul(child->value.text.string);
306		}
307	      else if (!strcmp(name, "maximumMediaSize"))
308		{
309		  p->max_paper_width = stp_xmlstrtoul(child->value.text.string);
310		  child = child->next;
311		  p->max_paper_height = stp_xmlstrtoul(child->value.text.string);
312		}
313	      else if (!strcmp(name, "maximumImageableArea"))
314		{
315		  p->max_imageable_width = stp_xmlstrtoul(child->value.text.string);
316		  child = child->next;
317		  p->max_imageable_height = stp_xmlstrtoul(child->value.text.string);
318		}
319	      else if (!strcmp(name, "CDOffset"))
320		{
321		  p->cd_x_offset = stp_xmlstrtoul(child->value.text.string);
322		  child = child->next;
323		  p->cd_y_offset = stp_xmlstrtoul(child->value.text.string);
324		}
325	      else if (!strcmp(name, "CDMediaSize"))
326		{
327		  p->cd_page_width = stp_xmlstrtoul(child->value.text.string);
328		  child = child->next;
329		  p->cd_page_height = stp_xmlstrtoul(child->value.text.string);
330		}
331	      else if (!strcmp(name, "extraBottom"))
332		p->paper_extra_bottom = stp_xmlstrtoul(val);
333	      else if (!strcmp(name, "AlignmentChoices"))
334		{
335		  p->alignment_passes =
336		    stp_xmlstrtoul(child->value.text.string);
337		  child = child->next;
338		  p->alignment_choices =
339		    stp_xmlstrtoul(child->value.text.string);
340		  child = child->next;
341		  p->alternate_alignment_passes =
342		    stp_xmlstrtoul(child->value.text.string);
343		  child = child->next;
344		  p->alternate_alignment_choices =
345		    stp_xmlstrtoul(child->value.text.string);
346		}
347	      else if (!strcmp(name, "ChannelNames"))
348		{
349		  p->channel_names = stp_string_list_create();
350		  while (child)
351		    {
352		      if (child->type == STP_MXML_ELEMENT &&
353			  !strcmp(child->value.element.name, "ChannelName"))
354			{
355			  const char *cname = stp_mxmlElementGetAttr(child, "name");
356			  stp_string_list_add_string(p->channel_names, cname, cname);
357			}
358		      child = child->next;
359		    }
360		}
361	      else if (!strcmp(name, "resolutions"))
362		stp_escp2_load_resolutions_from_xml(v, tmp);
363	    }
364	  else
365	    {
366	      if (!strcmp(name, "supportsVariableDropsizes"))
367		p->flags |= MODEL_VARIABLE_YES;
368	      else if (!strcmp(name, "hasFastGraymode"))
369		p->flags |= MODEL_GRAYMODE_YES;
370	      else if (!strcmp(name, "hasFast360DPI"))
371		p->flags |= MODEL_FAST_360_YES;
372	      else if (!strcmp(name, "sendZeroAdvance"))
373		p->flags |= MODEL_SEND_ZERO_ADVANCE_YES;
374	      else if (!strcmp(name, "supportsInkChange"))
375		p->flags |= MODEL_SUPPORTS_INK_CHANGE_YES;
376	      else if (!strcmp(name, "supportsD4Mode"))
377		p->flags |= MODEL_PACKET_MODE_YES;
378	      else if (!strcmp(name, "hasInterchangeableInkCartridges"))
379		p->flags |= MODEL_INTERCHANGEABLE_INK_YES;
380	      else if (!strcmp(name, "resolutions"))
381		stp_escp2_load_resolutions_from_xml(v, tmp);
382	    }
383	}
384      tmp = tmp->next;
385    }
386}
387
388void
389stp_escp2_load_model(const stp_vars_t *v, int model)
390{
391  stp_list_t *dirlist = stpi_data_path();
392  stp_list_item_t *item;
393  char buf[1024];
394  int found = 0;
395
396  stp_xml_init();
397  sprintf(buf, "escp2/model/model_%d.xml", model);
398  item = stp_list_get_start(dirlist);
399  while (item)
400    {
401      const char *dn = (const char *) stp_list_item_get_data(item);
402      char *fn = stpi_path_merge(dn, buf);
403      stp_mxml_node_t *doc = stp_mxmlLoadFromFile(NULL, fn, STP_MXML_NO_CALLBACK);
404      stp_free(fn);
405      if (doc)
406	{
407	  stp_mxml_node_t *node =
408	    stp_mxmlFindElement(doc, doc, "escp2:model", NULL, NULL,
409				STP_MXML_DESCEND);
410	  if (node)
411	    {
412	      const char *stmp = stp_mxmlElementGetAttr(node, "id");
413	      STPI_ASSERT(stmp && stp_xmlstrtol(stmp) == model, v);
414	      load_model_from_file(v, node, model);
415	      found = 1;
416	    }
417	  stp_mxmlDelete(doc);
418	  if (found)
419	    break;
420	}
421      item = stp_list_item_next(item);
422    }
423  stp_xml_exit();
424  stp_list_destroy(dirlist);
425  STPI_ASSERT(found, v);
426}
427
428stpi_escp2_printer_t *
429stp_escp2_get_printer(const stp_vars_t *v)
430{
431  int model = stp_get_model_id(v);
432  STPI_ASSERT(model >= 0, v);
433  if (!escp2_model_capabilities)
434    {
435      escp2_model_capabilities =
436	stp_zalloc(sizeof(stpi_escp2_printer_t) * (model + 1));
437      escp2_model_count = model + 1;
438    }
439  else if (model >= escp2_model_count)
440    {
441      escp2_model_capabilities =
442	stp_realloc(escp2_model_capabilities,
443		    sizeof(stpi_escp2_printer_t) * (model + 1));
444      (void) memset(escp2_model_capabilities + escp2_model_count, 0,
445		    sizeof(stpi_escp2_printer_t) * (model + 1 - escp2_model_count));
446      escp2_model_count = model + 1;
447    }
448  if (!(escp2_model_capabilities[model].active))
449    {
450#ifdef HAVE_LOCALE_H
451      char *locale = stp_strdup(setlocale(LC_ALL, NULL));
452      setlocale(LC_ALL, "C");
453#endif
454      escp2_model_capabilities[model].active = 1;
455      stp_escp2_load_model(v, model);
456#ifdef HAVE_LOCALE_H
457      setlocale(LC_ALL, locale);
458      stp_free(locale);
459#endif
460    }
461  return &(escp2_model_capabilities[model]);
462}
463
464model_featureset_t
465stp_escp2_get_cap(const stp_vars_t *v, escp2_model_option_t feature)
466{
467  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
468  model_featureset_t featureset =
469    (((1ul << escp2_printer_attrs[feature].bit_width) - 1ul) <<
470     escp2_printer_attrs[feature].bit_shift);
471  return printdef->flags & featureset;
472}
473
474int
475stp_escp2_has_cap(const stp_vars_t *v, escp2_model_option_t feature,
476		  model_featureset_t class)
477{
478  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
479  model_featureset_t featureset =
480    (((1ul << escp2_printer_attrs[feature].bit_width) - 1ul) <<
481     escp2_printer_attrs[feature].bit_shift);
482  return ((printdef->flags & featureset) == class);
483}
484