1 /*
2     generate_image.c - Part of psiconv, a PSION 5 file formats converter
3     Copyright (c) 1999-2014  Frodo Looijaard <frodo@frodo.looijaard.name>
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
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 
20 #include "config.h"
21 #include "compat.h"
22 
23 #include "generate_routines.h"
24 #include "error.h"
25 #include "list.h"
26 #include "image.h"
27 
28 #ifdef DMALLOC
29 #include <dmalloc.h>
30 #endif
31 
32 
33 static int psiconv_collect_pixel_data(psiconv_pixel_ints *pixels,
34                                int xsize,int ysize,
35                                const psiconv_pixel_floats_t data,
36                                int colordepth,int color,
37 			       int redbits,int greenbits,int bluebits,
38 			       const psiconv_pixel_floats_t palet);
39 static int psiconv_pixel_data_to_bytes(const psiconv_config config,int lev,
40                                 psiconv_pixel_bytes *bytes, int xsize,
41                                 int ysize, const psiconv_pixel_ints pixels,
42 				int colordepth);
43 static int psiconv_encode_rle8(const psiconv_config config,
44                         const psiconv_pixel_bytes plain_bytes,
45 			psiconv_pixel_bytes *encoded_bytes);
46 static int psiconv_encode_rle12(const psiconv_config config,
47                         const psiconv_pixel_bytes plain_bytes,
48 			psiconv_pixel_bytes *encoded_bytes);
49 static int psiconv_encode_rle16(const psiconv_config config,
50                         const psiconv_pixel_bytes plain_bytes,
51 			psiconv_pixel_bytes *encoded_bytes);
52 static int psiconv_encode_rle24(const psiconv_config config,
53                         const psiconv_pixel_bytes plain_bytes,
54 			psiconv_pixel_bytes *encoded_bytes);
55 
psiconv_write_paint_data_section(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_paint_data_section value,int is_clipart)56 int psiconv_write_paint_data_section(const psiconv_config config,
57                                      psiconv_buffer buf, int lev,
58                                      const psiconv_paint_data_section value,
59 				     int is_clipart)
60 {
61   int res,colordepth,i;
62   psiconv_pixel_ints ints;
63   psiconv_pixel_floats_t floats,palet;
64   psiconv_list bytes,bytes_rle;
65   psiconv_u8 *byteptr,encoding;
66 
67   psiconv_progress(config,lev,0,"Writing paint data section");
68 
69   /* First, we check whether we can cope with the current configuration.
70      If not, we stop at once */
71   if ((config->colordepth != 2) && (config->colordepth != 4) &&
72       (config->colordepth != 8) && (config->colordepth != 12) &&
73       (config->colordepth != 16) && (config->colordepth != 24)) {
74     psiconv_error(config,lev,0,
75 	         "Unsupported color depth (%d); try 2, 4, 8, 16 or 24",
76 		 config->colordepth);
77     res = -PSICONV_E_GENERATE;
78     goto ERROR1;
79   }
80 
81  if ((config->color) &&
82      (config->bluebits || config->redbits || config->greenbits) &&
83      (config->bluebits+config->redbits+config->greenbits!=config->colordepth)) {
84    psiconv_error(config,lev,0,
85                 "Sum of red (%d), green  (%d) and blue (%d) bits should be "
86 		"equal to the color depth (%d)",
87 		config->redbits,config->greenbits,config->bluebits,
88 		config->colordepth);
89     res = -PSICONV_E_GENERATE;
90     goto ERROR1;
91   }
92 
93  if (config->color &&
94      !(config->redbits || config->greenbits || config->bluebits) &&
95      (config->colordepth != 4) && (config->colordepth != 8)) {
96    psiconv_error(config,lev,0,
97                 "Current color depth (%d) has no palet associated with it",
98 		config->colordepth);
99    res = -PSICONV_E_GENERATE;
100    goto ERROR1;
101  }
102 
103  if (config->color || (config->colordepth != 2))
104    psiconv_warn(config,lev,0,
105                 "All image types except 2-bit greyscale are experimental!");
106 
107 
108   if (!value) {
109     psiconv_error(config,lev,0,"Null paint data section");
110     res = -PSICONV_E_GENERATE;
111     goto ERROR1;
112   }
113 
114   floats.red = value->red;
115   floats.green = value->green;
116   floats.blue = value->blue;
117   floats.length = value->xsize * value->ysize;
118 
119   palet = psiconv_palet_none;
120   if ((config->color) && (config->redbits == 0) && (config->greenbits == 0) &&
121       (config->bluebits == 0))
122     switch (config->colordepth) {
123       case 4: palet = psiconv_palet_color_4; break;
124       case 8: palet = psiconv_palet_color_8; break;
125       default: palet = psiconv_palet_none; break;
126     }
127 
128   if ((res = psiconv_collect_pixel_data(&ints,value->xsize,
129 	                        value->ysize,floats,
130 	                        config->colordepth,config->color,
131 				config->redbits,config->greenbits,
132 				config->bluebits,palet))) {
133     psiconv_error(config,lev,0,"Error collecting pixel data");
134     goto ERROR1;
135   }
136 
137   if ((res = psiconv_pixel_data_to_bytes(config,lev+1,&bytes,value->xsize,
138 	                                 value->ysize,ints,
139 					 config->colordepth))) {
140     psiconv_error(config,lev,0,"Error translating pixel data to bytes");
141     goto ERROR2;
142   }
143 
144 
145   switch (config->colordepth) {
146     case 2:
147     case 4:
148     case 8:
149       encoding = 0x01;
150       if ((res = psiconv_encode_rle8(config,bytes,&bytes_rle))) {
151         psiconv_error(config,lev,0,"Error encoding RLE8");
152 	goto ERROR3;
153       }
154       break;
155     case 12:
156       encoding = 0x02;
157       if ((res = psiconv_encode_rle12(config,bytes,&bytes_rle))) {
158         psiconv_error(config,lev,0,"Error encoding RLE12");
159 	goto ERROR3;
160       }
161       break;
162     case 16:
163       encoding = 0x03;
164       if ((res = psiconv_encode_rle16(config,bytes,&bytes_rle))) {
165         psiconv_error(config,lev,0,"Error encoding RLE16");
166 	goto ERROR3;
167       }
168       break;
169     case 24:
170       encoding = 0x04;
171       if ((res = psiconv_encode_rle24(config,bytes,&bytes_rle))) {
172         psiconv_error(config,lev,0,"Error encoding RLE24");
173 	goto ERROR3;
174       }
175       break;
176     default:
177       encoding = 0x00;
178   }
179   if (encoding) {
180     if (psiconv_list_length(bytes_rle) < psiconv_list_length(bytes)) {
181       psiconv_list_free(bytes);
182       bytes = bytes_rle;
183     } else {
184       psiconv_list_free(bytes_rle);
185       encoding = 0x00;
186     }
187   }
188 
189   if ((res = psiconv_write_u32(config,buf,lev+1,
190 	                       0x28+psiconv_list_length(bytes))))
191     goto ERROR3;
192   if ((res = psiconv_write_u32(config,buf,lev+1,0x28)))
193     goto ERROR3;
194   if ((res = psiconv_write_u32(config,buf,lev+1,value->xsize)))
195     goto ERROR3;
196   if ((res = psiconv_write_u32(config,buf,lev+1,value->ysize)))
197     goto ERROR3;
198   if ((res = psiconv_write_length(config,buf,lev+1,value->pic_xsize)))
199     goto ERROR3;
200   if ((res = psiconv_write_length(config,buf,lev+1,value->pic_ysize)))
201     goto ERROR3;
202   colordepth = config->colordepth;
203   if ((res = psiconv_write_u32(config,buf,lev+1,colordepth)))
204     goto ERROR3;
205   if ((res = psiconv_write_u32(config,buf,lev+1,(config->color?1:0))))
206     goto ERROR3;
207   if ((res = psiconv_write_u32(config,buf,lev+1,0)))
208     goto ERROR3;
209   if ((res = psiconv_write_u32(config,buf,lev+1,encoding)))
210     goto ERROR3;
211   if (is_clipart) {
212     if ((res = psiconv_write_u32(config,buf,lev+1,0xffffffff)))
213       goto ERROR3;
214     if ((res = psiconv_write_u32(config,buf,lev+1,0x00000044)))
215       goto ERROR3;
216   }
217   for (i = 0; i < psiconv_list_length(bytes); i++) {
218     if (!(byteptr = psiconv_list_get(bytes,i)))
219       goto ERROR3;
220     if ((res = psiconv_write_u8(config,buf,lev+1,*byteptr)))
221       goto ERROR3;
222   }
223 
224 ERROR3:
225   psiconv_list_free(bytes);
226 ERROR2:
227   psiconv_list_free(ints);
228 ERROR1:
229   if (res)
230     psiconv_error(config,lev,0,"Writing of paint data section failed");
231   else
232     psiconv_progress(config,lev,0,"End of paint data section");
233   return res;
234 }
235 
236 /* Translate the floating point RGB information into pixel values.
237    The palet is optional; without it, we just use the
238    colordepth. With a large palet this is not very fast, but it will do for
239    now. For greyscale pictures, just use the palet. */
psiconv_collect_pixel_data(psiconv_pixel_ints * pixels,int xsize,int ysize,const psiconv_pixel_floats_t data,int colordepth,int color,int redbits,int bluebits,int greenbits,const psiconv_pixel_floats_t palet)240 int psiconv_collect_pixel_data(psiconv_pixel_ints *pixels,int xsize,int ysize,
241                                const psiconv_pixel_floats_t data,
242                                int colordepth,int color,
243 			       int redbits,int bluebits,int greenbits,
244 			       const psiconv_pixel_floats_t palet)
245 {
246   int res,x,y,i;
247   psiconv_u32 index,pixel;
248   float p_red,p_green,p_blue,dist,new_dist;
249 
250   if (!(*pixels = psiconv_list_new(sizeof(psiconv_u32)))) {
251     res = -PSICONV_E_NOMEM;
252     goto ERROR1;
253   }
254 
255   for (y = 0; y < ysize; y++) {
256     for (x = 0; x < xsize; x++) {
257       index = y*xsize+x;
258       p_red = data.red[index];
259       p_green = data.green[index];
260       p_blue = data.blue[index];
261       if (!palet.length) {
262 	if (color)
263 	  pixel = (((psiconv_u32) (p_red * (1 << redbits) + 0.5))
264 	                                      << (greenbits+bluebits)) +
265 	          (((psiconv_u32) (p_green * (1 << greenbits) + 0.5))
266 		                              << bluebits) +
267 	          ((psiconv_u32) (p_blue * (1 << bluebits) + 0.5));
268 	else
269 	  pixel = (0.212671 * p_red + 0.715160 * p_green + 0.072169 * p_blue) * ((1 << colordepth) * 0.999);
270       } else {
271 	dist = 4; /* Max distance is 3, so this is safe */
272 	pixel = -1;
273 	for (i = 0; i < palet.length; i++) {
274 	  new_dist = (p_red - palet.red[i]) * (p_red - palet.red[i]) +
275                      (p_green - palet.green[i]) * (p_green - palet.green[i]) +
276 		     (p_blue - palet.blue[i]) * (p_blue - palet.blue[i]);
277 	  if (new_dist < dist) {
278 	    pixel = i;
279 	    dist = new_dist;
280 	  }
281 	}
282       }
283       if ((res = psiconv_list_add(*pixels,&pixel)))
284 	goto ERROR2;
285     }
286   }
287   return 0;
288 
289 ERROR2:
290   psiconv_list_free(*pixels);
291 ERROR1:
292   return res;
293 }
294 
psiconv_pixel_data_to_bytes(const psiconv_config config,int lev,psiconv_pixel_bytes * bytes,int xsize,int ysize,const psiconv_pixel_ints pixels,int colordepth)295 int psiconv_pixel_data_to_bytes(const psiconv_config config,int lev,
296                                 psiconv_pixel_bytes *bytes, int xsize,
297                                 int ysize, const psiconv_pixel_ints pixels,
298 				int colordepth)
299 {
300   int res;
301   int x,y;
302 
303   psiconv_u32 inputdata;
304   psiconv_u8 outputbyte;
305   psiconv_u32 *pixelptr;
306   int inputbitsleft,outputbitnr,bitsfit,outputbytenr;
307 
308 
309   if (!bytes) {
310     psiconv_error(config,lev,0,"NULL pixel data");
311     res = -PSICONV_E_GENERATE;
312     goto ERROR1;
313   }
314   if (!pixels) {
315     psiconv_error(config,lev,0,"NULL pixel data");
316     res = -PSICONV_E_GENERATE;
317     goto ERROR1;
318   }
319   if (psiconv_list_length(pixels) != xsize * ysize) {
320     psiconv_error(config,lev,0,"Pixel number is not correct");
321     res = -PSICONV_E_GENERATE;
322     goto ERROR1;
323   }
324 
325   if (!(*bytes = psiconv_list_new(sizeof(psiconv_u8)))) {
326     res = -PSICONV_E_NOMEM;
327     goto ERROR1;
328   }
329 
330 
331   outputbitnr = 0;
332   outputbyte = 0;
333   for (y = 0; y < ysize; y++) {
334     outputbytenr = 0;
335     for (x = 0; x < xsize; x++) {
336       if (!(pixelptr = psiconv_list_get(pixels,y*xsize+x))) {
337 	psiconv_error(config,lev,0,"Data structure corruption");
338 	res = -PSICONV_E_NOMEM;
339 	goto ERROR2;
340       }
341       inputbitsleft = colordepth;
342       inputdata = *pixelptr;
343       while (inputbitsleft) {
344 	bitsfit = (inputbitsleft+outputbitnr<=8?inputbitsleft:8-outputbitnr);
345 	outputbyte |= (inputdata & ((1 << bitsfit) - 1)) << outputbitnr;
346 	inputdata = inputdata >> bitsfit;
347 	inputbitsleft -= bitsfit;
348 	outputbitnr += bitsfit;
349 	if (outputbitnr == 8) {
350 	  if ((res = psiconv_list_add(*bytes,&outputbyte)))
351 	    goto ERROR2;
352 	  outputbitnr = 0;
353 	  outputbyte = 0;
354 	  outputbytenr ++;
355 	}
356       }
357     }
358     /* Always end lines on a long border */
359     if (outputbitnr != 0) {
360       if ((res = psiconv_list_add(*bytes,&outputbyte)))
361 	goto ERROR2;
362       outputbitnr = 0;
363       outputbyte = 0;
364       outputbytenr ++;
365     }
366 
367     while (outputbytenr % 0x04) {
368       if ((res = psiconv_list_add(*bytes,&outputbyte)))
369 	goto ERROR2;
370       outputbytenr ++;
371     }
372   }
373 
374   return 0;
375 
376 ERROR2:
377   psiconv_list_free(*bytes);
378 ERROR1:
379   return res;
380 }
381 
382 /* RLE8 encoding:
383      Marker bytes followed by one or more data bytes.
384      Marker value 0x00-0x7f: repeat the next data byte (marker+1) times
385      Marker value 0xff-0x80: (0x100-marker) data bytes follow */
psiconv_encode_rle8(const psiconv_config config,const psiconv_pixel_bytes plain_bytes,psiconv_pixel_bytes * encoded_bytes)386 int psiconv_encode_rle8(const psiconv_config config,
387                         const psiconv_pixel_bytes plain_bytes,
388 			psiconv_pixel_bytes *encoded_bytes)
389 {
390   int res,i,j,len;
391   psiconv_u8 *entry,*next;
392   psiconv_u8 temp;
393 
394   if (!(*encoded_bytes = psiconv_list_new(sizeof(*entry)))) {
395     res = -PSICONV_E_NOMEM;
396     goto ERROR1;
397   }
398 
399   for (i = 0; i < psiconv_list_length(plain_bytes);) {
400     if (!(entry = psiconv_list_get(plain_bytes,i))) {
401       res = -PSICONV_E_NOMEM;
402       goto ERROR2;
403     }
404     if (!(next = psiconv_list_get(plain_bytes,i+1))) {
405       res = -PSICONV_E_NOMEM;
406       goto ERROR2;
407     }
408     if (i == psiconv_list_length(plain_bytes) - 2) {
409       temp = 0xfe;
410       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
411 	goto ERROR2;
412       if ((res = psiconv_list_add(*encoded_bytes,entry)))
413 	goto ERROR2;
414       if ((res = psiconv_list_add(*encoded_bytes,next)))
415 	goto ERROR2;
416       i +=2;
417     } else if (*next == *entry) {
418       len = 1;
419       while ((*next == *entry) &&
420 	     (i+len + 2 < psiconv_list_length(plain_bytes)) &&
421 	     len < 0x80) {
422 	len ++;
423 	if (!(next = psiconv_list_get(plain_bytes,i+len))) {
424 	  res = -PSICONV_E_NOMEM;
425 	  goto ERROR2;
426 	}
427       }
428       temp = len - 1;
429       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
430 	goto ERROR2;
431       if ((res = psiconv_list_add(*encoded_bytes,entry)))
432 	goto ERROR2;
433       i += len;
434     } else {
435       len = 1;
436       while ((*next != *entry) &&
437 	     (i+len+1 < psiconv_list_length(plain_bytes)) &&
438 	     len < 0x80) {
439 	len ++;
440 	entry = next;
441 	if (!(next = psiconv_list_get(plain_bytes,i+len))) {
442 	  res = -PSICONV_E_NOMEM;
443 	  goto ERROR2;
444         }
445       }
446       len --;
447       temp = 0x100 - len;
448       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
449         goto ERROR2;
450       for (j = 0; j < len; j++) {
451         if (!(next = psiconv_list_get(plain_bytes,i+j))) {
452   	  res = -PSICONV_E_NOMEM;
453   	  goto ERROR2;
454         }
455         if ((res = psiconv_list_add(*encoded_bytes,next)))
456          goto ERROR2;
457       }
458       i += len;
459     }
460   }
461   return 0;
462 
463 ERROR2:
464   psiconv_list_free(*encoded_bytes);
465 ERROR1:
466   return res;
467 }
468 
469 /* RLE12 encoding:
470      Word based. The 12 least significant bits contain the pixel colors.
471      the 4 most signigicant bits are the number of repetitions minus 1 */
psiconv_encode_rle12(const psiconv_config config,const psiconv_pixel_bytes plain_bytes,psiconv_pixel_bytes * encoded_bytes)472 int psiconv_encode_rle12(const psiconv_config config,
473                         const psiconv_pixel_bytes plain_bytes,
474 			psiconv_pixel_bytes *encoded_bytes)
475 {
476   typedef psiconv_list psiconv_word_data; /* of psiconv_u16 */
477   psiconv_word_data data;
478   int res,i,len,location;
479   psiconv_u16 *word_entry,*word_next;
480   psiconv_u16 word_data;
481   psiconv_u8 byte_temp;
482   psiconv_u8 *byte_entry;
483 
484 
485   /* First extract the 12-bit values to encode */
486   if (!(data = psiconv_list_new(sizeof(psiconv_u16)))) {
487     res = -PSICONV_E_NOMEM;
488     goto ERROR1;
489   }
490 
491   for (i = 0; i < psiconv_list_length(plain_bytes); i++) {
492     if (!(byte_entry = psiconv_list_get(plain_bytes,i))) {
493       res = -PSICONV_E_NOMEM;
494       goto ERROR2;
495     }
496     location = 0;
497     if (location == 0) {
498       word_data = *byte_entry;
499       location ++;
500     } else if (location == 1) {
501       word_data = (word_data << 4) + (*byte_entry & 0x0f);
502       if ((res = psiconv_list_add(data,&word_data)))
503 	goto ERROR2;
504       word_data = *byte_entry >> 4;
505       location ++;
506     } else {
507       word_data = (word_data << 8) + *byte_entry;
508       if ((res = psiconv_list_add(data,&word_data)))
509 	goto ERROR2;
510       location = 0;
511     }
512   }
513 
514   if (!(*encoded_bytes = psiconv_list_new(sizeof(psiconv_u8)))) {
515     res = -PSICONV_E_NOMEM;
516     goto ERROR2;
517   }
518 
519   for (i = 0; i < psiconv_list_length(data);) {
520     if (!(word_entry = psiconv_list_get(data,i))) {
521       res = -PSICONV_E_NOMEM;
522       goto ERROR3;
523     }
524 
525     if (!(word_next = psiconv_list_get(data,i+1))) {
526       res = -PSICONV_E_NOMEM;
527       goto ERROR3;
528     }
529 
530     if (i == psiconv_list_length(data) - 2) {
531       byte_temp = *word_entry && 0xff;
532       if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
533         goto ERROR3;
534       byte_temp = *word_entry >> 8;
535       if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
536         goto ERROR3;
537       byte_temp = *word_next && 0xff;
538       if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
539         goto ERROR3;
540       byte_temp = *word_next >> 8;
541       if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
542         goto ERROR3;
543       i += 2;
544     }
545 
546     len = 0;
547     while ((*word_entry == *word_next) && (len < 16) &&
548 	   (i+len+1 < psiconv_list_length(data))) {
549       len ++;
550       if (!(word_next = psiconv_list_get(data,i+len))) {
551 	res = -PSICONV_E_NOMEM;
552 	goto ERROR3;
553       }
554     }
555 
556     byte_temp = *word_entry && 0xff;
557     if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
558       goto ERROR3;
559     byte_temp = (*word_entry >> 8) + ((len - 1) << 4);
560     if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
561       goto ERROR3;
562     i += len;
563   }
564   return 0;
565 
566 ERROR3:
567   psiconv_list_free(*encoded_bytes);
568 ERROR2:
569   psiconv_list_free(data);
570 ERROR1:
571   return res;
572 }
573 
574 /* RLE16 encoding:
575      Marker bytes followed by one or more data words.
576      Marker value 0x00-0x7f: repeat the next data word (marker+1) times
577      Marker value 0xff-0x80: (0x100-marker) data words follow */
psiconv_encode_rle16(const psiconv_config config,const psiconv_pixel_bytes plain_bytes,psiconv_pixel_bytes * encoded_bytes)578 int psiconv_encode_rle16(const psiconv_config config,
579                         const psiconv_pixel_bytes plain_bytes,
580 			psiconv_pixel_bytes *encoded_bytes)
581 {
582   int res,i,j,len;
583   psiconv_u8 *entry1,*entry2,*next1,*next2;
584   psiconv_u8 temp;
585 
586   if (!(*encoded_bytes = psiconv_list_new(sizeof(*entry1)))) {
587     res = -PSICONV_E_NOMEM;
588     goto ERROR1;
589   }
590 
591   for (i = 0; i < psiconv_list_length(plain_bytes);) {
592     if (!(entry1 = psiconv_list_get(plain_bytes,i))) {
593       res = -PSICONV_E_NOMEM;
594       goto ERROR2;
595     }
596     if (!(entry2 = psiconv_list_get(plain_bytes,i+1))) {
597       res = -PSICONV_E_NOMEM;
598       goto ERROR2;
599     }
600     if (!(next1 = psiconv_list_get(plain_bytes,i+2))) {
601       res = -PSICONV_E_NOMEM;
602       goto ERROR2;
603     }
604     if (!(next2 = psiconv_list_get(plain_bytes,i+3))) {
605       res = -PSICONV_E_NOMEM;
606       goto ERROR2;
607     }
608     if (i == psiconv_list_length(plain_bytes) - 4) {
609       temp = 0xfe;
610       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
611 	goto ERROR2;
612       if ((res = psiconv_list_add(*encoded_bytes,entry1)))
613 	goto ERROR2;
614       if ((res = psiconv_list_add(*encoded_bytes,entry2)))
615 	goto ERROR2;
616       if ((res = psiconv_list_add(*encoded_bytes,next1)))
617 	goto ERROR2;
618       if ((res = psiconv_list_add(*encoded_bytes,next2)))
619 	goto ERROR2;
620       i +=4;
621     } else if ((*next1 == *entry1) && (*next2 == *entry2)) {
622       len = 0;
623       while (((*next1 == *entry1) && (*next2 == *entry2)) &&
624 	     (i+2*len + 4 < psiconv_list_length(plain_bytes)) &&
625 	     len < 0x80) {
626 	len ++;
627 	if (!(next1 = psiconv_list_get(plain_bytes,i+len*2))) {
628 	  res = -PSICONV_E_NOMEM;
629 	  goto ERROR2;
630 	}
631 	if (!(next2 = psiconv_list_get(plain_bytes,i+len*2+1))) {
632 	  res = -PSICONV_E_NOMEM;
633 	  goto ERROR2;
634 	}
635       }
636       temp = len - 1;
637       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
638 	goto ERROR2;
639       if ((res = psiconv_list_add(*encoded_bytes,entry1)))
640 	goto ERROR2;
641       if ((res = psiconv_list_add(*encoded_bytes,entry2)))
642 	goto ERROR2;
643       i += len*2;
644     } else {
645       len = 1;
646       while (((*next1 != *entry1) || (*next2 != *entry2))&&
647 	     (i+len*2+4 < psiconv_list_length(plain_bytes)) &&
648 	     len < 0x80) {
649 	len ++;
650 	entry1 = next1;
651 	entry2 = next2;
652 	if (!(next1 = psiconv_list_get(plain_bytes,i+len*2))) {
653 	  res = -PSICONV_E_NOMEM;
654 	  goto ERROR2;
655         }
656 	if (!(next2 = psiconv_list_get(plain_bytes,i+len*2+1))) {
657 	  res = -PSICONV_E_NOMEM;
658 	  goto ERROR2;
659         }
660       }
661       len --;
662       temp = 0x100 - len;
663       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
664         goto ERROR2;
665       for (j = 0; j < len; j++) {
666         if (!(next1 = psiconv_list_get(plain_bytes,i+j*2))) {
667   	  res = -PSICONV_E_NOMEM;
668   	  goto ERROR2;
669         }
670         if (!(next2 = psiconv_list_get(plain_bytes,i+j*2+1))) {
671   	  res = -PSICONV_E_NOMEM;
672   	  goto ERROR2;
673         }
674         if ((res = psiconv_list_add(*encoded_bytes,next1)))
675          goto ERROR2;
676         if ((res = psiconv_list_add(*encoded_bytes,next2)))
677          goto ERROR2;
678       }
679       i += len*2;
680     }
681   }
682   return 0;
683 
684 ERROR2:
685   psiconv_list_free(*encoded_bytes);
686 ERROR1:
687   return res;
688 }
689 
690 /* RLE24 encoding:
691      Marker bytes followed by one or more data byte-triplets.
692      Marker value 0x00-0x7f: repeat the next data byte-triplets (marker+1) times
693      Marker value 0xff-0x80: (0x100-marker) data byte-triplets follow */
psiconv_encode_rle24(const psiconv_config config,const psiconv_pixel_bytes plain_bytes,psiconv_pixel_bytes * encoded_bytes)694 int psiconv_encode_rle24(const psiconv_config config,
695                         const psiconv_pixel_bytes plain_bytes,
696 			psiconv_pixel_bytes *encoded_bytes)
697 {
698   int res,i,j,len;
699   psiconv_u8 *entry1,*entry2,*entry3,*next1,*next2,*next3;
700   psiconv_u8 temp;
701 
702   if (!(*encoded_bytes = psiconv_list_new(sizeof(*entry1)))) {
703     res = -PSICONV_E_NOMEM;
704     goto ERROR1;
705   }
706 
707   for (i = 0; i < psiconv_list_length(plain_bytes);) {
708     if (!(entry1 = psiconv_list_get(plain_bytes,i))) {
709       res = -PSICONV_E_NOMEM;
710       goto ERROR2;
711     }
712     if (!(entry2 = psiconv_list_get(plain_bytes,i+1))) {
713       res = -PSICONV_E_NOMEM;
714       goto ERROR2;
715     }
716     if (!(entry3 = psiconv_list_get(plain_bytes,i+2))) {
717       res = -PSICONV_E_NOMEM;
718       goto ERROR2;
719     }
720     if (!(next1 = psiconv_list_get(plain_bytes,i+3))) {
721       res = -PSICONV_E_NOMEM;
722       goto ERROR2;
723     }
724     if (!(next2 = psiconv_list_get(plain_bytes,i+4))) {
725       res = -PSICONV_E_NOMEM;
726       goto ERROR2;
727     }
728     if (!(next3 = psiconv_list_get(plain_bytes,i+5))) {
729       res = -PSICONV_E_NOMEM;
730       goto ERROR2;
731     }
732     if (i == psiconv_list_length(plain_bytes) - 6) {
733       temp = 0xfe;
734       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
735 	goto ERROR2;
736       if ((res = psiconv_list_add(*encoded_bytes,entry1)))
737 	goto ERROR2;
738       if ((res = psiconv_list_add(*encoded_bytes,entry2)))
739 	goto ERROR2;
740       if ((res = psiconv_list_add(*encoded_bytes,entry3)))
741 	goto ERROR2;
742       if ((res = psiconv_list_add(*encoded_bytes,next1)))
743 	goto ERROR2;
744       if ((res = psiconv_list_add(*encoded_bytes,next2)))
745 	goto ERROR2;
746       if ((res = psiconv_list_add(*encoded_bytes,next3)))
747 	goto ERROR2;
748       i +=4;
749     } else if ((*next1 == *entry1) && (*next2 == *entry2) &&
750 	       (*next3 == *entry3)) {
751       len = 0;
752       while (((*next1 == *entry1) && (*next2 == *entry2) &&
753 	      (*next3 == *entry3)) &&
754 	     (i+3*len + 6 < psiconv_list_length(plain_bytes)) &&
755 	     len < 0x80) {
756 	len ++;
757 	if (!(next1 = psiconv_list_get(plain_bytes,i+len*3))) {
758 	  res = -PSICONV_E_NOMEM;
759 	  goto ERROR2;
760 	}
761 	if (!(next2 = psiconv_list_get(plain_bytes,i+len*3+1))) {
762 	  res = -PSICONV_E_NOMEM;
763 	  goto ERROR2;
764 	}
765 	if (!(next3 = psiconv_list_get(plain_bytes,i+len*3+2))) {
766 	  res = -PSICONV_E_NOMEM;
767 	  goto ERROR2;
768 	}
769       }
770       temp = len - 1;
771       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
772 	goto ERROR2;
773       if ((res = psiconv_list_add(*encoded_bytes,entry1)))
774 	goto ERROR2;
775       if ((res = psiconv_list_add(*encoded_bytes,entry2)))
776 	goto ERROR2;
777       if ((res = psiconv_list_add(*encoded_bytes,entry3)))
778 	goto ERROR2;
779       i += len*3;
780     } else {
781       len = 1;
782       while (((*next1 != *entry1) || (*next2 != *entry2) ||
783 	      (*next3 != *entry3)) &&
784 	     (i+len*3+6 < psiconv_list_length(plain_bytes)) &&
785 	     len < 0x80) {
786 	len ++;
787 	entry1 = next1;
788 	entry2 = next2;
789 	entry3 = next3;
790 	if (!(next1 = psiconv_list_get(plain_bytes,i+len*3))) {
791 	  res = -PSICONV_E_NOMEM;
792 	  goto ERROR2;
793         }
794 	if (!(next2 = psiconv_list_get(plain_bytes,i+len*3+1))) {
795 	  res = -PSICONV_E_NOMEM;
796 	  goto ERROR2;
797         }
798 	if (!(next3 = psiconv_list_get(plain_bytes,i+len*3+2))) {
799 	  res = -PSICONV_E_NOMEM;
800 	  goto ERROR2;
801         }
802       }
803       len --;
804       temp = 0x100 - len;
805       if ((res = psiconv_list_add(*encoded_bytes,&temp)))
806         goto ERROR2;
807       for (j = 0; j < len; j++) {
808         if (!(next1 = psiconv_list_get(plain_bytes,i+j*3))) {
809   	  res = -PSICONV_E_NOMEM;
810   	  goto ERROR2;
811         }
812         if (!(next2 = psiconv_list_get(plain_bytes,i+j*3+1))) {
813   	  res = -PSICONV_E_NOMEM;
814   	  goto ERROR2;
815         }
816         if (!(next2 = psiconv_list_get(plain_bytes,i+j*3+2))) {
817   	  res = -PSICONV_E_NOMEM;
818   	  goto ERROR2;
819         }
820         if ((res = psiconv_list_add(*encoded_bytes,next1)))
821          goto ERROR2;
822         if ((res = psiconv_list_add(*encoded_bytes,next2)))
823          goto ERROR2;
824         if ((res = psiconv_list_add(*encoded_bytes,next3)))
825          goto ERROR2;
826       }
827       i += len*3;
828     }
829   }
830   return 0;
831 
832 ERROR2:
833   psiconv_list_free(*encoded_bytes);
834 ERROR1:
835   return res;
836 }
837 
838 
psiconv_write_sketch_section(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_sketch_section value)839 int psiconv_write_sketch_section(const psiconv_config config,
840                                  psiconv_buffer buf, int lev,
841 				 const psiconv_sketch_section value)
842 {
843   int res;
844 
845   psiconv_progress(config,lev,0,"Writing sketch section");
846   if (!value) {
847     psiconv_error(config,lev,0,"NULL sketch section");
848     res = -PSICONV_E_GENERATE;
849     goto ERROR1;
850   }
851 
852   if ((res = psiconv_write_u16(config,buf,lev+1,value->displayed_xsize)))
853     goto ERROR1;
854   if ((res = psiconv_write_u16(config,buf,lev+1,value->displayed_ysize)))
855     goto ERROR1;
856   if ((res = psiconv_write_u16(config,buf,lev+1,value->picture_data_x_offset)))
857     goto ERROR1;
858   if ((res = psiconv_write_u16(config,buf,lev+1,value->picture_data_y_offset)))
859     goto ERROR1;
860   if ((res = psiconv_write_u16(config,buf,lev+1,value->displayed_size_x_offset)))
861     goto ERROR1;
862   if ((res = psiconv_write_u16(config,buf,lev+1,value->displayed_size_y_offset)))
863     goto ERROR1;
864   if ((res = psiconv_write_u16(config,buf,lev+1,value->form_xsize)))
865     goto ERROR1;
866   if ((res = psiconv_write_u16(config,buf,lev+1,value->form_ysize)))
867     goto ERROR1;
868   if ((res = psiconv_write_u16(config,buf,lev+1,0x0000)))
869     goto ERROR1;
870   if ((res = psiconv_write_paint_data_section(config,buf,lev+1,value->picture,0)))
871     goto ERROR1;
872   if ((res = psiconv_write_u16(config,buf,lev+1,value->magnification_x * 0x03e8)))
873     goto ERROR1;
874   if ((res = psiconv_write_u16(config,buf,lev+1,value->magnification_y * 0x03e8)))
875     goto ERROR1;
876   if ((res = psiconv_write_u32(config,buf,lev+1,value->cut_left * 0x0c *
877 	                                  value->displayed_xsize)))
878     goto ERROR1;
879   if ((res = psiconv_write_u32(config,buf,lev+1,value->cut_right * 0x0c *
880 	                                  value->displayed_xsize)))
881     goto ERROR1;
882   if ((res = psiconv_write_u32(config,buf,lev+1,value->cut_top * 0x0c *
883 	                                  value->displayed_ysize)))
884     goto ERROR1;
885   if ((res = psiconv_write_u32(config,buf,lev+1,value->cut_bottom * 0x0c *
886 	                                  value->displayed_ysize)))
887     goto ERROR1;
888 
889 ERROR1:
890   if (res)
891     psiconv_error(config,lev,0,"Writing of sketch section failed");
892   else
893     psiconv_progress(config,lev,0,"End of sketch section");
894   return res;
895 }
896 
psiconv_write_clipart_section(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_clipart_section value)897 int psiconv_write_clipart_section(const psiconv_config config,
898                                   psiconv_buffer buf, int lev,
899 				  const psiconv_clipart_section value)
900 {
901   int res;
902 
903   psiconv_progress(config,lev,0,"Writing clipart section");
904   if (!value) {
905     psiconv_error(config,lev,0, "NULL Clipart Section");
906     res = -PSICONV_E_GENERATE;
907     goto ERROR;
908   }
909   if ((res = psiconv_write_u32(config,buf,lev+1,PSICONV_ID_CLIPART_ITEM)))
910     goto ERROR;
911   if ((res = psiconv_write_u32(config,buf,lev+1,0x00000002)))
912     goto ERROR;
913   if ((res = psiconv_write_u32(config,buf,lev+1,0x00000000)))
914     goto ERROR;
915   if ((res = psiconv_write_u32(config,buf,lev+1,0x00000000)))
916     goto ERROR;
917   if ((res = psiconv_write_u32(config,buf,lev+1,0x0000000C)))
918     goto ERROR;
919   if ((res = psiconv_write_paint_data_section(config,buf,lev+1,value->picture,1)))
920     goto ERROR;
921 
922 ERROR:
923   if (res)
924     psiconv_error(config,lev,0,"Writing of clipart section failed");
925   else
926     psiconv_progress(config,lev,0,"End of clipart section");
927   return res;
928 }
929 
psiconv_write_jumptable_section(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_jumptable_section value)930 int psiconv_write_jumptable_section(const psiconv_config config,
931                                     psiconv_buffer buf, int lev,
932 				    const psiconv_jumptable_section value)
933 {
934   int res,i;
935   psiconv_u32 *offset_ptr;
936 
937   psiconv_progress(config,lev,0,"Writing jumptable section");
938 
939   if (!value) {
940     psiconv_error(config,lev,0,"NULL Jumptable Section");
941     res = -PSICONV_E_GENERATE;
942     goto ERROR;
943   }
944   if ((res = psiconv_write_u32(config,buf,lev+1,psiconv_list_length(value))))
945     goto ERROR;
946   for (i = 0; i < psiconv_list_length(value); i++) {
947     if (!(offset_ptr = psiconv_list_get(value,i))) {
948       psiconv_error(config,lev,0,"Massive memory corruption");
949       res = -PSICONV_E_NOMEM;
950       goto ERROR;
951     }
952     if ((res = psiconv_write_offset(config,buf,lev+1,*offset_ptr)))
953       goto ERROR;
954   }
955 
956 ERROR:
957   if (res)
958     psiconv_error(config,lev,0,"Writing of jumptable section failed");
959   else
960     psiconv_progress(config,lev,0,"End of jumptable section");
961   return res;
962 }
963