1 /*
2     generate_driver.c - Part of psiconv, a PSION 5 file formats converter
3     Copyright (c) 2000-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 <stdlib.h>
24 
25 #include "error.h"
26 #include "generate_routines.h"
27 
28 #ifdef DMALLOC
29 #include <dmalloc.h>
30 #endif
31 
32 static psiconv_ucs2 unicode_paint[10] = { 'P','a','i','n','t','.','a','p','p',0 };
33 static psiconv_ucs2 unicode_texted[11] ={ 'T','e','x','t','E','d','.','a','p','p',0 };
34 static psiconv_ucs2 unicode_word[9] =   { 'W','o','r','d','.','a','p','p',0 };
35 
36 
psiconv_write(const psiconv_config config,psiconv_buffer * buf,const psiconv_file value)37 int psiconv_write(const psiconv_config config, psiconv_buffer *buf,
38                   const psiconv_file value)
39 {
40   int res;
41   int lev = 0;
42 
43   if (!value) {
44     psiconv_error(config,0,0,"Can't parse to an empty buffer!");
45     return -PSICONV_E_OTHER;
46   }
47   if (!(*buf = psiconv_buffer_new())) {
48     psiconv_error(config,lev+1,0,"Out of memory error");
49     return -PSICONV_E_NOMEM;
50   }
51 
52   if (value->type == psiconv_word_file) {
53     if ((res = psiconv_write_header_section(config,*buf,lev+1,PSICONV_ID_PSION5,
54                                             PSICONV_ID_DATA_FILE,
55                                             PSICONV_ID_WORD)))
56       goto ERROR;
57     if ((res =psiconv_write_word_file(config,*buf,lev+1,(psiconv_word_f) (value->file))))
58       goto ERROR;
59   } else if (value->type == psiconv_texted_file) {
60     if ((res = psiconv_write_header_section(config,*buf,lev+1,PSICONV_ID_PSION5,
61                                             PSICONV_ID_DATA_FILE,
62                                             PSICONV_ID_TEXTED)))
63       goto ERROR;
64     if ((res =psiconv_write_texted_file(config,*buf,lev+1,
65                                            (psiconv_texted_f) (value->file))))
66       goto ERROR;
67   } else if (value->type == psiconv_sketch_file) {
68     if ((res = psiconv_write_header_section(config,*buf,lev+1,PSICONV_ID_PSION5,
69                                             PSICONV_ID_DATA_FILE,
70                                             PSICONV_ID_SKETCH)))
71       goto ERROR;
72     if ((res =psiconv_write_sketch_file(config,*buf,lev+1,
73                                            (psiconv_sketch_f) (value->file))))
74       goto ERROR;
75   } else if (value->type == psiconv_mbm_file) {
76     if ((res = psiconv_write_header_section(config,*buf,lev+1,PSICONV_ID_PSION5,
77                                             PSICONV_ID_MBM_FILE,
78                                             0x00000000)))
79       goto ERROR;
80     if ((res =psiconv_write_mbm_file(config,*buf,lev+1,
81                                            (psiconv_mbm_f) (value->file))))
82       goto ERROR;
83   } else if (value->type == psiconv_clipart_file) {
84     /* No complete header section, so we do it all in the below function */
85     if ((res =psiconv_write_clipart_file(config,*buf,lev+1,
86                                            (psiconv_clipart_f) (value->file))))
87       goto ERROR;
88   } else {
89     psiconv_error(config,0,0,"Unknown or unsupported file type");
90     res = -PSICONV_E_GENERATE;
91     goto ERROR;
92   }
93   if ((res = psiconv_buffer_resolve(*buf))) {
94     psiconv_error(config,lev+1,0,"Internal error resolving buffer references");
95     goto ERROR;
96   }
97   return -PSICONV_E_OK;
98 
99 ERROR:
100   psiconv_buffer_free(*buf);
101   return res;
102 }
103 
psiconv_write_texted_file(const psiconv_config config,psiconv_buffer buf,int lev,psiconv_texted_f value)104 int psiconv_write_texted_file(const psiconv_config config,
105                               psiconv_buffer buf,int lev,psiconv_texted_f value)
106 {
107   psiconv_character_layout base_char;
108   psiconv_paragraph_layout base_para;
109   int res;
110   psiconv_section_table_section section_table;
111   psiconv_section_table_entry entry;
112   psiconv_u32 section_table_id;
113   psiconv_buffer buf_texted;
114 
115   psiconv_progress(config,lev,0,"Writing texted file");
116   if (!value) {
117     psiconv_error(config,lev,0,"Null TextEd file");
118     res = -PSICONV_E_GENERATE;
119     goto ERROR1;
120   }
121 
122   if (!(section_table = psiconv_list_new(sizeof(*entry)))) {
123     psiconv_error(config,lev+1,0,"Out of memory error");
124     res = -PSICONV_E_NOMEM;
125     goto ERROR1;
126   }
127 
128   if (!(entry = malloc(sizeof(*entry)))) {
129     psiconv_error(config,lev+1,0,"Out of memory error");
130     res = -PSICONV_E_NOMEM;
131     goto ERROR2;
132   }
133 
134   if (!(base_char = psiconv_basic_character_layout())) {
135     psiconv_error(config,lev+1,0,"Out of memory error");
136     res = -PSICONV_E_NOMEM;
137     goto ERROR3;
138   }
139   if (!(base_para = psiconv_basic_paragraph_layout())) {
140     psiconv_error(config,lev+1,0,"Out of memory error");
141     res = -PSICONV_E_NOMEM;
142     goto ERROR4;
143   }
144 
145   section_table_id = psiconv_buffer_unique_id();
146   if ((res = psiconv_write_offset(config,buf,lev+1,section_table_id))) {
147     psiconv_error(config,lev+1,0,"Out of memory error");
148     goto ERROR5;
149   }
150 
151   entry->id = PSICONV_ID_APPL_ID_SECTION;
152   entry->offset = psiconv_buffer_unique_id();
153   if ((res = psiconv_list_add(section_table,entry))) {
154     psiconv_error(config,lev+1,0,"Out of memory error");
155     goto ERROR5;
156   }
157   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
158     psiconv_error(config,lev+1,0,"Out of memory error");
159     goto ERROR5;
160   }
161   if ((res=psiconv_write_application_id_section(config,buf,lev+1,
162                                            PSICONV_ID_TEXTED,unicode_texted)))
163     goto ERROR5;
164 
165   entry->id = PSICONV_ID_PAGE_LAYOUT_SECTION;
166   entry->offset = psiconv_buffer_unique_id();
167   if ((res = psiconv_list_add(section_table,entry))) {
168     psiconv_error(config,lev+1,0,"Out of memory error");
169     goto ERROR5;
170   }
171   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
172     psiconv_error(config,lev+1,0,"Out of memory error");
173     goto ERROR5;
174   }
175   if ((res = psiconv_write_page_layout_section(config,buf,lev+1,value->page_sec)))
176     goto ERROR5;
177 
178   entry->id = PSICONV_ID_TEXTED;
179   entry->offset = psiconv_buffer_unique_id();
180   if ((res = psiconv_list_add(section_table,entry))) {
181     psiconv_error(config,lev+1,0,"Out of memory error");
182     goto ERROR5;
183   }
184   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
185     psiconv_error(config,lev+1,0,"Out of memory error");
186     goto ERROR5;
187   }
188   if ((res = psiconv_write_texted_section(config,buf,lev+1,value->texted_sec,
189                                            base_char,base_para,&buf_texted)))
190     goto ERROR5;
191 
192   if ((res = psiconv_buffer_concat(buf,buf_texted))) {
193     psiconv_error(config,lev+1,0,"Out of memory error");
194     goto ERROR6;
195   }
196 
197   if ((res = psiconv_buffer_add_target(buf,section_table_id))) {
198     psiconv_error(config,lev+1,0,"Out of memory error");
199     goto ERROR6;
200   }
201 
202   res = psiconv_write_section_table_section(config,buf,lev+1,section_table);
203 
204 ERROR6:
205   psiconv_buffer_free(buf_texted);
206 ERROR5:
207   psiconv_free_paragraph_layout(base_para);
208 ERROR4:
209   psiconv_free_character_layout(base_char);
210 ERROR3:
211   free(entry);
212 ERROR2:
213   psiconv_list_free(section_table);
214 ERROR1:
215   if (res)
216     psiconv_error(config,lev,0,"Writing of texted file failed");
217   else
218     psiconv_progress(config,lev,0,"End of texted file");
219   return res;
220 }
221 
psiconv_write_word_file(const psiconv_config config,psiconv_buffer buf,int lev,psiconv_word_f value)222 int psiconv_write_word_file(const psiconv_config config,
223                             psiconv_buffer buf,int lev,psiconv_word_f value)
224 {
225   int res;
226   psiconv_section_table_section section_table;
227   psiconv_section_table_entry entry;
228   psiconv_u32 section_table_id;
229 
230   psiconv_progress(config,lev,0,"Writing word file");
231   if (!value) {
232     psiconv_error(config,lev,0,"Null Word file");
233     res = -PSICONV_E_GENERATE;
234     goto ERROR1;
235   }
236 
237   if (!(section_table = psiconv_list_new(sizeof(*entry)))) {
238     psiconv_error(config,lev+1,0,"Out of memory error");
239     res = -PSICONV_E_NOMEM;
240     goto ERROR1;
241   }
242 
243   if (!(entry = malloc(sizeof(*entry)))) {
244     psiconv_error(config,lev+1,0,"Out of memory error");
245     res = -PSICONV_E_NOMEM;
246     goto ERROR2;
247   }
248 
249   section_table_id = psiconv_buffer_unique_id();
250   if ((res = psiconv_write_offset(config,buf,lev+1,section_table_id)))
251     goto ERROR3;
252 
253   entry->id = PSICONV_ID_APPL_ID_SECTION;
254   entry->offset = psiconv_buffer_unique_id();
255   if ((res = psiconv_list_add(section_table,entry))) {
256     psiconv_error(config,lev+1,0,"Out of memory error");
257     goto ERROR3;
258   }
259   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
260     psiconv_error(config,lev+1,0,"Out of memory error");
261     goto ERROR3;
262   }
263   if ((res=psiconv_write_application_id_section(config,buf,lev+1,
264                                            PSICONV_ID_WORD,unicode_word)))
265     goto ERROR3;
266 
267   entry->id = PSICONV_ID_WORD_STATUS_SECTION;
268   entry->offset = psiconv_buffer_unique_id();
269   if ((res = psiconv_list_add(section_table,entry))) {
270     psiconv_error(config,lev+1,0,"Out of memory error");
271     goto ERROR3;
272   }
273   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
274     psiconv_error(config,lev+1,0,"Out of memory error");
275     goto ERROR3;
276   }
277   if ((res = psiconv_write_word_status_section(config,buf,lev+1,value->status_sec)))
278     goto ERROR3;
279 
280   entry->id = PSICONV_ID_PAGE_LAYOUT_SECTION;
281   entry->offset = psiconv_buffer_unique_id();
282   if ((res = psiconv_list_add(section_table,entry))) {
283     psiconv_error(config,lev+1,0,"Out of memory error");
284     goto ERROR3;
285   }
286   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
287     psiconv_error(config,lev+1,0,"Out of memory error");
288     goto ERROR3;
289   }
290   if ((res = psiconv_write_page_layout_section(config,buf,lev+1,value->page_sec)))
291     goto ERROR3;
292 
293   entry->id = PSICONV_ID_WORD_STYLES_SECTION;
294   entry->offset = psiconv_buffer_unique_id();
295   if ((res = psiconv_list_add(section_table,entry))) {
296     psiconv_error(config,lev+1,0,"Out of memory error");
297     goto ERROR3;
298   }
299   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
300     psiconv_error(config,lev+1,0,"Out of memory error");
301     goto ERROR3;
302   }
303   if ((res = psiconv_write_word_styles_section(config,buf,lev+1,value->styles_sec)))
304     goto ERROR3;
305 
306   entry->id = PSICONV_ID_TEXT_SECTION;
307   entry->offset = psiconv_buffer_unique_id();
308   if ((res = psiconv_list_add(section_table,entry))) {
309     psiconv_error(config,lev+1,0,"Out of memory error");
310     goto ERROR3;
311   }
312   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
313     psiconv_error(config,lev+1,0,"Out of memory error");
314     goto ERROR3;
315   }
316   if ((res = psiconv_write_text_section(config,buf,lev+1,value->paragraphs)))
317     goto ERROR3;
318 
319   entry->id = PSICONV_ID_LAYOUT_SECTION;
320   entry->offset = psiconv_buffer_unique_id();
321   if ((res = psiconv_list_add(section_table,entry))) {
322     psiconv_error(config,lev+1,0,"Out of memory error");
323     goto ERROR3;
324   }
325   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
326     psiconv_error(config,lev+1,0,"Out of memory error");
327     goto ERROR3;
328   }
329   if ((res = psiconv_write_styled_layout_section(config,buf,lev+1,value->paragraphs,
330                                                  value->styles_sec)))
331     goto ERROR3;
332 
333   if ((res = psiconv_buffer_add_target(buf,section_table_id))) {
334     psiconv_error(config,lev+1,0,"Out of memory error");
335     goto ERROR3;
336   }
337 
338   res = psiconv_write_section_table_section(config,buf,lev+1,section_table);
339 
340 ERROR3:
341   free(entry);
342 ERROR2:
343   psiconv_list_free(section_table);
344 ERROR1:
345   if (res)
346     psiconv_error(config,lev,0,"Writing of word file failed");
347   else
348     psiconv_progress(config,lev,0,"End of word file");
349   return res;
350 }
351 
psiconv_write_sketch_file(const psiconv_config config,psiconv_buffer buf,int lev,psiconv_sketch_f value)352 int psiconv_write_sketch_file(const psiconv_config config,
353                               psiconv_buffer buf,int lev,psiconv_sketch_f value)
354 {
355   int res;
356   psiconv_section_table_section section_table;
357   psiconv_section_table_entry entry;
358   psiconv_u32 section_table_id;
359 
360   psiconv_progress(config,lev,0,"Writing sketch file");
361   if (!value) {
362     psiconv_error(config,lev,0,"Null Sketch file");
363     res = -PSICONV_E_GENERATE;
364     goto ERROR1;
365   }
366 
367   if (!(section_table = psiconv_list_new(sizeof(*entry)))) {
368     psiconv_error(config,lev+1,0,"Out of memory error");
369     res = -PSICONV_E_NOMEM;
370     goto ERROR1;
371   }
372 
373   if (!(entry = malloc(sizeof(*entry)))) {
374     psiconv_error(config,lev+1,0,"Out of memory error");
375     res = -PSICONV_E_NOMEM;
376     goto ERROR2;
377   }
378 
379   section_table_id = psiconv_buffer_unique_id();
380   if ((res = psiconv_write_offset(config,buf,lev+1,section_table_id)))
381     goto ERROR3;
382 
383   entry->id = PSICONV_ID_APPL_ID_SECTION;
384   entry->offset = psiconv_buffer_unique_id();
385   if ((res = psiconv_list_add(section_table,entry))) {
386     psiconv_error(config,lev+1,0,"Out of memory error");
387     goto ERROR3;
388   }
389   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
390     psiconv_error(config,lev+1,0,"Out of memory error");
391     goto ERROR3;
392   }
393   if ((res=psiconv_write_application_id_section(config,buf,lev+1,
394                                            PSICONV_ID_SKETCH,unicode_paint)))
395     goto ERROR3;
396 
397   entry->id = PSICONV_ID_SKETCH_SECTION;
398   entry->offset = psiconv_buffer_unique_id();
399   if ((res = psiconv_list_add(section_table,entry))) {
400     psiconv_error(config,lev+1,0,"Out of memory error");
401     goto ERROR3;
402   }
403   if ((res = psiconv_buffer_add_target(buf,entry->offset))) {
404     psiconv_error(config,lev+1,0,"Out of memory error");
405     goto ERROR3;
406   }
407   if ((res = psiconv_write_sketch_section(config,buf,lev+1,value->sketch_sec)))
408     goto ERROR3;
409 
410   if ((res = psiconv_buffer_add_target(buf,section_table_id))) {
411     psiconv_error(config,lev+1,0,"Out of memory error");
412     goto ERROR3;
413   }
414   res = psiconv_write_section_table_section(config,buf,lev+1,section_table);
415 
416 ERROR3:
417   free(entry);
418 ERROR2:
419   psiconv_list_free(section_table);
420 ERROR1:
421   if (res)
422     psiconv_error(config,lev,0,"Writing of sketch file failed");
423   else
424     psiconv_progress(config,lev,0,"End of sketch file");
425   return res;
426 }
427 
psiconv_write_mbm_file(const psiconv_config config,psiconv_buffer buf,int lev,psiconv_mbm_f value)428 int psiconv_write_mbm_file(const psiconv_config config,
429                            psiconv_buffer buf,int lev,psiconv_mbm_f value)
430 {
431   int res,i;
432   psiconv_jumptable_section jumptable;
433   psiconv_u32 *entry,id,table_id;
434   psiconv_paint_data_section section;
435 
436   psiconv_progress(config,lev,0,"Writing mbm file");
437   if (!value) {
438     psiconv_error(config,lev,0,"Null MBM file");
439     res = -PSICONV_E_GENERATE;
440     goto ERROR1;
441   }
442 
443   if (!(jumptable = psiconv_list_new(sizeof(*entry)))) {
444     psiconv_error(config,lev+1,0,"Out of memory error");
445     res = -PSICONV_E_NOMEM;
446     goto ERROR1;
447   }
448 
449   table_id = psiconv_buffer_unique_id();
450   if ((res = psiconv_buffer_add_reference(buf,table_id))) {
451     psiconv_error(config,lev+1,0,"Out of memory error");
452     goto ERROR2;
453   }
454 
455   for (i = 0; i < psiconv_list_length(value->sections); i++) {
456     if (!(section = psiconv_list_get(value->sections,i))) {
457       psiconv_error(config,lev,0,"Data structure corruption");
458       res = -PSICONV_E_NOMEM;
459       goto ERROR2;
460     }
461     id = psiconv_buffer_unique_id();
462     if ((res = psiconv_list_add(jumptable,&id))) {
463       psiconv_error(config,lev+1,0,"Out of memory error");
464       goto ERROR2;
465      }
466     if ((res = psiconv_buffer_add_target(buf,id))) {
467       psiconv_error(config,lev+1,0,"Out of memory error");
468       goto ERROR2;
469     }
470     if ((res = psiconv_write_paint_data_section(config,buf,lev+1,section,0)))
471       goto ERROR2;
472   }
473 
474   if ((res = psiconv_buffer_add_target(buf,table_id))) {
475     psiconv_error(config,lev+1,0,"Out of memory error");
476     goto ERROR2;
477   }
478   if ((res = psiconv_write_jumptable_section(config,buf,lev+1,jumptable)))
479     goto ERROR2;
480 
481 
482 ERROR2:
483   psiconv_list_free(jumptable);
484 ERROR1:
485   if (res)
486     psiconv_error(config,lev,0,"Writing of mbm file failed");
487   else
488     psiconv_progress(config,lev,0,"End of mbm file");
489   return res;
490 }
491 
492 /* Note: this file is special, because it does not have a complete header! */
psiconv_write_clipart_file(const psiconv_config config,psiconv_buffer buf,int lev,psiconv_clipart_f value)493 int psiconv_write_clipart_file(const psiconv_config config,
494                            psiconv_buffer buf,int lev,psiconv_clipart_f value)
495 {
496   int res,i;
497   psiconv_jumptable_section jumptable;
498   psiconv_u32 *entry,id;
499   psiconv_clipart_section section;
500   psiconv_buffer sec_buf;
501 
502   psiconv_progress(config,lev,0,"Writing clipart file");
503   if (!value) {
504     psiconv_error(config,lev,0,"Null Clipart file");
505     res = -PSICONV_E_GENERATE;
506     goto ERROR1;
507   }
508 
509   if (!(jumptable = psiconv_list_new(sizeof(*entry)))) {
510     psiconv_error(config,lev+1,0,"Out of memory error");
511     res = -PSICONV_E_NOMEM;
512     goto ERROR1;
513   }
514 
515   if (!(sec_buf = psiconv_buffer_new())) {
516     psiconv_error(config,lev+1,0,"Out of memory error");
517     res = -PSICONV_E_NOMEM;
518     goto ERROR2;
519   }
520 
521   if ((res = psiconv_write_u32(config,buf,lev+1,PSICONV_ID_CLIPART)))
522     goto ERROR3;
523 
524   for (i = 0; i < psiconv_list_length(value->sections); i++) {
525     if (!(section = psiconv_list_get(value->sections,i))) {
526       psiconv_error(config,lev,0,"Data structure corruption");
527       res = -PSICONV_E_NOMEM;
528       goto ERROR3;
529     }
530     id = psiconv_buffer_unique_id();
531     if ((res = psiconv_list_add(jumptable,&id))) {
532       psiconv_error(config,lev+1,0,"Out of memory error");
533       goto ERROR3;
534     }
535     if ((res = psiconv_buffer_add_target(sec_buf,id))) {
536       psiconv_error(config,lev+1,0,"Out of memory error");
537       goto ERROR3;
538     }
539     if ((res = psiconv_write_clipart_section(config,sec_buf, lev+1,section)))
540       goto ERROR3;
541   }
542 
543   if ((res = psiconv_write_jumptable_section(config,buf,lev+1,jumptable)))
544     goto ERROR3;
545 
546   if ((res = psiconv_buffer_concat(buf,sec_buf))) {
547     psiconv_error(config,lev+1,0,"Out of memory error");
548     goto ERROR3;
549   }
550 
551 
552 ERROR3:
553   psiconv_buffer_free(sec_buf);
554 ERROR2:
555   psiconv_list_free(jumptable);
556 ERROR1:
557   if (res)
558     psiconv_error(config,lev,0,"Writing of clipart file failed");
559   else
560     psiconv_progress(config,lev,0,"End of clipart file");
561   return res;
562 }
563