Line data Source code
1 : #define PY_SSIZE_T_CLEAN
2 : #include "Python.h"
3 : #include "structmember.h"
4 : #include "_iomodule.h"
5 :
6 : /* Implementation note: the buffer is always at least one character longer
7 : than the enclosed string, for proper functioning of _PyIO_find_line_ending.
8 : */
9 :
10 : typedef struct {
11 : PyObject_HEAD
12 : Py_UNICODE *buf;
13 : Py_ssize_t pos;
14 : Py_ssize_t string_size;
15 : size_t buf_size;
16 :
17 : char ok; /* initialized? */
18 : char closed;
19 : char readuniversal;
20 : char readtranslate;
21 : PyObject *decoder;
22 : PyObject *readnl;
23 : PyObject *writenl;
24 :
25 : PyObject *dict;
26 : PyObject *weakreflist;
27 : } stringio;
28 :
29 : #define CHECK_INITIALIZED(self) \
30 : if (self->ok <= 0) { \
31 : PyErr_SetString(PyExc_ValueError, \
32 : "I/O operation on uninitialized object"); \
33 : return NULL; \
34 : }
35 :
36 : #define CHECK_CLOSED(self) \
37 : if (self->closed) { \
38 : PyErr_SetString(PyExc_ValueError, \
39 : "I/O operation on closed file"); \
40 : return NULL; \
41 : }
42 :
43 : PyDoc_STRVAR(stringio_doc,
44 : "Text I/O implementation using an in-memory buffer.\n"
45 : "\n"
46 : "The initial_value argument sets the value of object. The newline\n"
47 : "argument is like the one of TextIOWrapper's constructor.");
48 :
49 :
50 : /* Internal routine for changing the size, in terms of characters, of the
51 : buffer of StringIO objects. The caller should ensure that the 'size'
52 : argument is non-negative. Returns 0 on success, -1 otherwise. */
53 : static int
54 0 : resize_buffer(stringio *self, size_t size)
55 : {
56 : /* Here, unsigned types are used to avoid dealing with signed integer
57 : overflow, which is undefined in C. */
58 0 : size_t alloc = self->buf_size;
59 0 : Py_UNICODE *new_buf = NULL;
60 :
61 : assert(self->buf != NULL);
62 :
63 : /* Reserve one more char for line ending detection. */
64 0 : size = size + 1;
65 : /* For simplicity, stay in the range of the signed type. Anyway, Python
66 : doesn't allow strings to be longer than this. */
67 0 : if (size > PY_SSIZE_T_MAX)
68 0 : goto overflow;
69 :
70 0 : if (size < alloc / 2) {
71 : /* Major downsize; resize down to exact size. */
72 0 : alloc = size + 1;
73 : }
74 0 : else if (size < alloc) {
75 : /* Within allocated size; quick exit */
76 0 : return 0;
77 : }
78 0 : else if (size <= alloc * 1.125) {
79 : /* Moderate upsize; overallocate similar to list_resize() */
80 0 : alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
81 : }
82 : else {
83 : /* Major upsize; resize up to exact size */
84 0 : alloc = size + 1;
85 : }
86 :
87 0 : if (alloc > ((size_t)-1) / sizeof(Py_UNICODE))
88 0 : goto overflow;
89 0 : new_buf = (Py_UNICODE *)PyMem_Realloc(self->buf,
90 : alloc * sizeof(Py_UNICODE));
91 0 : if (new_buf == NULL) {
92 0 : PyErr_NoMemory();
93 0 : return -1;
94 : }
95 0 : self->buf_size = alloc;
96 0 : self->buf = new_buf;
97 :
98 0 : return 0;
99 :
100 : overflow:
101 0 : PyErr_SetString(PyExc_OverflowError,
102 : "new buffer size too large");
103 0 : return -1;
104 : }
105 :
106 : /* Internal routine for writing a whole PyUnicode object to the buffer of a
107 : StringIO object. Returns 0 on success, or -1 on error. */
108 : static Py_ssize_t
109 0 : write_str(stringio *self, PyObject *obj)
110 : {
111 : Py_UNICODE *str;
112 : Py_ssize_t len;
113 0 : PyObject *decoded = NULL;
114 : assert(self->buf != NULL);
115 : assert(self->pos >= 0);
116 :
117 0 : if (self->decoder != NULL) {
118 0 : decoded = _PyIncrementalNewlineDecoder_decode(
119 : self->decoder, obj, 1 /* always final */);
120 : }
121 : else {
122 0 : decoded = obj;
123 0 : Py_INCREF(decoded);
124 : }
125 0 : if (self->writenl) {
126 0 : PyObject *translated = PyUnicode_Replace(
127 : decoded, _PyIO_str_nl, self->writenl, -1);
128 0 : Py_DECREF(decoded);
129 0 : decoded = translated;
130 : }
131 0 : if (decoded == NULL)
132 0 : return -1;
133 :
134 : assert(PyUnicode_Check(decoded));
135 0 : str = PyUnicode_AS_UNICODE(decoded);
136 0 : len = PyUnicode_GET_SIZE(decoded);
137 :
138 : assert(len >= 0);
139 :
140 : /* This overflow check is not strictly necessary. However, it avoids us to
141 : deal with funky things like comparing an unsigned and a signed
142 : integer. */
143 0 : if (self->pos > PY_SSIZE_T_MAX - len) {
144 0 : PyErr_SetString(PyExc_OverflowError,
145 : "new position too large");
146 0 : goto fail;
147 : }
148 0 : if (self->pos + len > self->string_size) {
149 0 : if (resize_buffer(self, self->pos + len) < 0)
150 0 : goto fail;
151 : }
152 :
153 0 : if (self->pos > self->string_size) {
154 : /* In case of overseek, pad with null bytes the buffer region between
155 : the end of stream and the current position.
156 :
157 : 0 lo string_size hi
158 : | |<---used--->|<----------available----------->|
159 : | | <--to pad-->|<---to write---> |
160 : 0 buf position
161 :
162 : */
163 0 : memset(self->buf + self->string_size, '\0',
164 0 : (self->pos - self->string_size) * sizeof(Py_UNICODE));
165 : }
166 :
167 : /* Copy the data to the internal buffer, overwriting some of the
168 : existing data if self->pos < self->string_size. */
169 0 : memcpy(self->buf + self->pos, str, len * sizeof(Py_UNICODE));
170 0 : self->pos += len;
171 :
172 : /* Set the new length of the internal string if it has changed. */
173 0 : if (self->string_size < self->pos) {
174 0 : self->string_size = self->pos;
175 : }
176 :
177 0 : Py_DECREF(decoded);
178 0 : return 0;
179 :
180 : fail:
181 0 : Py_XDECREF(decoded);
182 0 : return -1;
183 : }
184 :
185 : PyDoc_STRVAR(stringio_getvalue_doc,
186 : "Retrieve the entire contents of the object.");
187 :
188 : static PyObject *
189 0 : stringio_getvalue(stringio *self)
190 : {
191 0 : CHECK_INITIALIZED(self);
192 0 : CHECK_CLOSED(self);
193 0 : return PyUnicode_FromUnicode(self->buf, self->string_size);
194 : }
195 :
196 : PyDoc_STRVAR(stringio_tell_doc,
197 : "Tell the current file position.");
198 :
199 : static PyObject *
200 0 : stringio_tell(stringio *self)
201 : {
202 0 : CHECK_INITIALIZED(self);
203 0 : CHECK_CLOSED(self);
204 0 : return PyLong_FromSsize_t(self->pos);
205 : }
206 :
207 : PyDoc_STRVAR(stringio_read_doc,
208 : "Read at most n characters, returned as a string.\n"
209 : "\n"
210 : "If the argument is negative or omitted, read until EOF\n"
211 : "is reached. Return an empty string at EOF.\n");
212 :
213 : static PyObject *
214 0 : stringio_read(stringio *self, PyObject *args)
215 : {
216 : Py_ssize_t size, n;
217 : Py_UNICODE *output;
218 0 : PyObject *arg = Py_None;
219 :
220 0 : CHECK_INITIALIZED(self);
221 0 : if (!PyArg_ParseTuple(args, "|O:read", &arg))
222 0 : return NULL;
223 0 : CHECK_CLOSED(self);
224 :
225 0 : if (PyNumber_Check(arg)) {
226 0 : size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
227 0 : if (size == -1 && PyErr_Occurred())
228 0 : return NULL;
229 : }
230 0 : else if (arg == Py_None) {
231 : /* Read until EOF is reached, by default. */
232 0 : size = -1;
233 : }
234 : else {
235 0 : PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
236 0 : Py_TYPE(arg)->tp_name);
237 0 : return NULL;
238 : }
239 :
240 : /* adjust invalid sizes */
241 0 : n = self->string_size - self->pos;
242 0 : if (size < 0 || size > n) {
243 0 : size = n;
244 0 : if (size < 0)
245 0 : size = 0;
246 : }
247 :
248 0 : output = self->buf + self->pos;
249 0 : self->pos += size;
250 0 : return PyUnicode_FromUnicode(output, size);
251 : }
252 :
253 : /* Internal helper, used by stringio_readline and stringio_iternext */
254 : static PyObject *
255 0 : _stringio_readline(stringio *self, Py_ssize_t limit)
256 : {
257 : Py_UNICODE *start, *end, old_char;
258 : Py_ssize_t len, consumed;
259 :
260 : /* In case of overseek, return the empty string */
261 0 : if (self->pos >= self->string_size)
262 0 : return PyUnicode_FromString("");
263 :
264 0 : start = self->buf + self->pos;
265 0 : if (limit < 0 || limit > self->string_size - self->pos)
266 0 : limit = self->string_size - self->pos;
267 :
268 0 : end = start + limit;
269 0 : old_char = *end;
270 0 : *end = '\0';
271 0 : len = _PyIO_find_line_ending(
272 0 : self->readtranslate, self->readuniversal, self->readnl,
273 : start, end, &consumed);
274 0 : *end = old_char;
275 : /* If we haven't found any line ending, we just return everything
276 : (`consumed` is ignored). */
277 0 : if (len < 0)
278 0 : len = limit;
279 0 : self->pos += len;
280 0 : return PyUnicode_FromUnicode(start, len);
281 : }
282 :
283 : PyDoc_STRVAR(stringio_readline_doc,
284 : "Read until newline or EOF.\n"
285 : "\n"
286 : "Returns an empty string if EOF is hit immediately.\n");
287 :
288 : static PyObject *
289 0 : stringio_readline(stringio *self, PyObject *args)
290 : {
291 0 : PyObject *arg = Py_None;
292 0 : Py_ssize_t limit = -1;
293 :
294 0 : CHECK_INITIALIZED(self);
295 0 : if (!PyArg_ParseTuple(args, "|O:readline", &arg))
296 0 : return NULL;
297 0 : CHECK_CLOSED(self);
298 :
299 0 : if (PyNumber_Check(arg)) {
300 0 : limit = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
301 0 : if (limit == -1 && PyErr_Occurred())
302 0 : return NULL;
303 : }
304 0 : else if (arg != Py_None) {
305 0 : PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
306 0 : Py_TYPE(arg)->tp_name);
307 0 : return NULL;
308 : }
309 0 : return _stringio_readline(self, limit);
310 : }
311 :
312 : static PyObject *
313 0 : stringio_iternext(stringio *self)
314 : {
315 : PyObject *line;
316 :
317 0 : CHECK_INITIALIZED(self);
318 0 : CHECK_CLOSED(self);
319 :
320 0 : if (Py_TYPE(self) == &PyStringIO_Type) {
321 : /* Skip method call overhead for speed */
322 0 : line = _stringio_readline(self, -1);
323 : }
324 : else {
325 : /* XXX is subclassing StringIO really supported? */
326 0 : line = PyObject_CallMethodObjArgs((PyObject *)self,
327 : _PyIO_str_readline, NULL);
328 0 : if (line && !PyUnicode_Check(line)) {
329 0 : PyErr_Format(PyExc_IOError,
330 : "readline() should have returned an str object, "
331 0 : "not '%.200s'", Py_TYPE(line)->tp_name);
332 0 : Py_DECREF(line);
333 0 : return NULL;
334 : }
335 : }
336 :
337 0 : if (line == NULL)
338 0 : return NULL;
339 :
340 0 : if (PyUnicode_GET_SIZE(line) == 0) {
341 : /* Reached EOF */
342 0 : Py_DECREF(line);
343 0 : return NULL;
344 : }
345 :
346 0 : return line;
347 : }
348 :
349 : PyDoc_STRVAR(stringio_truncate_doc,
350 : "Truncate size to pos.\n"
351 : "\n"
352 : "The pos argument defaults to the current file position, as\n"
353 : "returned by tell(). The current file position is unchanged.\n"
354 : "Returns the new absolute position.\n");
355 :
356 : static PyObject *
357 0 : stringio_truncate(stringio *self, PyObject *args)
358 : {
359 : Py_ssize_t size;
360 0 : PyObject *arg = Py_None;
361 :
362 0 : CHECK_INITIALIZED(self);
363 0 : if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
364 0 : return NULL;
365 0 : CHECK_CLOSED(self);
366 :
367 0 : if (PyNumber_Check(arg)) {
368 0 : size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
369 0 : if (size == -1 && PyErr_Occurred())
370 0 : return NULL;
371 : }
372 0 : else if (arg == Py_None) {
373 : /* Truncate to current position if no argument is passed. */
374 0 : size = self->pos;
375 : }
376 : else {
377 0 : PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
378 0 : Py_TYPE(arg)->tp_name);
379 0 : return NULL;
380 : }
381 :
382 0 : if (size < 0) {
383 0 : PyErr_Format(PyExc_ValueError,
384 : "Negative size value %zd", size);
385 0 : return NULL;
386 : }
387 :
388 0 : if (size < self->string_size) {
389 0 : if (resize_buffer(self, size) < 0)
390 0 : return NULL;
391 0 : self->string_size = size;
392 : }
393 :
394 0 : return PyLong_FromSsize_t(size);
395 : }
396 :
397 : PyDoc_STRVAR(stringio_seek_doc,
398 : "Change stream position.\n"
399 : "\n"
400 : "Seek to character offset pos relative to position indicated by whence:\n"
401 : " 0 Start of stream (the default). pos should be >= 0;\n"
402 : " 1 Current position - pos must be 0;\n"
403 : " 2 End of stream - pos must be 0.\n"
404 : "Returns the new absolute position.\n");
405 :
406 : static PyObject *
407 0 : stringio_seek(stringio *self, PyObject *args)
408 : {
409 : PyObject *posobj;
410 : Py_ssize_t pos;
411 0 : int mode = 0;
412 :
413 0 : CHECK_INITIALIZED(self);
414 0 : if (!PyArg_ParseTuple(args, "O|i:seek", &posobj, &mode))
415 0 : return NULL;
416 :
417 0 : pos = PyNumber_AsSsize_t(posobj, PyExc_OverflowError);
418 0 : if (pos == -1 && PyErr_Occurred())
419 0 : return NULL;
420 :
421 0 : CHECK_CLOSED(self);
422 :
423 0 : if (mode != 0 && mode != 1 && mode != 2) {
424 0 : PyErr_Format(PyExc_ValueError,
425 : "Invalid whence (%i, should be 0, 1 or 2)", mode);
426 0 : return NULL;
427 : }
428 0 : else if (pos < 0 && mode == 0) {
429 0 : PyErr_Format(PyExc_ValueError,
430 : "Negative seek position %zd", pos);
431 0 : return NULL;
432 : }
433 0 : else if (mode != 0 && pos != 0) {
434 0 : PyErr_SetString(PyExc_IOError,
435 : "Can't do nonzero cur-relative seeks");
436 0 : return NULL;
437 : }
438 :
439 : /* mode 0: offset relative to beginning of the string.
440 : mode 1: no change to current position.
441 : mode 2: change position to end of file. */
442 0 : if (mode == 1) {
443 0 : pos = self->pos;
444 : }
445 0 : else if (mode == 2) {
446 0 : pos = self->string_size;
447 : }
448 :
449 0 : self->pos = pos;
450 :
451 0 : return PyLong_FromSsize_t(self->pos);
452 : }
453 :
454 : PyDoc_STRVAR(stringio_write_doc,
455 : "Write string to file.\n"
456 : "\n"
457 : "Returns the number of characters written, which is always equal to\n"
458 : "the length of the string.\n");
459 :
460 : static PyObject *
461 0 : stringio_write(stringio *self, PyObject *obj)
462 : {
463 : Py_ssize_t size;
464 :
465 0 : CHECK_INITIALIZED(self);
466 0 : if (!PyUnicode_Check(obj)) {
467 0 : PyErr_Format(PyExc_TypeError, "unicode argument expected, got '%s'",
468 0 : Py_TYPE(obj)->tp_name);
469 0 : return NULL;
470 : }
471 0 : CHECK_CLOSED(self);
472 0 : size = PyUnicode_GET_SIZE(obj);
473 :
474 0 : if (size > 0 && write_str(self, obj) < 0)
475 0 : return NULL;
476 :
477 0 : return PyLong_FromSsize_t(size);
478 : }
479 :
480 : PyDoc_STRVAR(stringio_close_doc,
481 : "Close the IO object. Attempting any further operation after the\n"
482 : "object is closed will raise a ValueError.\n"
483 : "\n"
484 : "This method has no effect if the file is already closed.\n");
485 :
486 : static PyObject *
487 0 : stringio_close(stringio *self)
488 : {
489 0 : self->closed = 1;
490 : /* Free up some memory */
491 0 : if (resize_buffer(self, 0) < 0)
492 0 : return NULL;
493 0 : Py_CLEAR(self->readnl);
494 0 : Py_CLEAR(self->writenl);
495 0 : Py_CLEAR(self->decoder);
496 0 : Py_RETURN_NONE;
497 : }
498 :
499 : static int
500 0 : stringio_traverse(stringio *self, visitproc visit, void *arg)
501 : {
502 0 : Py_VISIT(self->dict);
503 0 : return 0;
504 : }
505 :
506 : static int
507 0 : stringio_clear(stringio *self)
508 : {
509 0 : Py_CLEAR(self->dict);
510 0 : return 0;
511 : }
512 :
513 : static void
514 0 : stringio_dealloc(stringio *self)
515 : {
516 0 : _PyObject_GC_UNTRACK(self);
517 0 : self->ok = 0;
518 0 : if (self->buf) {
519 0 : PyMem_Free(self->buf);
520 0 : self->buf = NULL;
521 : }
522 0 : Py_CLEAR(self->readnl);
523 0 : Py_CLEAR(self->writenl);
524 0 : Py_CLEAR(self->decoder);
525 0 : Py_CLEAR(self->dict);
526 0 : if (self->weakreflist != NULL)
527 0 : PyObject_ClearWeakRefs((PyObject *) self);
528 0 : Py_TYPE(self)->tp_free(self);
529 0 : }
530 :
531 : static PyObject *
532 0 : stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
533 : {
534 : stringio *self;
535 :
536 : assert(type != NULL && type->tp_alloc != NULL);
537 0 : self = (stringio *)type->tp_alloc(type, 0);
538 0 : if (self == NULL)
539 0 : return NULL;
540 :
541 : /* tp_alloc initializes all the fields to zero. So we don't have to
542 : initialize them here. */
543 :
544 0 : self->buf = (Py_UNICODE *)PyMem_Malloc(0);
545 0 : if (self->buf == NULL) {
546 0 : Py_DECREF(self);
547 0 : return PyErr_NoMemory();
548 : }
549 :
550 0 : return (PyObject *)self;
551 : }
552 :
553 : static int
554 0 : stringio_init(stringio *self, PyObject *args, PyObject *kwds)
555 : {
556 0 : char *kwlist[] = {"initial_value", "newline", NULL};
557 0 : PyObject *value = NULL;
558 0 : char *newline = "\n";
559 :
560 0 : if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oz:__init__", kwlist,
561 : &value, &newline))
562 0 : return -1;
563 :
564 0 : if (newline && newline[0] != '\0'
565 0 : && !(newline[0] == '\n' && newline[1] == '\0')
566 0 : && !(newline[0] == '\r' && newline[1] == '\0')
567 0 : && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
568 0 : PyErr_Format(PyExc_ValueError,
569 : "illegal newline value: %s", newline);
570 0 : return -1;
571 : }
572 0 : if (value && value != Py_None && !PyUnicode_Check(value)) {
573 0 : PyErr_Format(PyExc_TypeError,
574 : "initial_value must be unicode or None, not %.200s",
575 0 : Py_TYPE(value)->tp_name);
576 0 : return -1;
577 : }
578 :
579 0 : self->ok = 0;
580 :
581 0 : Py_CLEAR(self->readnl);
582 0 : Py_CLEAR(self->writenl);
583 0 : Py_CLEAR(self->decoder);
584 :
585 0 : if (newline) {
586 0 : self->readnl = PyString_FromString(newline);
587 0 : if (self->readnl == NULL)
588 0 : return -1;
589 : }
590 0 : self->readuniversal = (newline == NULL || newline[0] == '\0');
591 0 : self->readtranslate = (newline == NULL);
592 : /* If newline == "", we don't translate anything.
593 : If newline == "\n" or newline == None, we translate to "\n", which is
594 : a no-op.
595 : (for newline == None, TextIOWrapper translates to os.sepline, but it
596 : is pointless for StringIO)
597 : */
598 0 : if (newline != NULL && newline[0] == '\r') {
599 0 : self->writenl = PyUnicode_FromString(newline);
600 : }
601 :
602 0 : if (self->readuniversal) {
603 0 : self->decoder = PyObject_CallFunction(
604 : (PyObject *)&PyIncrementalNewlineDecoder_Type,
605 0 : "Oi", Py_None, (int) self->readtranslate);
606 0 : if (self->decoder == NULL)
607 0 : return -1;
608 : }
609 :
610 : /* Now everything is set up, resize buffer to size of initial value,
611 : and copy it */
612 0 : self->string_size = 0;
613 0 : if (value && value != Py_None) {
614 0 : Py_ssize_t len = PyUnicode_GetSize(value);
615 : /* This is a heuristic, for newline translation might change
616 : the string length. */
617 0 : if (resize_buffer(self, len) < 0)
618 0 : return -1;
619 0 : self->pos = 0;
620 0 : if (write_str(self, value) < 0)
621 0 : return -1;
622 : }
623 : else {
624 0 : if (resize_buffer(self, 0) < 0)
625 0 : return -1;
626 : }
627 0 : self->pos = 0;
628 :
629 0 : self->closed = 0;
630 0 : self->ok = 1;
631 0 : return 0;
632 : }
633 :
634 : /* Properties and pseudo-properties */
635 :
636 : PyDoc_STRVAR(stringio_readable_doc,
637 : "readable() -> bool. Returns True if the IO object can be read.");
638 :
639 : PyDoc_STRVAR(stringio_writable_doc,
640 : "writable() -> bool. Returns True if the IO object can be written.");
641 :
642 : PyDoc_STRVAR(stringio_seekable_doc,
643 : "seekable() -> bool. Returns True if the IO object can be seeked.");
644 :
645 : static PyObject *
646 0 : stringio_seekable(stringio *self, PyObject *args)
647 : {
648 0 : CHECK_INITIALIZED(self);
649 0 : CHECK_CLOSED(self);
650 0 : Py_RETURN_TRUE;
651 : }
652 :
653 : static PyObject *
654 0 : stringio_readable(stringio *self, PyObject *args)
655 : {
656 0 : CHECK_INITIALIZED(self);
657 0 : CHECK_CLOSED(self);
658 0 : Py_RETURN_TRUE;
659 : }
660 :
661 : static PyObject *
662 0 : stringio_writable(stringio *self, PyObject *args)
663 : {
664 0 : CHECK_INITIALIZED(self);
665 0 : CHECK_CLOSED(self);
666 0 : Py_RETURN_TRUE;
667 : }
668 :
669 : /* Pickling support.
670 :
671 : The implementation of __getstate__ is similar to the one for BytesIO,
672 : except that we also save the newline parameter. For __setstate__ and unlike
673 : BytesIO, we call __init__ to restore the object's state. Doing so allows us
674 : to avoid decoding the complex newline state while keeping the object
675 : representation compact.
676 :
677 : See comment in bytesio.c regarding why only pickle protocols and onward are
678 : supported.
679 : */
680 :
681 : static PyObject *
682 0 : stringio_getstate(stringio *self)
683 : {
684 0 : PyObject *initvalue = stringio_getvalue(self);
685 : PyObject *dict;
686 : PyObject *state;
687 :
688 0 : if (initvalue == NULL)
689 0 : return NULL;
690 0 : if (self->dict == NULL) {
691 0 : Py_INCREF(Py_None);
692 0 : dict = Py_None;
693 : }
694 : else {
695 0 : dict = PyDict_Copy(self->dict);
696 0 : if (dict == NULL)
697 0 : return NULL;
698 : }
699 :
700 0 : state = Py_BuildValue("(OOnN)", initvalue,
701 0 : self->readnl ? self->readnl : Py_None,
702 : self->pos, dict);
703 0 : Py_DECREF(initvalue);
704 0 : return state;
705 : }
706 :
707 : static PyObject *
708 0 : stringio_setstate(stringio *self, PyObject *state)
709 : {
710 : PyObject *initarg;
711 : PyObject *position_obj;
712 : PyObject *dict;
713 : Py_ssize_t pos;
714 :
715 : assert(state != NULL);
716 0 : CHECK_CLOSED(self);
717 :
718 : /* We allow the state tuple to be longer than 4, because we may need
719 : someday to extend the object's state without breaking
720 : backward-compatibility. */
721 0 : if (!PyTuple_Check(state) || Py_SIZE(state) < 4) {
722 0 : PyErr_Format(PyExc_TypeError,
723 : "%.200s.__setstate__ argument should be 4-tuple, got %.200s",
724 0 : Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
725 0 : return NULL;
726 : }
727 :
728 : /* Initialize the object's state. */
729 0 : initarg = PyTuple_GetSlice(state, 0, 2);
730 0 : if (initarg == NULL)
731 0 : return NULL;
732 0 : if (stringio_init(self, initarg, NULL) < 0) {
733 0 : Py_DECREF(initarg);
734 0 : return NULL;
735 : }
736 0 : Py_DECREF(initarg);
737 :
738 : /* Restore the buffer state. Even if __init__ did initialize the buffer,
739 : we have to initialize it again since __init__ may translate the
740 : newlines in the initial_value string. We clearly do not want that
741 : because the string value in the state tuple has already been translated
742 : once by __init__. So we do not take any chance and replace object's
743 : buffer completely. */
744 : {
745 0 : Py_UNICODE *buf = PyUnicode_AS_UNICODE(PyTuple_GET_ITEM(state, 0));
746 0 : Py_ssize_t bufsize = PyUnicode_GET_SIZE(PyTuple_GET_ITEM(state, 0));
747 0 : if (resize_buffer(self, bufsize) < 0)
748 0 : return NULL;
749 0 : memcpy(self->buf, buf, bufsize * sizeof(Py_UNICODE));
750 0 : self->string_size = bufsize;
751 : }
752 :
753 : /* Set carefully the position value. Alternatively, we could use the seek
754 : method instead of modifying self->pos directly to better protect the
755 : object internal state against errneous (or malicious) inputs. */
756 0 : position_obj = PyTuple_GET_ITEM(state, 2);
757 0 : if (!PyIndex_Check(position_obj)) {
758 0 : PyErr_Format(PyExc_TypeError,
759 : "third item of state must be an integer, got %.200s",
760 0 : Py_TYPE(position_obj)->tp_name);
761 0 : return NULL;
762 : }
763 0 : pos = PyNumber_AsSsize_t(position_obj, PyExc_OverflowError);
764 0 : if (pos == -1 && PyErr_Occurred())
765 0 : return NULL;
766 0 : if (pos < 0) {
767 0 : PyErr_SetString(PyExc_ValueError,
768 : "position value cannot be negative");
769 0 : return NULL;
770 : }
771 0 : self->pos = pos;
772 :
773 : /* Set the dictionary of the instance variables. */
774 0 : dict = PyTuple_GET_ITEM(state, 3);
775 0 : if (dict != Py_None) {
776 0 : if (!PyDict_Check(dict)) {
777 0 : PyErr_Format(PyExc_TypeError,
778 : "fourth item of state should be a dict, got a %.200s",
779 0 : Py_TYPE(dict)->tp_name);
780 0 : return NULL;
781 : }
782 0 : if (self->dict) {
783 : /* Alternatively, we could replace the internal dictionary
784 : completely. However, it seems more practical to just update it. */
785 0 : if (PyDict_Update(self->dict, dict) < 0)
786 0 : return NULL;
787 : }
788 : else {
789 0 : Py_INCREF(dict);
790 0 : self->dict = dict;
791 : }
792 : }
793 :
794 0 : Py_RETURN_NONE;
795 : }
796 :
797 :
798 : static PyObject *
799 0 : stringio_closed(stringio *self, void *context)
800 : {
801 0 : CHECK_INITIALIZED(self);
802 0 : return PyBool_FromLong(self->closed);
803 : }
804 :
805 : static PyObject *
806 0 : stringio_line_buffering(stringio *self, void *context)
807 : {
808 0 : CHECK_INITIALIZED(self);
809 0 : CHECK_CLOSED(self);
810 0 : Py_RETURN_FALSE;
811 : }
812 :
813 : static PyObject *
814 0 : stringio_newlines(stringio *self, void *context)
815 : {
816 0 : CHECK_INITIALIZED(self);
817 0 : CHECK_CLOSED(self);
818 0 : if (self->decoder == NULL)
819 0 : Py_RETURN_NONE;
820 0 : return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
821 : }
822 :
823 : static struct PyMethodDef stringio_methods[] = {
824 : {"close", (PyCFunction)stringio_close, METH_NOARGS, stringio_close_doc},
825 : {"getvalue", (PyCFunction)stringio_getvalue, METH_NOARGS, stringio_getvalue_doc},
826 : {"read", (PyCFunction)stringio_read, METH_VARARGS, stringio_read_doc},
827 : {"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
828 : {"tell", (PyCFunction)stringio_tell, METH_NOARGS, stringio_tell_doc},
829 : {"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
830 : {"seek", (PyCFunction)stringio_seek, METH_VARARGS, stringio_seek_doc},
831 : {"write", (PyCFunction)stringio_write, METH_O, stringio_write_doc},
832 :
833 : {"seekable", (PyCFunction)stringio_seekable, METH_NOARGS, stringio_seekable_doc},
834 : {"readable", (PyCFunction)stringio_readable, METH_NOARGS, stringio_readable_doc},
835 : {"writable", (PyCFunction)stringio_writable, METH_NOARGS, stringio_writable_doc},
836 :
837 : {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS},
838 : {"__setstate__", (PyCFunction)stringio_setstate, METH_O},
839 : {NULL, NULL} /* sentinel */
840 : };
841 :
842 : static PyGetSetDef stringio_getset[] = {
843 : {"closed", (getter)stringio_closed, NULL, NULL},
844 : {"newlines", (getter)stringio_newlines, NULL, NULL},
845 : /* (following comments straight off of the original Python wrapper:)
846 : XXX Cruft to support the TextIOWrapper API. This would only
847 : be meaningful if StringIO supported the buffer attribute.
848 : Hopefully, a better solution, than adding these pseudo-attributes,
849 : will be found.
850 : */
851 : {"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
852 : {NULL}
853 : };
854 :
855 : PyTypeObject PyStringIO_Type = {
856 : PyVarObject_HEAD_INIT(NULL, 0)
857 : "_io.StringIO", /*tp_name*/
858 : sizeof(stringio), /*tp_basicsize*/
859 : 0, /*tp_itemsize*/
860 : (destructor)stringio_dealloc, /*tp_dealloc*/
861 : 0, /*tp_print*/
862 : 0, /*tp_getattr*/
863 : 0, /*tp_setattr*/
864 : 0, /*tp_reserved*/
865 : 0, /*tp_repr*/
866 : 0, /*tp_as_number*/
867 : 0, /*tp_as_sequence*/
868 : 0, /*tp_as_mapping*/
869 : 0, /*tp_hash*/
870 : 0, /*tp_call*/
871 : 0, /*tp_str*/
872 : 0, /*tp_getattro*/
873 : 0, /*tp_setattro*/
874 : 0, /*tp_as_buffer*/
875 : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
876 : | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
877 : stringio_doc, /*tp_doc*/
878 : (traverseproc)stringio_traverse, /*tp_traverse*/
879 : (inquiry)stringio_clear, /*tp_clear*/
880 : 0, /*tp_richcompare*/
881 : offsetof(stringio, weakreflist), /*tp_weaklistoffset*/
882 : 0, /*tp_iter*/
883 : (iternextfunc)stringio_iternext, /*tp_iternext*/
884 : stringio_methods, /*tp_methods*/
885 : 0, /*tp_members*/
886 : stringio_getset, /*tp_getset*/
887 : 0, /*tp_base*/
888 : 0, /*tp_dict*/
889 : 0, /*tp_descr_get*/
890 : 0, /*tp_descr_set*/
891 : offsetof(stringio, dict), /*tp_dictoffset*/
892 : (initproc)stringio_init, /*tp_init*/
893 : 0, /*tp_alloc*/
894 : stringio_new, /*tp_new*/
895 : };
|