28 |
28 |
29 #include "data_buffer.h" |
29 #include "data_buffer.h" |
30 |
30 |
31 // ============================================================================ |
31 // ============================================================================ |
32 // |
32 // |
33 void data_buffer::merge (data_buffer* other) |
33 data_buffer::data_buffer (int size) |
|
34 { |
|
35 set_writepos (get_buffer()); |
|
36 set_buffer (new byte[size]); |
|
37 set_allocated_size (size); |
|
38 } |
|
39 |
|
40 // ============================================================================ |
|
41 // |
|
42 data_buffer::~data_buffer() |
|
43 { |
|
44 assert (count_marks() == 0 && count_refs() == 0); |
|
45 delete get_buffer(); |
|
46 } |
|
47 |
|
48 // ============================================================================ |
|
49 // |
|
50 void data_buffer::merge_and_destroy (data_buffer* other) |
34 { |
51 { |
35 if (!other) |
52 if (!other) |
36 return; |
53 return; |
37 |
54 |
38 int oldsize = writesize; |
55 int oldsize = get_write_size(); |
39 |
56 copy_buffer (other); |
40 for (int x = 0; x < other->writesize; x++) |
57 |
41 write (* (other->buffer + x)); |
58 // Assimilate in its marks and references |
42 |
59 for (byte_mark* mark : other->get_marks()) |
43 // Merge its marks and references |
|
44 int u = 0; |
|
45 |
|
46 for (u = 0; u < MAX_MARKS; u++) |
|
47 { |
60 { |
48 if (other->marks[u]) |
61 mark->pos += oldsize; |
49 { |
62 push_to_marks (mark); |
50 // Merge the mark and offset its position. |
|
51 if (marks[u]) |
|
52 error ("DataBuffer: duplicate mark %d!\n"); |
|
53 |
|
54 marks[u] = other->marks[u]; |
|
55 marks[u]->pos += oldsize; |
|
56 |
|
57 // The original mark becomes null so that the deconstructor |
|
58 // will not delete it prematurely. (should it delete any |
|
59 // marks in the first place since there is no such thing |
|
60 // as at temporary mark?) |
|
61 other->marks[u] = null; |
|
62 } |
|
63 |
|
64 if (other->refs[u]) |
|
65 { |
|
66 // Same for references |
|
67 // TODO: add a g_NextRef system like here, akin to marks! |
|
68 int r = add_reference (other->refs[u]->num, false); |
|
69 refs[r]->pos = other->refs[u]->pos + oldsize; |
|
70 } |
|
71 } |
63 } |
72 |
64 |
|
65 for (mark_reference* ref : other->get_refs()) |
|
66 { |
|
67 ref->pos += oldsize; |
|
68 push_to_refs (ref); |
|
69 } |
|
70 |
|
71 clear_marks(); |
|
72 clear_refs(); |
73 delete other; |
73 delete other; |
74 } |
74 } |
75 |
75 |
76 // ============================================================================ |
76 // ============================================================================ |
77 // |
77 // |
78 data_buffer* data_buffer::clone() |
78 data_buffer* data_buffer::clone() |
79 { |
79 { |
80 data_buffer* other = new data_buffer; |
80 data_buffer* other = new data_buffer; |
81 |
81 other->copy_buffer (this); |
82 for (int x = 0; x < writesize; x++) |
|
83 other->write (* (buffer + x)); |
|
84 |
|
85 return other; |
82 return other; |
86 } |
83 } |
87 |
84 |
88 // ============================================================================ |
85 // ============================================================================ |
89 // |
86 // |
90 int data_buffer::add_mark (string name) |
87 void data_buffer::copy_buffer (const data_buffer* buf) |
91 { |
88 { |
92 // Find a free slot for the mark |
89 check_space (buf->get_write_size()); |
93 int u = g_NextMark++; |
90 memcpy (m_writepos, buf->get_buffer(), buf->get_write_size()); |
94 |
91 m_writepos += buf->get_write_size(); |
95 if (marks[u]) |
92 } |
96 error ("DataBuffer: attempted to re-create mark %u!\n", u); |
93 |
97 |
94 // ============================================================================ |
98 if (u >= MAX_MARKS) |
95 // |
99 error ("mark quota exceeded, all labels, if-structs and loops add marks\n"); |
96 byte_mark* data_buffer::add_mark (string name) |
100 |
97 { |
101 ScriptMark* m = new ScriptMark; |
98 byte_mark* mark = new byte_mark; |
102 m->name = name; |
99 mark->name = name; |
103 m->pos = writesize; |
100 mark->pos = get_write_size(); |
104 marks[u] = m; |
101 push_to_marks (mark); |
105 return u; |
102 return mark; |
106 } |
103 } |
107 |
104 |
108 // ============================================================================ |
105 // ============================================================================ |
109 // |
106 // |
110 int data_buffer::add_reference (int marknum, bool placeholder) |
107 mark_reference* data_buffer::add_reference (byte_mark* mark, bool write_placeholder) |
111 { |
108 { |
112 int u; |
109 mark_reference* ref = new mark_reference; |
113 |
110 ref->target = mark; |
114 for (u = 0; u < MAX_MARKS; u++) |
111 ref->pos = get_write_size(); |
115 if (!refs[u]) |
112 push_to_refs (ref); |
116 break; |
|
117 |
|
118 // TODO: get rid of this |
|
119 if (u == MAX_MARKS) |
|
120 error ("mark reference quota exceeded, all goto-statements, if-structs and loops add refs\n"); |
|
121 |
|
122 ScriptMarkReference* r = new ScriptMarkReference; |
|
123 r->num = marknum; |
|
124 r->pos = writesize; |
|
125 refs[u] = r; |
|
126 |
113 |
127 // Write a dummy placeholder for the reference |
114 // Write a dummy placeholder for the reference |
128 if (placeholder) |
115 if (write_placeholder) |
129 write (0xBEEFCAFE); |
116 write_dword (0xBEEFCAFE); |
130 |
117 |
131 return u; |
118 return ref; |
132 } |
119 } |
133 |
120 |
134 // ============================================================================ |
121 // ============================================================================ |
135 // |
122 // |
136 void data_buffer::delete_mark (int marknum) |
123 void data_buffer::adjust_mark (byte_mark* mark) |
137 { |
124 { |
138 if (!marks[marknum]) |
125 mark->pos = get_write_size(); |
|
126 } |
|
127 |
|
128 // ============================================================================ |
|
129 // |
|
130 void data_buffer::offset_mark (byte_mark* mark, int offset) |
|
131 { |
|
132 mark->pos += offset; |
|
133 } |
|
134 |
|
135 // ============================================================================ |
|
136 // |
|
137 void data_buffer::write_float (float a) |
|
138 { |
|
139 // TODO: Find a way to store the number without decimal loss. |
|
140 write_dword (dh_push_number); |
|
141 write_dword (abs (a)); |
|
142 |
|
143 if (a < 0) |
|
144 write_dword (dh_unary_minus); |
|
145 } |
|
146 |
|
147 // ============================================================================ |
|
148 // |
|
149 void data_buffer::write_string_index (const string& a) |
|
150 { |
|
151 write_dword (dh_push_string_index); |
|
152 write_dword (get_string_table_index (a)); |
|
153 } |
|
154 |
|
155 // ============================================================================ |
|
156 // |
|
157 void data_buffer::dump() |
|
158 { |
|
159 for (int i = 0; i < get_write_size(); ++i) |
|
160 printf ("%d. [%d]\n", i, get_buffer()[i]); |
|
161 } |
|
162 |
|
163 // ============================================================================ |
|
164 // |
|
165 void data_buffer::check_space (int bytes) |
|
166 { |
|
167 int writesize = get_write_size(); |
|
168 |
|
169 if (writesize + bytes < get_allocated_size()) |
139 return; |
170 return; |
140 |
171 |
141 // Delete the mark |
172 // We don't have enough space in the buffer to write |
142 delete marks[marknum]; |
173 // the stuff - thus resize. First, store the old |
143 marks[marknum] = null; |
174 // buffer temporarily: |
144 |
175 char* copy = new char[get_allocated_size()]; |
145 // Delete its references |
176 memcpy (copy, get_buffer(), get_allocated_size()); |
146 for (int u = 0; u < MAX_MARKS; u++) |
177 |
147 { |
178 // Remake the buffer with the new size. Have enough space |
148 if (refs[u]->num == marknum) |
179 // for the stuff we're going to write, as well as a bit |
149 { |
180 // of leeway so we don't have to resize immediately again. |
150 delete refs[u]; |
181 size_t newsize = get_allocated_size() + bytes + 512; |
151 refs[u] = null; |
182 |
152 } |
183 delete get_buffer(); |
153 } |
184 set_buffer (new byte[newsize]); |
154 } |
185 set_allocated_size (newsize); |
155 |
186 |
156 // ============================================================================ |
187 // Now, copy the stuff back. |
157 // |
188 memcpy (m_buffer, copy, get_allocated_size()); |
158 void data_buffer::move_mark (int i) |
189 set_writepos (get_buffer() + writesize); |
159 { |
190 delete copy; |
160 if (!marks[i]) |
191 } |
161 return; |
192 |
162 |
193 // ============================================================================= |
163 marks[i]->pos = writesize; |
194 // |
164 } |
195 void data_buffer::write_byte (int8_t data) |
165 |
196 { |
166 // ============================================================================ |
197 check_space (1); |
167 // |
198 *m_writepos++ = data; |
168 void data_buffer::offset_mark (int mark, int offset) |
199 } |
169 { |
200 |
170 if (!marks[mark]) |
201 // ============================================================================= |
171 return; |
202 // |
172 |
203 void data_buffer::write_word (int16_t data) |
173 marks[mark]->pos += offset; |
204 { |
174 } |
205 check_space (2); |
175 |
206 |
176 // ============================================================================ |
207 for (int i = 0; i < 2; ++i) |
177 // |
208 *m_writepos++ = (data >> (i * 8)) & 0xFF; |
178 int data_buffer::count_marks() |
209 } |
179 { |
210 |
180 int count = 0; |
211 // ============================================================================= |
181 |
212 // |
182 for (int u = 0; u < MAX_MARKS; u++) |
213 void data_buffer::write_dword (int32_t data) |
183 count += !!marks[u]; |
214 { |
184 |
215 check_space (4); |
185 return count; |
216 |
186 } |
217 for (int i = 0; i < 4; ++i) |
187 |
218 *m_writepos++ = (data >> (i * 8)) & 0xFF; |
188 // ============================================================================ |
219 } |
189 // |
220 |
190 int data_buffer::count_references() |
221 // ============================================================================= |
191 { |
222 // |
192 int count = 0; |
223 void data_buffer::write_string (const string& a) |
193 |
224 { |
194 for (int u = 0; u < MAX_MARKS; u++) |
225 check_space (a.length() + 1); |
195 count += !!refs[u]; |
226 |
196 |
227 for (char c : a) |
197 return count; |
228 write_byte (c); |
198 } |
229 |
199 |
230 write_byte ('\0'); |
200 // ============================================================================ |
231 } |
201 // |
232 |
202 void data_buffer::write_float (string floatstring) |
233 |
203 { |
234 // ============================================================================= |
204 // TODO: Casting float to word causes the decimal to be lost. |
235 // |
205 // Find a way to store the number without such loss. |
236 byte_mark* data_buffer::find_mark_by_name (const string& target) |
206 float val = atof (floatstring); |
237 { |
207 write (dh_push_number); |
238 for (byte_mark* mark : get_marks()) |
208 write (static_cast<word> (abs (val))); |
239 if (mark->name == target) |
209 |
240 return mark; |
210 if (val < 0) |
241 |
211 write (dh_unary_minus); |
242 return null; |
212 } |
243 } |
213 |
|
214 // ============================================================================ |
|
215 // |
|
216 void data_buffer::write_string (string a) |
|
217 { |
|
218 write (dh_push_string_index); |
|
219 write (get_string_table_index (a)); |
|
220 } |
|
221 |
|
222 // ============================================================================ |
|
223 // |
|
224 void data_buffer::dump() |
|
225 { |
|
226 for (int x = 0; x < writesize; x++) |
|
227 printf ("%d. [%d]\n", x, * (buffer + x)); |
|
228 } |
|
229 |
|
230 // ============================================================================ |
|
231 // |
|
232 data_buffer::~data_buffer() |
|
233 { |
|
234 delete buffer; |
|
235 |
|
236 // Delete any marks and references |
|
237 for (int i = 0; i < MAX_MARKS; i++) |
|
238 { |
|
239 delete marks[i]; |
|
240 delete refs[i]; |
|
241 } |
|
242 } |
|
243 |
|
244 // ============================================================================ |
|
245 // |
|
246 data_buffer::data_buffer (int size) |
|
247 { |
|
248 writesize = 0; |
|
249 |
|
250 buffer = new unsigned char[size]; |
|
251 allocsize = size; |
|
252 |
|
253 // Clear the marks table out |
|
254 for (int u = 0; u < MAX_MARKS; u++) |
|
255 { |
|
256 marks[u] = null; |
|
257 refs[u] = null; |
|
258 } |
|
259 } |
|