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

# User Rev Content
1 root 1.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 elmex 1.2 STRLEN len;
73    
74 root 1.1 char *res = count > 0
75 elmex 1.2 ? strdup (SvPVx (POPs, len))
76 root 1.1 : 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