"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* Copyright (C) 1993-2005 Ghostgum Software Pty Ltd. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under licence and may not be copied,
7 modified or distributed except as expressly authorised under the terms
8 of the licence contained in the file LICENCE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostgum.com.au/ or contact Ghostsgum Software Pty Ltd,
12 218 Gallaghers Rd, Glen Waverley VIC 3150, AUSTRALIA,
13 Fax +61 3 9886 6616.
14 */
15
16 /* $Id: cps.c,v 1.7 2005/06/10 09:39:24 ghostgum Exp $ */
17 /* Copying PostScript files */
18
19 #include "common.h"
20 #include "dscparse.h"
21 #include "capp.h"
22 #define DEFINE_CDOC
23 #include "cdoc.h"
24
25 int ps_extract(Doc *doc, LPCTSTR filename, PAGELIST *pagelist, int copies);
26 int ps_copy(GFile *outfile, GFile *infile, FILE_OFFSET begin, FILE_OFFSET end);
27 int ps_fgets(char *s, int n, GFile *f);
28
29 static int ps_writestring(GFile *f, const char *str)
30 {
31 return gfile_write(f, str, (int)strlen(str));
32 }
33
34 /* Like fgets, but allows any combination of EOL characters
35 * and returns the count of bytes, not the string pointer.
36 * This reads one byte at a time, so is pretty slow.
37 * Use it for copying a header or trailer, but not for
38 * copying the whole document.
39 */
40 int ps_fgets(char *s, int n, GFile *f)
41 {
42 char ch = '\0';
43 int not_eof = 0;
44 char *p = s;
45 int count = 0; /* bytes written to buffer */
46 /* copy until first EOL character */
47 while ( (count < n) && ((not_eof = (int)gfile_read(f, &ch, 1)) != 0)
48 && (ch != '\r') && (ch != '\n') ) {
49 *p++ = (char)ch;
50 count++;
51 }
52
53 if ((count < n) && not_eof) {
54 /* check for extra EOL characters */
55 if (ch == '\r') {
56 *p++ = (char)ch;
57 count++;
58 /* check if MS-DOS \r\n is being used */
59 if ((count < n) && ((not_eof = (int)gfile_read(f, &ch, 1)) != 0)) {
60 if (ch == '\n') {
61 /* Yes, MS-DOS */
62 *p++ = (char)ch;
63 count++;
64 }
65 else {
66 /* No, Macintosh */
67 gfile_seek(f, -1, gfile_current);
68 }
69 }
70 }
71 else {
72 /* must have been '\n' */
73 *p++ = (char)ch;
74 count++;
75 }
76 }
77 if (count < n)
78 *p = '\0';
79
80 if ( (!not_eof) && (p == s) )
81 return 0;
82 return count;
83 }
84
85
86
87 static void
88 ps_num_copies(GFile *f, int copies)
89 {
90 char buf[MAXSTR];
91 if (copies >= 1) {
92 snprintf(buf, sizeof(buf)-1,
93 "[{\n%%%%BeginFeature: *NumCopies %d\n", copies);
94 ps_writestring(f, buf);
95 snprintf(buf, sizeof(buf)-1,
96 "<< /NumCopies %d >> setpagedevice\n", copies);
97 ps_writestring(f, buf);
98 ps_writestring(f, "%%%%EndFeature\n} stopped cleartomark\n");
99 }
100 }
101
102 /* Copy DSC until a particular comment is found */
103 /* Do not copy the comment */
104 /* Stop if file offset exceeds end */
105 /* return TRUE if comment found, FALSE if not found */
106 static BOOL
107 ps_copy_find(GFile *outfile, GFile *infile, FILE_OFFSET end,
108 char *s, int n, const char *comment)
109 {
110 int count;
111 int remain;
112 while (((remain = (FILE_POS)end - gfile_get_position(infile)) > 0) &&
113 ((count = ps_fgets(s, min(n-1, remain), infile))!=0)) {
114 s[n-1] = '\0';
115 if (strncmp(s, comment, strlen(comment)) == 0)
116 return TRUE;
117 gfile_write(outfile, s, count);
118 }
119 return FALSE;
120 }
121
122 int
123 ps_copy(GFile *outfile, GFile *infile, FILE_OFFSET begin, FILE_OFFSET end)
124 {
125 char *buf;
126 int count = 0;
127 buf = (char *)malloc(COPY_BUF_SIZE);
128 if (buf == (char *)NULL)
129 return -1;
130 if (begin >= 0)
131 gfile_seek(infile, begin, gfile_begin); /* seek to section to extract */
132 begin = gfile_get_position(infile);
133 while (begin < end) {
134 count = (int)(min(end-begin, COPY_BUF_SIZE));
135 if ((count = (int)gfile_read(infile, buf, count)) > 0) {
136 gfile_write(outfile, buf, count);
137 begin += count;
138 }
139 else
140 begin = end; /* EOF or error */
141 }
142 free(buf);
143 return count;
144 }
145
146 static int
147 ps_copy_setup(GFile *outfile, GFile *infile,
148 FILE_OFFSET begin, FILE_OFFSET end, int copies)
149 {
150 char line[DSC_LINE_LENGTH+1];
151 BOOL found;
152 int code = 0;
153 if (copies > 1) {
154 if (begin != end) {
155 gfile_seek(infile, begin, gfile_begin);
156 /* copy up to, but not including %%EndSetup */
157 found = ps_copy_find(outfile, infile, end,
158 line, sizeof(line)-1, "%%EndSetup");
159 /* insert code for multiple copies */
160 ps_num_copies(outfile, copies);
161 /* copy rest of setup section, including %%EndSetup */
162 if (found)
163 ps_writestring(outfile, line);
164 code = ps_copy(outfile, infile, -1, end);
165 }
166 else {
167 /* setup section was missing - add our own. */
168 ps_writestring(outfile, "%%BeginSetup\n");
169 ps_num_copies(outfile, copies);
170 ps_writestring(outfile, "%%EndSetup\n");
171 }
172 }
173 else
174 code = ps_copy(outfile, infile, begin, end);
175 return code;
176 }
177
178
179 /* Extract pages from a PostScript file */
180 /* The pages are in v->pagelist */
181 static int
182 ps_extract_pages(Doc *doc, GFile *infile, GFile *outfile,
183 PAGELIST *pagelist, int copies)
184 {
185 int i;
186 int pages = 0;
187 int neworder;
188 BOOL reverse;
189 DSC_OFFSET position;
190 char line[DSC_LINE_LENGTH+1];
191 char buf[MAXSTR];
192 BOOL end_header;
193 BOOL line_written;
194 BOOL pages_written = FALSE;
195 BOOL pageorder_written = FALSE;
196 CDSC *dsc = doc->dsc;
197 int page;
198 int count;
199
200 if (dsc == NULL)
201 return_error(-1);
202 if ((pagelist->page_count == 0) || (pagelist->select == NULL))
203 return_error(-1); /* can't do */
204 if (pagelist->page_count != (int)dsc->page_count)
205 return_error(-1);
206 for (i=0; i<pagelist->page_count; i++) {
207 if (pagelist->select[i])
208 pages++;
209 }
210
211 /* neworder = page order of the extracted document */
212 /* reverse = reverse the current page order */
213 neworder = dsc->page_order;
214 reverse = FALSE;
215 if (neworder == CDSC_ORDER_UNKNOWN) /* No page order so assume ASCEND */
216 neworder = CDSC_ASCEND;
217 /* Don't touch SPECIAL pageorder */
218 if (pagelist->reverse) {
219 /* New page order to be DESCEND */
220 if (neworder == CDSC_ASCEND)
221 neworder = CDSC_DESCEND;
222 else if (neworder == CDSC_DESCEND) {
223 /* neworder = DESCEND;*/ /* unchanged */
224 reverse = FALSE; /* already reversed, don't do it again */
225 }
226 }
227 else {
228 if (neworder == CDSC_DESCEND) {
229 neworder = CDSC_ASCEND;
230 reverse = TRUE; /* reverse it to become ascending */
231 }
232 }
233
234 /* copy header, fixing up %%Pages: and %%PageOrder:
235 * Write a DSC 3.0 %%Pages: or %%PageOrder: in header,
236 * even if document was DSC 2.x.
237 */
238 position = gfile_seek(infile, dsc->begincomments, gfile_begin);
239 while ( position < dsc->endcomments ) {
240 if (ps_fgets(line, min(sizeof(line), dsc->endcomments - position),
241 infile) == 0)
242 return FALSE;
243 position = gfile_get_position(infile);
244 end_header = (strncmp(line, "%%EndComments", 13) == 0);
245 if ((line[0] != '%') && (line[0] != ' ') && (line[0] != '+')
246 && (line[0] != '\t') && (line[0] != '\r') && (line[0] != '\n'))
247 end_header = TRUE;
248 line_written = FALSE;
249 if (end_header || strncmp(line, "%%Pages:", 8) == 0) {
250 if (!pages_written) {
251 snprintf(buf, sizeof(buf)-1, "%%%%Pages: %d\r\n", pages);
252 ps_writestring(outfile, buf);
253 pages_written = TRUE;
254 }
255 line_written = !end_header;
256 }
257 if (end_header || strncmp(line, "%%PageOrder:", 12) == 0) {
258 if (!pageorder_written) {
259 if (neworder == CDSC_ASCEND)
260 ps_writestring(outfile, "%%PageOrder: Ascend\r\n");
261 else if (neworder == CDSC_DESCEND)
262 ps_writestring(outfile, "%%PageOrder: Descend\r\n");
263 else
264 ps_writestring(outfile, "%%PageOrder: Special\r\n");
265 pageorder_written = TRUE;
266 }
267 line_written = !end_header;
268 }
269 if (!line_written)
270 ps_writestring(outfile, line);
271 }
272
273 if (dsc->begincomments != dsc->endcomments) {
274 if (!pages_written) {
275 snprintf(buf, sizeof(buf)-1, "%%%%Pages: %d\r\n", pages);
276 ps_writestring(outfile, buf);
277 /* pages_written = TRUE; */
278 }
279 if (!pageorder_written) {
280 if (neworder == CDSC_ASCEND)
281 ps_writestring(outfile, "%%PageOrder: Ascend\r\n");
282 else if (neworder == CDSC_DESCEND)
283 ps_writestring(outfile, "%%PageOrder: Descend\r\n");
284 else
285 ps_writestring(outfile, "%%PageOrder: Special\r\n");
286 /* pageorder_written = TRUE; */
287 }
288 }
289
290 ps_copy(outfile, infile, dsc->beginpreview, dsc->endpreview);
291 ps_copy(outfile, infile, dsc->begindefaults, dsc->enddefaults);
292 ps_copy(outfile, infile, dsc->beginprolog, dsc->endprolog);
293 ps_copy_setup(outfile, infile, dsc->beginsetup, dsc->endsetup, copies);
294
295 /* Copy each page */
296 page = 1;
297 i = reverse ? dsc->page_count - 1 : 0;
298 while ( reverse ? (i >= 0) : (i < (int)dsc->page_count) ) {
299 if (pagelist->select[doc_map_page(doc,i)]) {
300 gfile_seek(infile, dsc->page[i].begin, gfile_begin);
301 position = gfile_get_position(infile);
302 /* Read original %%Page: line */
303 if ((count = ps_fgets(line, sizeof(line)-1, infile)) == 0)
304 return -1;
305 /* Write new %%Page: line with new ordinal */
306 if (dsc->page[i].label)
307 snprintf(buf, sizeof(buf)-1, "%%%%Page: %s %d\r\n",
308 dsc->page[i].label, page);
309 else
310 snprintf(buf, sizeof(buf)-1,
311 "%%%%Page: %d %d\r\n", page, page);
312 ps_writestring(outfile, buf);
313 page++;
314 if (strncmp(line, "%%Page:", 7) != 0)
315 gfile_write(outfile, line, count);
316 ps_copy(outfile, infile, -1, dsc->page[i].end);
317 }
318 i += reverse ? -1 : 1;
319 }
320
321 /* copy trailer, removing %%Pages: and %%PageOrder: */
322 gfile_seek(infile, dsc->begintrailer, gfile_begin);
323 position = gfile_get_position(infile);
324 while ( position < dsc->endtrailer ) {
325 if (ps_fgets(line, min(sizeof(line), dsc->endtrailer - position),
326 infile) == 0)
327 return -1;
328 position = gfile_get_position(infile);
329 if (strncmp(line, "%%Pages:", 8) == 0) {
330 continue; /* has already been written in header */
331 }
332 else if (strncmp(line, "%%PageOrder:", 12) == 0) {
333 continue; /* has already been written in header */
334 }
335 else {
336 ps_writestring(outfile, line);
337 }
338 }
339 return 0;
340 }
341
342
343
344 /* Extract pages from a PostScript file.
345 * If copies > 1, insert PostScript code to request printing
346 * copies of each page.
347 * Used for saving a page that is being displayed,
348 * or in preparation for printing.
349 * Returns 0 if OK, -ve if error.
350 */
351 int
352 ps_extract(Doc *doc, LPCTSTR filename, PAGELIST *pagelist, int copies)
353 {
354 GFile *infile, *outfile;
355 CDSC *dsc;
356 int code;
357
358 if (doc_type(doc) == DOC_PDF)
359 return -1;
360 if ((infile = gfile_open(doc_name(doc), gfile_modeRead)) == (GFile *)NULL) {
361 app_msg(doc->app, "File \042");
362 app_csmsg(doc->app, doc_name(doc));
363 app_msg(doc->app, "\042 does not exist\n");
364 return_error(-1);
365 }
366 if ( (outfile = gfile_open(filename, gfile_modeWrite | gfile_modeCreate))
367 == (GFile *)NULL ) {
368 app_msg(doc->app, "File \042");
369 app_csmsg(doc->app, filename);
370 app_msg(doc->app, "\042 can not be opened for writing\n");
371 gfile_close(infile);
372 return_error(-1);
373 }
374
375 if (pagelist == NULL) {
376 /* Save file without changes */
377 code = ps_copy(outfile, infile, 0, gfile_get_length(infile));
378 }
379 else if (doc->dsc && doc->dsc->page_count &&
380 pagelist->page_count && (pagelist->select != NULL)) {
381 /* DSC with pages */
382 code = ps_extract_pages(doc, infile, outfile, pagelist, copies);
383 }
384 else if (doc->dsc) {
385 /* DSC without pages */
386 dsc = doc->dsc;
387 code = ps_copy(outfile, infile, dsc->begincomments, dsc->endcomments);
388 if (!code)
389 code = ps_copy(outfile, infile, dsc->begindefaults, dsc->enddefaults);
390 if (!code)
391 code = ps_copy(outfile, infile, dsc->beginprolog, dsc->endprolog);
392 if (!code)
393 code = ps_copy_setup(outfile, infile, dsc->beginsetup, dsc->endsetup,
394 copies);
395 if (!code)
396 code = ps_copy(outfile, infile, dsc->begintrailer, dsc->endtrailer);
397 }
398 else {
399 /* Not DSC */
400 if (copies > 1)
401 ps_num_copies(outfile, copies);
402 code = ps_copy(outfile, infile, 0, gfile_get_length(infile));
403 }
404
405 gfile_close(outfile);
406 gfile_close(infile);
407 if (code && !(debug & DEBUG_GENERAL))
408 csunlink(filename);
409 return code;
410 }
411
412