1 /*
2  * 	    qpdl.cpp                  (C) 2006-2008, Aurélien Croc (AP²C)
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; version 2 of the License.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the
15  *  Free Software Foundation, Inc.,
16  *  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  *  $Id$
19  *
20  */
21 #include "qpdl.h"
22 #include <errno.h>
23 #include <unistd.h>
24 #include <inttypes.h>
25 #include <string.h>
26 #include "page.h"
27 #include "band.h"
28 #include "errlog.h"
29 #include "request.h"
30 #include "bandplane.h"
31 
_renderBand(const Request & request,const Band * band)32 static bool _renderBand(const Request& request, const Band* band)
33 {
34     unsigned long version, subVersion, compression, size, dataSize, checkSum;
35     bool color, headerSent=false;
36     unsigned char header[0x20];
37     const BandPlane *plane;
38 
39     compression = band->parent()->compression();
40     version = request.printer()->qpdlVersion();
41     color = request.printer()->color();
42     subVersion = compression == 0x13 ? 3 : 0;
43 
44     for (unsigned int i=0; i < band->planesNr(); i++) {
45         bool nextBand = false;
46 
47         // Get the plane
48         plane = band->plane(i);
49         if (!plane) {
50             ERRORMSG(_("Inconsistent data. Operation aborted"));
51             return false;
52         }
53         checkSum = plane->checksum();
54 
55         // Check if there is a next band for that color
56         if (subVersion) {
57             const BandPlane *nextPlane;
58             const Band *next;
59 
60             next = band->sibling();
61             if (next) {
62                 for (unsigned int j=0; j < next->planesNr(); j++) {
63                     nextPlane = next->plane(j);
64                     if (nextPlane && nextPlane->colorNr() == plane->colorNr()){
65                         nextBand = true;
66                         break;
67                     }
68                 }
69             }
70         }
71 
72         // Calculate the data size
73         dataSize = plane->dataSize();
74         dataSize += 4;                  // Data signature
75         if (version > 0) {
76             dataSize += 4;              // Checksum
77             if (subVersion == 3)
78                 dataSize += 7*4;        // Sub-header
79         }
80 
81         // Send the header
82         if (!headerSent || version == 2) {
83             header[0x0] = 0xC;                      // Signature
84             header[0x1] = band->bandNr();           // Band number
85             header[0x2] = band->width() >> 8;       // Band width 8-15
86             header[0x3] = band->width();            // Band width 0-7
87             header[0x4] = band->height() >> 8;      // Band height 8-15
88             header[0x5] = band->height();           // Band height 0-7
89             headerSent = true;
90             size = 0x6;
91         } else
92             size = 0x0;
93             // Add color information if it's a color printer
94         if (color) {
95             header[size] = plane->colorNr();        // Color number
96             size++;
97         }
98             // Append the last information and send the header
99         header[size+0] = compression;               // Compression algorithm
100         header[size+1] = dataSize >> 24;            // Data size 24 - 31
101         header[size+2] = dataSize >> 16;            // Data size 16 - 23
102         header[size+3] = dataSize >> 8;             // Data size 8 - 15
103         header[size+4] = dataSize;                  // Data size 0 - 7
104         if (write(STDOUT_FILENO, (unsigned char*)&header, size+5) == -1) {
105             ERRORMSG(_("Error while sending data to the printer (%u)"), errno);
106             return false;
107         }
108 
109         // Send the sub-header
110         switch (plane->endian()) {
111             case BandPlane::Dependant:
112                 *(uint32_t *)&header = (uint32_t)(0x09ABCDEF +
113                     (subVersion << 28));                // Sub-header signature
114                 break;
115             case BandPlane::BigEndian:
116                 header[0x0] = 0x9 + (subVersion << 0x4);// Sub-header signature1
117                 header[0x1] = 0xAB;                     // Sub-header signature2
118                 header[0x2] = 0xCD;                     // Sub-header signature3
119                 header[0x3] = 0xEF;                     // Sub-header signature4
120                 break;
121             case BandPlane::LittleEndian:
122                 header[0x0] = 0xEF;                     // Sub-header signature4
123                 header[0x1] = 0xCD;                     // Sub-header signature3
124                 header[0x2] = 0xAB;                     // Sub-header signature2
125                 header[0x3] = 0x9 + (subVersion << 0x4);// Sub-header signature1
126                 break;
127         };
128         size = 4;
129         if (subVersion == 3) {
130             uint32_t state;
131 
132             checkSum += 0x39 + 0xAB + 0xCD + 0xEF;
133             if (!band->bandNr())
134                 state = 0x0;                        // First band
135             else if (nextBand) {
136                 state = 0x01000000;                 // Next band available
137                 checkSum += 0x01;
138             } else {
139                 state = 0x02000000;                 // Last band
140                 checkSum += 0x02;
141             }
142             memset(header + size + 4, 0, 6*4);
143 
144             switch (plane->endian()) {
145             case BandPlane::Dependant:
146                 *(uint32_t*)(&header + size) = (uint32_t)plane->dataSize();
147                 *(uint32_t*)(&header + size + 4) = (uint32_t)state;
148                 break;
149             case BandPlane::BigEndian:
150                 header[size+0] = plane->dataSize() >> 24;   // Data size 24 - 31
151                 header[size+1] = plane->dataSize() >> 16;   // Data size 16 - 23
152                 header[size+2] = plane->dataSize() >> 8;    // Data size 8 - 15
153                 header[size+3] = plane->dataSize();         // Data size 0 - 7
154                 header[size+4] = state >> 24;               // State 24 - 31
155                 header[size+5] = state >> 16;               // State 16 - 23
156                 header[size+6] = state >> 8;                // State 8 - 15
157                 header[size+7] = state;                     // State 0 - 7
158                 break;
159             case BandPlane::LittleEndian:
160                 header[size+0] = plane->dataSize();         // Data size 0 - 7
161                 header[size+1] = plane->dataSize() >> 8;    // Data size 8 - 15
162                 header[size+2] = plane->dataSize() >> 16;   // Data size 16 - 23
163                 header[size+3] = plane->dataSize() >> 24;   // Data size 24 - 31
164                 header[size+4] = state;                     // State 0 - 7
165                 header[size+5] = state >> 8;                // State 8 - 15
166                 header[size+6] = state >> 16;               // State 16 - 23
167                 header[size+7] = state >> 24;               // State 24 - 31
168                 break;
169             }
170             for (unsigned int j=0; j < 4; j++)
171                 checkSum += header[size + j];
172             size += 4 + 4 + 5*4;
173         } else
174             for (unsigned int j=0; j < 4; j++)
175                 checkSum += header[size - j - 1];
176         if (write(STDOUT_FILENO, (unsigned char*)&header, size) == -1) {
177             ERRORMSG(_("Error while sending data to the printer (%u)"), errno);
178             return false;
179         }
180 
181         // Send the data
182         if (write(STDOUT_FILENO, plane->data(), plane->dataSize()) == -1) {
183             ERRORMSG(_("Error while sending data to the printer (%u)"), errno);
184             return false;
185         }
186 
187         // Send the checksum
188         header[0] = checkSum >> 24;                 // Checksum 24 - 31
189         header[1] = checkSum >> 16;                 // Checksum 16 - 23
190         header[2] = checkSum >> 8;                  // Checksum 8 - 15
191         header[3] = checkSum;                       // Checksum 0 - 7
192         size = 4;
193             // Close the plane if needed
194         if (color && version == 1 && (i+1) == band->planesNr()) {
195             header[4] = 0;
196             size++;
197         }
198         if (write(STDOUT_FILENO, (unsigned char*)&header, size) == -1) {
199             ERRORMSG(_("Error while sending data to the printer (%u)"), errno);
200             return false;
201         }
202     }
203 
204     return true;
205 }
206 
renderPage(const Request & request,Page * page,bool lastPage)207 bool renderPage(const Request& request, Page* page, bool lastPage)
208 {
209     unsigned char duplex=0, tumble=0, paperSource;
210     unsigned long width, height;
211     unsigned char header[0x11];
212     const Band* band;
213 
214     if (!page) {
215         ERRORMSG(_("Try to render a NULL page"));
216         return false;
217     }
218 
219     // Get the duplex values
220     paperSource = request.printer()->paperSource();
221     switch (request.duplex()) {
222         case Request::Simplex:
223             duplex = 1;
224             tumble = 0;
225             break;
226         case Request::LongEdge:
227             duplex = 1;
228             tumble = page->pageNr() % 2;
229             break;
230         case Request::ShortEdge:
231             duplex = 0;
232             tumble = page->pageNr() % 2;
233             break;
234         case Request::ManualLongEdge:
235             duplex = 0;
236             tumble = page->pageNr() % 2;
237             if (tumble && !lastPage)
238                 paperSource = 3; // Multi source
239             break;
240         case Request::ManualShortEdge:
241             duplex = 1;
242             tumble = page->pageNr() % 2;
243             if (tumble && !lastPage)
244                 paperSource = 3; // Multi source
245             /** @todo what about the Short edge? The page isn't rotated?  */
246             break;
247     }
248 
249     width = page->width();
250     height = page->height();
251 
252     // Send the page header
253     header[0x0] = 0;                                // Signature
254     header[0x1] = page->yResolution() / 100;        // Y Resolution
255     header[0x2] = page->copiesNr() >> 8;            // Number of copies 8-15
256     header[0x3] = page->copiesNr();                 // Number of copies 0-7
257     header[0x4] = request.printer()->paperType();   // Paper type
258     header[0x5] = width >> 8;                       // Printable area width
259     header[0x6] = width;                            // Printable area width
260     header[0x7] = height >> 8;                      // Printable area height
261     header[0x8] = height;                           // Printable area height
262     header[0x9] = paperSource;                      // Paper source
263     header[0xa] = request.printer()->unknownByte1();// ??? XXX
264     header[0xb] = duplex;                           // Duplex
265     header[0xc] = tumble;                           // Tumble
266     header[0xd] = request.printer()->unknownByte2();// ??? XXX
267     header[0xe] = request.printer()->qpdlVersion(); // QPDL Version
268     header[0xf] = request.printer()->unknownByte3();// ??? XXX
269     header[0x10] = page->xResolution() / 100;       // X Resolution
270     if (write(STDOUT_FILENO, (unsigned char*)&header, 0x11) == -1) {
271         ERRORMSG(_("Error while sending data to the printer (%u)"), errno);
272         return false;
273     }
274 
275     // Send the page bands
276     band = page->firstBand();
277     while (band) {
278         if (!_renderBand(request, band))
279             return false;
280         band = band->sibling();
281     }
282 
283     // Send the page footer
284     header[0x0] = 1;                                // Signature
285     header[0x1] = page->copiesNr() >> 8;            // Number of copies 8-15
286     header[0x2] = page->copiesNr();                 // Number of copies 0-7
287     if (write(STDOUT_FILENO, (unsigned char*)&header, 0x3) == -1) {
288         ERRORMSG(_("Error while sending data to the printer (%u)"), errno);
289         return false;
290     }
291 
292     return true;
293 }
294 
295 /* vim: set expandtab tabstop=4 shiftwidth=4 smarttab tw=80 cin enc=utf8: */
296 
297