ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.2
Committed: Sat Dec 30 14:34:10 2006 UTC (17 years, 5 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.1: +3 -1 lines
Log Message:
fixed a crash in object_freezer::as_string (), where too many items were popped
from the perl stack.

File Contents

# Content
1 /*****************************************************************************/
2 /* CrossFire, A roguelike realtime multiplayer game */
3 /*****************************************************************************/
4
5 /*
6 * This code is placed under the GNU General Public Licence (GPL)
7 *
8 * Copyright (C) 2006 by Marc Lehmann <crossfire@schmorp.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include "logger.h"
26 #include "cfperl.h"
27 #include "kw_hash.h"
28
29 object_freezer::object_freezer ()
30 : dynbuf (128 * 1024, 64 * 1024)
31 {
32 av = newAV ();
33 }
34
35 object_freezer::~object_freezer ()
36 {
37 SvREFCNT_dec (av);
38 }
39
40 void object_freezer::put (attachable *ext)
41 {
42 ext->optimise ();
43
44 if (ext->self)
45 {
46 int idx = AvFILLp ((AV *)av) + 1;
47 av_store (av, idx, newRV_inc ((SV *)ext->self));
48
49 add ((void *)"oid ", 4);
50 add ((sint32)idx);
51 add ('\n');
52 }
53 }
54
55 bool object_freezer::save (const char *filename)
56 {
57 CALL_BEGIN (3);
58 CALL_ARG_SV (newSVpv (filename, 0));
59 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
60 CALL_ARG_SV (newRV_inc ((SV *)av));
61 CALL_CALL ("cf::object_freezer_save", G_VOID | G_DISCARD);
62 CALL_END;
63 }
64
65 char *object_freezer::as_string ()
66 {
67 CALL_BEGIN (2);
68 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
69 CALL_ARG_SV (newRV_inc ((SV *)av));
70 CALL_CALL ("cf::object_freezer_as_string", G_SCALAR);
71
72 STRLEN len;
73
74 char *res = count > 0
75 ? strdup (SvPVx (POPs, len))
76 : strdup ("[fatal error]");
77
78 CALL_END;
79
80 return res;
81 }
82
83 int fprintf (object_freezer &freezer, const char *format, ...)
84 {
85 va_list ap;
86
87 va_start (ap, format);
88
89 int len = vsnprintf ((char *)freezer.force (1024), 1024, format, ap);
90
91 if (len >= 0)
92 freezer.alloc (len);
93
94 va_end (ap);
95 }
96
97 int fputs (const char *s, object_freezer &freezer)
98 {
99 freezer.add (s);
100 }
101
102 static const char thawer_eof[] = "\n\n\n\0\0\0";
103
104 object_thawer::object_thawer (const char *filename)
105 {
106 static const char eof[] = "\n\n\n\0\0\0";
107
108 av = 0;
109 text = 0;
110 line = 0;
111
112 if (filename)
113 {
114 CALL_BEGIN (1);
115 CALL_ARG_SV (newSVpv (filename, 0));
116 CALL_CALL ("cf::object_thawer_load", G_ARRAY);
117
118 if (count == 2)
119 {
120 // second value - perl objects
121 {
122 SV *sv = POPs;
123 if (SvROK (sv))
124 av = (AV *)SvREFCNT_inc (SvRV (sv));
125 }
126
127 // first value - text part, pad with 3 zeroes
128 {
129 SV *sv = POPs;
130 STRLEN len;
131 char *sv_ = SvPVbyte (sv, len);
132 text = newSV (len + sizeof (eof));
133 SvCUR_set (text, len);
134 memcpy (SvPVX (text), sv_, len);
135 memcpy (SvEND (text), eof, sizeof (eof)); // just to be sure
136
137 line = SvPVX (text);
138 }
139 }
140
141 CALL_END;
142 }
143 }
144
145 object_thawer::object_thawer (const char *data, AV *perlav)
146 {
147 av = perlav;
148 text = newSVpv (data, 0);
149 sv_catpv (text, thawer_eof);
150 line = SvPVbyte_nolen (text);
151 }
152
153 void object_thawer::get (attachable *obj, int oid)
154 {
155 if (!av || oid < 0) // this is actually an error of sorts
156 return;
157
158 SV **svp = av_fetch ((AV *)av, oid, 0);
159
160 if (!svp || !SvROK (*svp))
161 {
162 printf ("trying to thaw duplicate or never-issued oid %d, ignoring.\n", oid);
163 return;
164 }
165
166 if (!SvROK (*svp))
167 {
168 LOG (llevError, "deserialised perl object is not an RV");
169 return;
170 }
171
172 HV *hv = (HV *)SvRV (*svp);
173
174 if (SvTYPE (hv) != SVt_PVHV)
175 {
176 LOG (llevError, "deserialised perl object is not a PVHV");
177 return;
178 }
179
180 if (obj->self)
181 {
182 // the hard way(?)
183
184 // the dirty blues: "just" swap the XPVHV's
185 swap (SvANY (obj->self), SvANY (hv));
186
187 // do not swap magic, though
188 swap (SvMAGIC (obj->self), SvMAGIC (hv));
189 }
190 else
191 {
192 // the easy way(?)
193
194 obj->self = hv;
195 SvRV_set (*svp, &PL_sv_undef);
196
197 sv_magicext ((SV *)obj->self, 0, PERL_MAGIC_ext, &attachable::vtbl, (char *)obj, 0);
198
199 // borrow a refcount for the perl object
200 obj->flags |= attachable::F_BORROWED;
201 obj->refcnt_dec ();
202 }
203
204 obj->reattach ();
205 }
206
207 object_thawer::~object_thawer ()
208 {
209 if (text) SvREFCNT_dec (text);
210 if (av) SvREFCNT_dec (av);
211 }
212
213 char *fgets (char *s, int n, object_thawer &thawer)
214 {
215 char *p = thawer.line;
216 char *q = s;
217
218 if (!p)
219 return 0;
220
221 while (--n)
222 {
223 if (!*p)
224 break;
225
226 *q++ = *p;
227
228 if (*p++ == '\n')
229 break;
230 }
231
232 *q = 0;
233 thawer.line = p;
234
235 return s == q ? 0 : s;
236 }
237
238 keyword object_thawer::get_kv ()
239 {
240 if (!line)
241 return KW_EOF;
242
243 for (;;)
244 {
245 char *p = line;
246
247 if (!*p)
248 return KW_EOF;
249
250 // parse keyword
251 while (*p > ' ')
252 p++;
253
254 int klen = p - line;
255
256 if (*p++ != '\n')
257 {
258 // parse value
259 while (*(unsigned char *)p <= ' ' && *p != '\n') // skip 0x01 .. 0x20
260 ++p;
261
262 last_value = p;
263
264 while (*p != '\n')
265 p++;
266
267 *p++ = 0;
268 }
269 else
270 last_value = 0;
271
272 line [klen] = 0;
273 keyword_idx *kw = kw_lex::match (line, klen);
274
275 //printf ("KV %d<%s,%s>\n", kw ? kw->index : 0, line, last_value);//D
276
277 last_keyword = line;
278 line = p;
279
280 if (kw)
281 return kw->index;
282 else if (!*last_keyword || *last_keyword == '#')
283 ; // empty/comment line
284 else
285 return KW_ERROR;
286 }
287 }
288
289 void object_thawer::skip_kv (keyword kw)
290 {
291 shstr ml;
292
293 switch (kw)
294 {
295 case KW_msg: get_ml (KW_endmsg , ml); break;
296 case KW_lore: get_ml (KW_endlore , ml); break;
297 case KW_maplore: get_ml (KW_endmaplore, ml); break;
298 }
299 }
300
301 void object_thawer::get (shstr &sh) const
302 {
303 if (last_value)
304 sh = last_value;
305 else
306 {
307 sh = "<value missing>";
308 LOG (llevError, "keyword requires value: <%.320s>\n", line);//TODO: add filename
309 }
310 }
311
312 void object_thawer::get_ml (keyword kend, shstr &sh)
313 {
314 char kw[128];
315
316 int klen = keyword_len [kend];
317
318 kw [0] = '\n';
319 memcpy (kw + 1, keyword_str [kend], klen);
320 kw [klen + 1] = '\n';
321 kw [klen + 2] = 0;
322
323 // first test for completely empty msg... "endXXX\n"
324 if (!strncmp (line, kw + 1, klen + 1))
325 {
326 sh = 0;
327
328 line += klen + 1;
329
330 return;
331 }
332 else
333 {
334 // multi-line strings are delimited by "\nendXXX\n" or "endXXX\n" (NULL)
335
336 char *end = strstr (line, kw);
337
338 if (!end)
339 {
340 sh = 0;
341 return;
342 }
343
344 *end = 0;
345 sh = line;
346
347 line = end + keyword_len [kend] + 1;
348
349 while (*line++ != '\n')
350 ;
351 }
352 }
353
354 sint32 object_thawer::get_sint32 () const
355 {
356 char *p = last_value;
357
358 if (!p)
359 return 0;
360
361 sint32 val = 0;
362 bool negate;
363
364 if (*p == '-')
365 {
366 negate = true;
367 ++p;
368 }
369 else
370 negate = false;
371
372 do
373 {
374 val *= 10;
375 val += *p++ - '0';
376 }
377 while (*p);
378
379 return negate ? -val : val;
380 }
381
382 sint64 object_thawer::get_sint64 () const
383 {
384 return last_value ? atoll (last_value) : 0;
385 }
386
387 double object_thawer::get_double () const
388 {
389 return last_value ? atof (last_value) : 0;
390 }
391