src/data_buffer.cc

changeset 86
43fe4be38a58
parent 85
264a61e9eba0
equal deleted inserted replaced
85:264a61e9eba0 86:43fe4be38a58
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 }

mercurial