1 /*
2     generate_simple.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 
21 #include "config.h"
22 #include "compat.h"
23 
24 #include <string.h>
25 #include <stdlib.h>
26 
27 #include "generate_routines.h"
28 #include "error.h"
29 
30 #ifdef DMALLOC
31 #include <dmalloc.h>
32 #endif
33 
34 static int psiconv_write_string_aux(const psiconv_config config,
35                                     psiconv_buffer buf, int lev,
36 				    const psiconv_string_t value,int kind);
37 
psiconv_write_u8(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_u8 value)38 int psiconv_write_u8(const psiconv_config config,psiconv_buffer buf,
39                      int lev,const psiconv_u8 value)
40 {
41   int res;
42   psiconv_progress(config,lev,0,"Writing u8");
43   psiconv_debug(config,lev+1,0,"Value: %02x",value);
44   res = psiconv_buffer_add(buf,value);
45   if (res)
46     psiconv_error(config,lev,0,"Out of memory error");
47   return res;
48 }
49 
psiconv_write_u16(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_u16 value)50 int psiconv_write_u16(const psiconv_config config,psiconv_buffer buf,
51                       int lev,const psiconv_u16 value)
52 {
53   int res;
54   psiconv_progress(config,lev,0,"Writing u16");
55   psiconv_debug(config,lev+1,0,"Value: %04x",value);
56   if ((res = psiconv_buffer_add(buf,value & 0xff)))
57     goto ERROR;
58   if ((res = psiconv_buffer_add(buf,(value & 0xff00) >> 8)))
59     goto ERROR;
60 ERROR:
61   if (res)
62     psiconv_error(config,lev,0,"Out of memory error");
63   return res;
64 }
65 
psiconv_write_u32(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_u32 value)66 int psiconv_write_u32(const psiconv_config config,psiconv_buffer buf,
67                       int lev,const psiconv_u32 value)
68 {
69   int res;
70   psiconv_progress(config,lev,0,"Writing u32");
71   psiconv_debug(config,lev+1,0,"Value: %08x",value);
72 
73   if ((res = psiconv_buffer_add(buf,value & 0xff)))
74     goto ERROR;
75   if ((res = psiconv_buffer_add(buf,(value & 0xff00) >> 8)))
76     goto ERROR;
77   if ((res = psiconv_buffer_add(buf,(value & 0xff0000) >> 16)))
78     goto ERROR;
79   if ((res = psiconv_buffer_add(buf,(value & 0xff000000) >> 24)))
80     goto ERROR;
81 ERROR:
82   if (res)
83     psiconv_error(config,lev,0,"Out of memory error");
84   return res;
85 }
86 
psiconv_write_S(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_u32 value)87 int psiconv_write_S(const psiconv_config config,psiconv_buffer buf,
88                     int lev,const psiconv_u32 value)
89 {
90   int res;
91 
92   psiconv_progress(config,lev,0,"Writing S");
93   psiconv_debug(config,lev+1,0,"Value: %08x",value);
94   if (value < 0x40)
95     res = psiconv_write_u8(config,buf,lev+2,value * 4 + 2);
96   else if (value < 0x2000)
97     res = psiconv_write_u16(config,buf,lev+2,value * 8 + 3);
98   else {
99     psiconv_error(config,0,psiconv_buffer_length(buf),
100                  "Don't know how to write S value larger than 0x2000 "
101                  "(trying %x)",value);
102     res = -PSICONV_E_GENERATE;
103   }
104   if (res)
105     psiconv_error(config,lev,0,"Writing of S failed");
106   else
107     psiconv_progress(config,lev,0,"End of S");
108   return res;
109 }
110 
psiconv_write_X(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_u32 value)111 int psiconv_write_X(const psiconv_config config,psiconv_buffer buf,
112                     int lev, const psiconv_u32 value)
113 {
114   int res;
115   psiconv_progress(config,lev,0,"Writing X");
116   psiconv_debug(config,lev+1,0,"Value: %08x",value);
117   if (value < 0x80)
118     res = psiconv_write_u8(config,buf,lev+2,value * 2);
119   else if (value < 0x4000)
120     res = psiconv_write_u16(config,buf,lev+2,value * 4 + 1);
121   else if (value < 0x20000000)
122     res = psiconv_write_u16(config,buf,lev+2,value * 8 + 3);
123   else {
124     psiconv_error(config,lev,0,
125                  "Don't know how to write X value larger than 0x20000000 "
126                  "(trying %x)",value);
127     res = -PSICONV_E_GENERATE;
128   }
129   if (res)
130     psiconv_error(config,lev,0,"Writing of X failed");
131   else
132     psiconv_progress(config,lev,0,"End of X");
133   return res;
134 }
135 
psiconv_write_length(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_length_t value)136 int psiconv_write_length(const psiconv_config config,psiconv_buffer buf,
137                          int lev,const psiconv_length_t value)
138 {
139   int res;
140   psiconv_progress(config,lev,0,"Writing length");
141   psiconv_debug(config,lev+1,0,"Value: %f",value);
142   res = psiconv_write_u32(config,buf,lev+2,value * (1440.0/2.54) + 0.5);
143   if (res)
144     psiconv_error(config,lev,0,"Writing of length failed");
145   else
146     psiconv_progress(config,lev,0,"End of length");
147   return res;
148 }
149 
psiconv_write_size(const psiconv_config config,psiconv_buffer buf,int lev,psiconv_size_t value)150 int psiconv_write_size(const psiconv_config config,psiconv_buffer buf,
151                        int lev, psiconv_size_t value)
152 {
153   int res;
154   psiconv_progress(config,lev,0,"Writing size");
155   psiconv_debug(config,lev+1,0,"Value: %f",value);
156   res = psiconv_write_u32(config,buf,lev+2,value * 20.0 + 0.5);
157   if (res)
158     psiconv_error(config,lev,0,"Writing of size failed");
159   else
160     psiconv_progress(config,lev,0,"End of size");
161   return res;
162 }
163 
psiconv_write_bool(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_bool_t value)164 int psiconv_write_bool(const psiconv_config config,psiconv_buffer buf,
165                        int lev,const psiconv_bool_t value)
166 {
167   int res;
168   psiconv_progress(config,lev,0,"Writing bool");
169   psiconv_debug(config,lev+1,0,"Value: %s",
170                 value == psiconv_bool_false?"False":"True");
171   if ((value != psiconv_bool_true) && (value != psiconv_bool_false))
172     psiconv_warn(config,0,psiconv_buffer_length(buf),
173                  "Boolean has non-enum value (found %d, used true)",value);
174   res = psiconv_write_u8(config,buf,lev+2,value == psiconv_bool_false?0:1);
175   if (res)
176     psiconv_error(config,lev,0,"Writing of bool failed");
177   else
178     psiconv_progress(config,lev,0,"End of bool");
179   return res;
180 }
181 
psiconv_write_string(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_string_t value)182 int psiconv_write_string(const psiconv_config config,psiconv_buffer buf,
183                          int lev, const psiconv_string_t value)
184 {
185   int res;
186   psiconv_progress(config,lev,0,"Writing string");
187   res = psiconv_write_string_aux(config,buf,lev+1,value,-1);
188   if (res)
189     psiconv_error(config,lev,0,"Writing of string failed");
190   else
191     psiconv_progress(config,lev,0,"End of string");
192   return res;
193 }
194 
psiconv_write_short_string(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_string_t value)195 int psiconv_write_short_string(const psiconv_config config,psiconv_buffer buf,
196                                int lev,const psiconv_string_t value)
197 {
198   int res;
199   psiconv_progress(config,lev,0,"Writing short string");
200   res = psiconv_write_string_aux(config,buf,lev+1,value,-2);
201   if (res)
202     psiconv_error(config,lev,0,"Writing of short string failed");
203   else
204     psiconv_progress(config,lev,0,"End of short string");
205   return res;
206 }
207 
psiconv_write_charlist(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_string_t value)208 int psiconv_write_charlist(const psiconv_config config,psiconv_buffer buf,
209                            int lev,const psiconv_string_t value)
210 {
211   int res;
212   psiconv_progress(config,lev,0,"Writing charlist");
213   res = psiconv_write_string_aux(config,buf,lev+1,value,0);
214   if (res)
215     psiconv_error(config,lev,0,"Writing of charlist failed");
216   else
217     psiconv_progress(config,lev,0,"End of charlist");
218   return res;
219 }
220 
221 
psiconv_write_string_aux(const psiconv_config config,psiconv_buffer buf,int lev,const psiconv_string_t value,int kind)222 int psiconv_write_string_aux(const psiconv_config config,psiconv_buffer buf,
223                              int lev, const psiconv_string_t value,int kind)
224 {
225   int res,i,len;
226   char *printable;
227 
228   len = psiconv_unicode_strlen(value);
229   if (!value) {
230     psiconv_error(config,lev,0, "NULL string");
231     return -PSICONV_E_GENERATE;
232   }
233 
234   if (!(printable = psiconv_make_printable(config,value))) {
235     psiconv_error(config,lev,0,"Out of memory error");
236     return -PSICONV_E_NOMEM;
237   }
238   psiconv_debug(config,lev+1,0,"Value: %s",printable);
239   free(printable);
240 
241   if (kind == -1)
242     res = psiconv_write_S(config,buf,lev+2,len);
243   else if (kind == -2)
244     res = psiconv_write_u8(config,buf,lev+2,len);
245   else
246     res = 0;
247   if (res)
248     return res;
249 
250   for (i = 0; i < len; i++)
251     if ((res = psiconv_unicode_write_char(config,buf,lev+2,value[i])))
252       return res;
253   return -PSICONV_E_OK;
254 }
255 
psiconv_write_offset(const psiconv_config config,psiconv_buffer buf,int lev,psiconv_u32 id)256 int psiconv_write_offset(const psiconv_config config,psiconv_buffer buf,
257                          int lev,psiconv_u32 id)
258 {
259   int res;
260   psiconv_progress(config,lev,0,"Writing offset");
261   psiconv_debug(config,lev+1,0,"ID: %08x",id);
262   res = psiconv_buffer_add_reference(buf,id);
263   if (res)
264     psiconv_error(config,lev,0,"Out of memory error");
265   return res;
266 }
267