1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* Write Python objects to files and read them back.
26 This is intended for writing and reading compiled Python code only;
27 a true persistent storage facility would be much harder, since
28 it would have to take circular links and sharing into account. */
30 #include "allobjects.h"
31 #include "modsupport.h"
32 #include "longintrepr.h"
41 #define TYPE_FLOAT 'f'
42 #define TYPE_COMPLEX 'x'
44 #define TYPE_STRING 's'
45 #define TYPE_TUPLE '('
49 #define TYPE_UNKNOWN '?'
53 /* If fp == NULL, the following are valid: */
59 #define w_byte(c, p) if (((p)->fp)) putc((c), (p)->fp); \
60 else if ((p)->ptr != (p)->end) *(p)->ptr++ = (c); \
70 return; /* An error already occurred */
71 size
= getstringsize(p
->str
);
72 newsize
= size
+ 1024;
73 if (resizestring(&p
->str
, newsize
) != 0) {
74 p
->ptr
= p
->end
= NULL
;
77 p
->ptr
= GETSTRINGVALUE((stringobject
*)p
->str
) + size
;
78 p
->end
= GETSTRINGVALUE((stringobject
*)p
->str
) + newsize
;
90 fwrite(s
, 1, n
, p
->fp
);
105 w_byte( x
& 0xff, p
);
106 w_byte((x
>> 8) & 0xff, p
);
114 w_byte((int)( x
& 0xff), p
);
115 w_byte((int)((x
>> 8) & 0xff), p
);
116 w_byte((int)((x
>>16) & 0xff), p
);
117 w_byte((int)((x
>>24) & 0xff), p
);
128 w_byte(TYPE_NULL
, p
);
130 w_byte(TYPE_NONE
, p
);
131 else if (is_intobject(v
)) {
133 w_long(getintvalue(v
), p
);
135 else if (is_longobject(v
)) {
136 longobject
*ob
= (longobject
*)v
;
137 w_byte(TYPE_LONG
, p
);
142 for (i
= 0; i
< n
; i
++)
143 w_short(ob
->ob_digit
[i
], p
);
145 else if (is_floatobject(v
)) {
146 extern void float_buf_repr
PROTO((char *, floatobject
*));
147 char buf
[256]; /* Plenty to format any double */
148 float_buf_repr(buf
, (floatobject
*)v
);
150 w_byte(TYPE_FLOAT
, p
);
154 #ifndef WITHOUT_COMPLEX
155 else if (is_complexobject(v
)) {
156 extern void float_buf_repr
PROTO((char *, floatobject
*));
157 char buf
[256]; /* Plenty to format any double */
159 w_byte(TYPE_COMPLEX
, p
);
160 temp
= (floatobject
*)newfloatobject(PyComplex_RealAsDouble(v
));
161 float_buf_repr(buf
, temp
);
166 temp
= (floatobject
*)newfloatobject(PyComplex_ImagAsDouble(v
));
167 float_buf_repr(buf
, temp
);
174 else if (is_stringobject(v
)) {
175 w_byte(TYPE_STRING
, p
);
176 n
= getstringsize(v
);
178 w_string(getstringvalue(v
), n
, p
);
180 else if (is_tupleobject(v
)) {
181 w_byte(TYPE_TUPLE
, p
);
184 for (i
= 0; i
< n
; i
++) {
185 w_object(GETTUPLEITEM(v
, i
), p
);
188 else if (is_listobject(v
)) {
189 w_byte(TYPE_LIST
, p
);
192 for (i
= 0; i
< n
; i
++) {
193 w_object(getlistitem(v
, i
), p
);
196 else if (is_dictobject(v
)) {
199 w_byte(TYPE_DICT
, p
);
200 /* This one is NULL object terminated! */
202 while (mappinggetnext(v
, &pos
, &key
, &value
)) {
206 w_object((object
*)NULL
, p
);
208 else if (is_codeobject(v
)) {
209 codeobject
*co
= (codeobject
*)v
;
210 w_byte(TYPE_CODE
, p
);
211 w_short(co
->co_argcount
, p
);
212 w_short(co
->co_nlocals
, p
);
213 w_short(co
->co_flags
, p
);
214 w_object((object
*)co
->co_code
, p
);
215 w_object(co
->co_consts
, p
);
216 w_object(co
->co_names
, p
);
217 w_object(co
->co_varnames
, p
);
218 w_object(co
->co_filename
, p
);
219 w_object(co
->co_name
, p
);
222 w_byte(TYPE_UNKNOWN
, p
);
246 typedef WFILE RFILE
; /* Same struct with different invariants */
248 #define rs_byte(p) (((p)->ptr != (p)->end) ? (unsigned char)*(p)->ptr++ : EOF)
250 #define r_byte(p) ((p)->fp ? getc((p)->fp) : rs_byte(p))
259 return fread(s
, 1, n
, p
->fp
);
260 if (p
->end
- p
->ptr
< n
)
262 memcpy(s
, p
->ptr
, n
);
274 /* XXX If your short is > 16 bits, add sign-extension here!!! */
283 register FILE *fp
= p
->fp
;
286 x
|= (long)getc(fp
) << 8;
287 x
|= (long)getc(fp
) << 16;
288 x
|= (long)getc(fp
) << 24;
292 x
|= (long)rs_byte(p
) << 8;
293 x
|= (long)rs_byte(p
) << 16;
294 x
|= (long)rs_byte(p
) << 24;
296 /* XXX If your long is > 32 bits, add sign-extension here!!! */
306 int type
= r_byte(p
);
311 err_setstr(EOFError
, "EOF read where object expected");
322 return newintobject(r_long(p
));
330 ob
= alloclongobject(size
);
334 for (i
= 0; i
< size
; i
++)
335 ob
->ob_digit
[i
] = r_short(p
);
341 extern double atof
PROTO((const char *));
344 if (r_string(buf
, (int)n
, p
) != n
) {
346 "EOF read where object expected");
350 return newfloatobject(atof(buf
));
353 #ifndef WITHOUT_COMPLEX
356 extern double atof
PROTO((const char *));
360 if (r_string(buf
, (int)n
, p
) != n
) {
362 "EOF read where object expected");
368 if (r_string(buf
, (int)n
, p
) != n
) {
370 "EOF read where object expected");
375 return newcomplexobject(c
);
381 v
= newsizedstringobject((char *)NULL
, n
);
383 if (r_string(getstringvalue(v
), (int)n
, p
) != n
) {
387 "EOF read where object expected");
394 v
= newtupleobject((int)n
);
397 for (i
= 0; i
< n
; i
++) {
404 SETTUPLEITEM(v
, (int)i
, v2
);
410 v
= newlistobject((int)n
);
413 for (i
= 0; i
< n
; i
++) {
420 setlistitem(v
, (int)i
, v2
);
432 break; /* XXXX and how about memory errors? */
434 /* XXXX error check? */
435 dict2insert(v
, key
, val
);
443 int argcount
= r_short(p
);
444 int nlocals
= r_short(p
);
445 int flags
= r_short(p
);
447 object
*consts
= NULL
;
448 object
*names
= NULL
;
449 object
*varnames
= NULL
;
450 object
*filename
= NULL
;
454 if (code
) consts
= r_object(p
);
455 if (consts
) names
= r_object(p
);
456 if (names
) varnames
= r_object(p
);
457 if (varnames
) filename
= r_object(p
);
458 if (filename
) name
= r_object(p
);
460 if (!err_occurred()) {
461 v
= (object
*) newcodeobject(
462 argcount
, nlocals
, flags
,
463 code
, consts
, names
, varnames
,
479 err_setstr(TypeError
, "read unknown object");
499 if (err_occurred()) {
500 fatal("XXX rd_object called with exception set"); /* tmp */
501 fprintf(stderr
, "XXX rd_object called with exception set\n");
505 return r_object(&rf
);
514 if (err_occurred()) {
515 fprintf(stderr
, "XXX rds_object called with exception set\n");
522 return r_object(&rf
);
525 /* And an interface for Python programs... */
528 marshal_dump(self
, args
)
535 if (!getargs(args
, "(OO)", &x
, &f
))
537 if (!is_fileobject(f
)) {
538 err_setstr(TypeError
, "marshal.dump() 2nd arg must be file");
541 wf
.fp
= getfilefile(f
);
543 wf
.ptr
= wf
.end
= NULL
;
550 marshal_load(self
, args
)
557 if (!getargs(args
, "O", &f
))
559 if (!is_fileobject(f
)) {
560 err_setstr(TypeError
, "marshal.load() arg must be file");
563 rf
.fp
= getfilefile(f
);
565 rf
.ptr
= rf
.end
= NULL
;
568 if (err_occurred()) {
576 marshal_dumps(self
, args
)
582 if (!getargs(args
, "O", &x
))
585 wf
.str
= newsizedstringobject((char *)NULL
, 50);
588 wf
.ptr
= GETSTRINGVALUE((stringobject
*)wf
.str
);
589 wf
.end
= wf
.ptr
+ getstringsize(wf
.str
);
592 resizestring(&wf
.str
,
593 (int) (wf
.ptr
- GETSTRINGVALUE((stringobject
*)wf
.str
)));
598 marshal_loads(self
, args
)
606 if (!getargs(args
, "s#", &s
, &n
))
614 if (err_occurred()) {
621 static struct methodlist marshal_methods
[] = {
622 {"dump", marshal_dump
},
623 {"load", marshal_load
},
624 {"dumps", marshal_dumps
},
625 {"loads", marshal_loads
},
626 {NULL
, NULL
} /* sentinel */
632 (void) initmodule("marshal", marshal_methods
);