1 /*
2     buffer.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 <stdlib.h>
25 
26 #include "list.h"
27 #include "error.h"
28 #include "buffer.h"
29 
30 #ifdef DMALLOC
31 #include <dmalloc.h>
32 #endif
33 
34 typedef struct psiconv_relocation_s {
35   psiconv_u32 offset;
36   int id;
37 } *psiconv_relocation;
38 
39 struct psiconv_buffer_s {
40   psiconv_list reloc_target; /* of struct relocation_s */
41   psiconv_list reloc_ref; /* of struct relocation_s */
42   psiconv_list data; /* of psiconv_u8 */
43 };
44 
45 static psiconv_u32 unique_id = 1;
46 
psiconv_buffer_unique_id(void)47 psiconv_u32 psiconv_buffer_unique_id(void)
48 {
49   return unique_id ++;
50 }
51 
psiconv_buffer_new(void)52 psiconv_buffer psiconv_buffer_new(void)
53 {
54   psiconv_buffer buf;
55   if (!(buf = malloc(sizeof(*buf))))
56     goto ERROR1;
57   if (!(buf->data = psiconv_list_new(sizeof(psiconv_u8))))
58     goto ERROR2;
59   if (!(buf->reloc_target = psiconv_list_new(
60                                    sizeof(struct psiconv_relocation_s))))
61     goto ERROR3;
62   if (!(buf->reloc_ref = psiconv_list_new(
63                                    sizeof(struct psiconv_relocation_s))))
64     goto ERROR4;
65   return buf;
66 ERROR4:
67   psiconv_list_free(buf->reloc_target);
68 ERROR3:
69   psiconv_list_free(buf->data);
70 ERROR2:
71   free(buf);
72 ERROR1:
73   return NULL;
74 }
75 
psiconv_buffer_free(psiconv_buffer buf)76 void psiconv_buffer_free(psiconv_buffer buf)
77 {
78   psiconv_list_free(buf->reloc_ref);
79   psiconv_list_free(buf->reloc_target);
80   psiconv_list_free(buf->data);
81   free(buf);
82 }
83 
psiconv_buffer_length(const psiconv_buffer buf)84 psiconv_u32 psiconv_buffer_length(const psiconv_buffer buf)
85 {
86   return psiconv_list_length(buf->data);
87 }
88 
psiconv_buffer_get(const psiconv_buffer buf,psiconv_u32 off)89 psiconv_u8 *psiconv_buffer_get(const psiconv_buffer buf, psiconv_u32 off)
90 {
91   return psiconv_list_get(buf->data,off);
92 }
93 
psiconv_buffer_add(psiconv_buffer buf,psiconv_u8 data)94 int psiconv_buffer_add(psiconv_buffer buf,psiconv_u8 data)
95 {
96   return psiconv_list_add(buf->data,&data);
97 }
98 
psiconv_buffer_fread(psiconv_buffer buf,size_t size,FILE * f)99 size_t psiconv_buffer_fread(psiconv_buffer buf, size_t size, FILE *f)
100 {
101   return psiconv_list_fread(buf->data,size,f);
102 }
103 
psiconv_buffer_fread_all(psiconv_buffer buf,FILE * f)104 int psiconv_buffer_fread_all(psiconv_buffer buf, FILE *f)
105 {
106   return psiconv_list_fread_all(buf->data,f);
107 }
108 
psiconv_buffer_fwrite_all(const psiconv_buffer buf,FILE * f)109 int psiconv_buffer_fwrite_all(const psiconv_buffer buf, FILE *f)
110 {
111   return psiconv_list_fwrite_all(buf->data,f);
112 }
113 
psiconv_buffer_subbuffer(psiconv_buffer * buf,const psiconv_buffer org,psiconv_u32 offset,psiconv_u32 length)114 int psiconv_buffer_subbuffer(psiconv_buffer *buf, const psiconv_buffer org,
115                              psiconv_u32 offset, psiconv_u32 length)
116 {
117   int i;
118   int res;
119   psiconv_u8 *data;
120   if (! (*buf = psiconv_buffer_new())) {
121     res = PSICONV_E_NOMEM;
122     goto ERROR1;
123   }
124   for (i = 0; i < length; i++) {
125     if (!(data = psiconv_buffer_get(org,offset+i))) {
126       res = PSICONV_E_OTHER;
127       goto ERROR2;
128     }
129     if ((res = psiconv_buffer_add(*buf,*data))) {
130       goto ERROR2;
131     }
132   }
133   return 0;
134 
135 ERROR2:
136 	psiconv_buffer_free(*buf);
137 ERROR1:
138 	return res;
139 }
140 
psiconv_buffer_concat(psiconv_buffer buf,const psiconv_buffer extra)141 int psiconv_buffer_concat(psiconv_buffer buf, const psiconv_buffer extra)
142 {
143   int res;
144   psiconv_u32 i;
145   psiconv_relocation reloc;
146 
147 
148   for (i = 0; i < psiconv_list_length(extra->reloc_target); i++) {
149     if (!(reloc = psiconv_list_get(extra->reloc_target,i)))
150       return -PSICONV_E_OTHER;
151     reloc->offset += psiconv_list_length(buf->data);
152     if ((res=psiconv_list_add(buf->reloc_target,reloc)))
153       return res;
154   }
155   for (i = 0; i < psiconv_list_length(extra->reloc_ref); i++) {
156     if (!(reloc = psiconv_list_get(extra->reloc_ref,i)))
157       return -PSICONV_E_OTHER;
158     reloc->offset += psiconv_list_length(buf->data);
159     if ((res = psiconv_list_add(buf->reloc_ref,reloc)))
160       return res;
161   }
162   return psiconv_list_concat(buf->data,extra->data);
163 }
164 
psiconv_buffer_resolve(psiconv_buffer buf)165 int psiconv_buffer_resolve(psiconv_buffer buf)
166 {
167   int res;
168   psiconv_u32 i,j,temp;
169   psiconv_relocation target,ref;
170 
171   for (i = 0; i < psiconv_list_length(buf->reloc_ref);i++) {
172     if (!(ref = psiconv_list_get(buf->reloc_ref,i)))
173       return -PSICONV_E_OTHER;
174     for (j = 0;  j < psiconv_list_length(buf->reloc_target);j++) {
175       if (!(target = psiconv_list_get(buf->reloc_target,j)))
176         return -PSICONV_E_OTHER;
177       if (ref->id == target->id) {
178         temp = target->offset & 0xff;
179         if ((res = psiconv_list_replace(buf->data,ref->offset,&temp)))
180           return -PSICONV_E_OTHER;
181         temp = (target->offset >> 8) & 0xff;
182         if ((res = psiconv_list_replace(buf->data,ref->offset + 1,&temp)))
183           return -PSICONV_E_OTHER;
184         temp = (target->offset >> 16) & 0xff;
185         if ((res = psiconv_list_replace(buf->data,ref->offset + 2,&temp)))
186           return -PSICONV_E_OTHER;
187         temp = (target->offset >> 24) & 0xff;
188         if ((res = psiconv_list_replace(buf->data,ref->offset + 3,&temp)))
189           return -PSICONV_E_OTHER;
190         break;
191       }
192     }
193     if (j == psiconv_list_length(buf->reloc_target))
194       return -PSICONV_E_OTHER;
195   }
196   psiconv_list_empty(buf->reloc_target);
197   psiconv_list_empty(buf->reloc_ref);
198   return -PSICONV_E_OK;
199 }
200 
psiconv_buffer_add_reference(psiconv_buffer buf,int id)201 int psiconv_buffer_add_reference(psiconv_buffer buf,int id)
202 {
203   struct psiconv_relocation_s reloc;
204   int res,i;
205   psiconv_u8 data;
206 
207   reloc.offset = psiconv_list_length(buf->data);
208   reloc.id = id;
209   if ((res = psiconv_list_add(buf->reloc_ref,&reloc)))
210     return res;
211   data = 0x00;
212   for (i = 0; i < 4; i++)
213     if ((res = psiconv_list_add(buf->data,&data)))
214       return res;
215   return -PSICONV_E_OK;
216 }
217 
psiconv_buffer_add_target(psiconv_buffer buf,int id)218 int psiconv_buffer_add_target(psiconv_buffer buf, int id)
219 {
220   struct psiconv_relocation_s reloc;
221 
222   reloc.offset = psiconv_list_length(buf->data);
223   reloc.id = id;
224   return psiconv_list_add(buf->reloc_target,&reloc);
225 }
226