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
resize_buffer(stringio * self,size_t size)54 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     size_t alloc = self->buf_size;
59     Py_UNICODE *new_buf = NULL;
60 
61     assert(self->buf != NULL);
62 
63     /* Reserve one more char for line ending detection. */
64     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     if (size > PY_SSIZE_T_MAX)
68         goto overflow;
69 
70     if (size < alloc / 2) {
71         /* Major downsize; resize down to exact size. */
72         alloc = size + 1;
73     }
74     else if (size < alloc) {
75         /* Within allocated size; quick exit */
76         return 0;
77     }
78     else if (size <= alloc * 1.125) {
79         /* Moderate upsize; overallocate similar to list_resize() */
80         alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
81     }
82     else {
83         /* Major upsize; resize up to exact size */
84         alloc = size + 1;
85     }
86 
87     if (alloc > ((size_t)-1) / sizeof(Py_UNICODE))
88         goto overflow;
89     new_buf = (Py_UNICODE *)PyMem_Realloc(self->buf,
90                                           alloc * sizeof(Py_UNICODE));
91     if (new_buf == NULL) {
92         PyErr_NoMemory();
93         return -1;
94     }
95     self->buf_size = alloc;
96     self->buf = new_buf;
97 
98     return 0;
99 
100   overflow:
101     PyErr_SetString(PyExc_OverflowError,
102                     "new buffer size too large");
103     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
write_str(stringio * self,PyObject * obj)109 write_str(stringio *self, PyObject *obj)
110 {
111     Py_UNICODE *str;
112     Py_ssize_t len;
113     PyObject *decoded = NULL;
114     assert(self->buf != NULL);
115     assert(self->pos >= 0);
116 
117     if (self->decoder != NULL) {
118         decoded = _PyIncrementalNewlineDecoder_decode(
119             self->decoder, obj, 1 /* always final */);
120     }
121     else {
122         decoded = obj;
123         Py_INCREF(decoded);
124     }
125     if (self->writenl) {
126         PyObject *translated = PyUnicode_Replace(
127             decoded, _PyIO_str_nl, self->writenl, -1);
128         Py_DECREF(decoded);
129         decoded = translated;
130     }
131     if (decoded == NULL)
132         return -1;
133 
134     assert(PyUnicode_Check(decoded));
135     str = PyUnicode_AS_UNICODE(decoded);
136     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     if (self->pos > PY_SSIZE_T_MAX - len) {
144         PyErr_SetString(PyExc_OverflowError,
145                         "new position too large");
146         goto fail;
147     }
148     if (self->pos + len > self->string_size) {
149         if (resize_buffer(self, self->pos + len) < 0)
150             goto fail;
151     }
152 
153     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         memset(self->buf + self->string_size, '\0',
164                (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     memcpy(self->buf + self->pos, str, len * sizeof(Py_UNICODE));
170     self->pos += len;
171 
172     /* Set the new length of the internal string if it has changed. */
173     if (self->string_size < self->pos) {
174         self->string_size = self->pos;
175     }
176 
177     Py_DECREF(decoded);
178     return 0;
179 
180 fail:
181     Py_XDECREF(decoded);
182     return -1;
183 }
184 
185 PyDoc_STRVAR(stringio_getvalue_doc,
186     "Retrieve the entire contents of the object.");
187 
188 static PyObject *
stringio_getvalue(stringio * self)189 stringio_getvalue(stringio *self)
190 {
191     CHECK_INITIALIZED(self);
192     CHECK_CLOSED(self);
193     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 *
stringio_tell(stringio * self)200 stringio_tell(stringio *self)
201 {
202     CHECK_INITIALIZED(self);
203     CHECK_CLOSED(self);
204     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 *
stringio_read(stringio * self,PyObject * args)214 stringio_read(stringio *self, PyObject *args)
215 {
216     Py_ssize_t size, n;
217     Py_UNICODE *output;
218     PyObject *arg = Py_None;
219 
220     CHECK_INITIALIZED(self);
221     if (!PyArg_ParseTuple(args, "|O:read", &arg))
222         return NULL;
223     CHECK_CLOSED(self);
224 
225     if (PyNumber_Check(arg)) {
226         size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
227         if (size == -1 && PyErr_Occurred())
228             return NULL;
229     }
230     else if (arg == Py_None) {
231         /* Read until EOF is reached, by default. */
232         size = -1;
233     }
234     else {
235         PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
236                      Py_TYPE(arg)->tp_name);
237         return NULL;
238     }
239 
240     /* adjust invalid sizes */
241     n = self->string_size - self->pos;
242     if (size < 0 || size > n) {
243         size = n;
244         if (size < 0)
245             size = 0;
246     }
247 
248     output = self->buf + self->pos;
249     self->pos += size;
250     return PyUnicode_FromUnicode(output, size);
251 }
252 
253 /* Internal helper, used by stringio_readline and stringio_iternext */
254 static PyObject *
_stringio_readline(stringio * self,Py_ssize_t limit)255 _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     if (self->pos >= self->string_size)
262         return PyUnicode_FromString("");
263 
264     start = self->buf + self->pos;
265     if (limit < 0 || limit > self->string_size - self->pos)
266         limit = self->string_size - self->pos;
267 
268     end = start + limit;
269     old_char = *end;
270     *end = '\0';
271     len = _PyIO_find_line_ending(
272         self->readtranslate, self->readuniversal, self->readnl,
273         start, end, &consumed);
274     *end = old_char;
275     /* If we haven't found any line ending, we just return everything
276        (`consumed` is ignored). */
277     if (len < 0)
278         len = limit;
279     self->pos += len;
280     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 *
stringio_readline(stringio * self,PyObject * args)289 stringio_readline(stringio *self, PyObject *args)
290 {
291     PyObject *arg = Py_None;
292     Py_ssize_t limit = -1;
293 
294     CHECK_INITIALIZED(self);
295     if (!PyArg_ParseTuple(args, "|O:readline", &arg))
296         return NULL;
297     CHECK_CLOSED(self);
298 
299     if (PyNumber_Check(arg)) {
300         limit = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
301         if (limit == -1 && PyErr_Occurred())
302             return NULL;
303     }
304     else if (arg != Py_None) {
305         PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
306                      Py_TYPE(arg)->tp_name);
307         return NULL;
308     }
309     return _stringio_readline(self, limit);
310 }
311 
312 static PyObject *
stringio_iternext(stringio * self)313 stringio_iternext(stringio *self)
314 {
315     PyObject *line;
316 
317     CHECK_INITIALIZED(self);
318     CHECK_CLOSED(self);
319 
320     if (Py_TYPE(self) == &PyStringIO_Type) {
321         /* Skip method call overhead for speed */
322         line = _stringio_readline(self, -1);
323     }
324     else {
325         /* XXX is subclassing StringIO really supported? */
326         line = PyObject_CallMethodObjArgs((PyObject *)self,
327                                            _PyIO_str_readline, NULL);
328         if (line && !PyUnicode_Check(line)) {
329             PyErr_Format(PyExc_IOError,
330                          "readline() should have returned an str object, "
331                          "not '%.200s'", Py_TYPE(line)->tp_name);
332             Py_DECREF(line);
333             return NULL;
334         }
335     }
336 
337     if (line == NULL)
338         return NULL;
339 
340     if (PyUnicode_GET_SIZE(line) == 0) {
341         /* Reached EOF */
342         Py_DECREF(line);
343         return NULL;
344     }
345 
346     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 *
stringio_truncate(stringio * self,PyObject * args)357 stringio_truncate(stringio *self, PyObject *args)
358 {
359     Py_ssize_t size;
360     PyObject *arg = Py_None;
361 
362     CHECK_INITIALIZED(self);
363     if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
364         return NULL;
365     CHECK_CLOSED(self);
366 
367     if (PyNumber_Check(arg)) {
368         size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
369         if (size == -1 && PyErr_Occurred())
370             return NULL;
371     }
372     else if (arg == Py_None) {
373         /* Truncate to current position if no argument is passed. */
374         size = self->pos;
375     }
376     else {
377         PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
378                      Py_TYPE(arg)->tp_name);
379         return NULL;
380     }
381 
382     if (size < 0) {
383         PyErr_Format(PyExc_ValueError,
384                      "Negative size value %zd", size);
385         return NULL;
386     }
387 
388     if (size < self->string_size) {
389         if (resize_buffer(self, size) < 0)
390             return NULL;
391         self->string_size = size;
392     }
393 
394     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 *
stringio_seek(stringio * self,PyObject * args)407 stringio_seek(stringio *self, PyObject *args)
408 {
409     PyObject *posobj;
410     Py_ssize_t pos;
411     int mode = 0;
412 
413     CHECK_INITIALIZED(self);
414     if (!PyArg_ParseTuple(args, "O|i:seek", &posobj, &mode))
415         return NULL;
416 
417     pos = PyNumber_AsSsize_t(posobj, PyExc_OverflowError);
418     if (pos == -1 && PyErr_Occurred())
419         return NULL;
420 
421     CHECK_CLOSED(self);
422 
423     if (mode != 0 && mode != 1 && mode != 2) {
424         PyErr_Format(PyExc_ValueError,
425                      "Invalid whence (%i, should be 0, 1 or 2)", mode);
426         return NULL;
427     }
428     else if (pos < 0 && mode == 0) {
429         PyErr_Format(PyExc_ValueError,
430                      "Negative seek position %zd", pos);
431         return NULL;
432     }
433     else if (mode != 0 && pos != 0) {
434         PyErr_SetString(PyExc_IOError,
435                         "Can't do nonzero cur-relative seeks");
436         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     if (mode == 1) {
443         pos = self->pos;
444     }
445     else if (mode == 2) {
446         pos = self->string_size;
447     }
448 
449     self->pos = pos;
450 
451     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 *
stringio_write(stringio * self,PyObject * obj)461 stringio_write(stringio *self, PyObject *obj)
462 {
463     Py_ssize_t size;
464 
465     CHECK_INITIALIZED(self);
466     if (!PyUnicode_Check(obj)) {
467         PyErr_Format(PyExc_TypeError, "unicode argument expected, got '%s'",
468                      Py_TYPE(obj)->tp_name);
469         return NULL;
470     }
471     CHECK_CLOSED(self);
472     size = PyUnicode_GET_SIZE(obj);
473 
474     if (size > 0 && write_str(self, obj) < 0)
475         return NULL;
476 
477     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 *
stringio_close(stringio * self)487 stringio_close(stringio *self)
488 {
489     self->closed = 1;
490     /* Free up some memory */
491     if (resize_buffer(self, 0) < 0)
492         return NULL;
493     Py_CLEAR(self->readnl);
494     Py_CLEAR(self->writenl);
495     Py_CLEAR(self->decoder);
496     Py_RETURN_NONE;
497 }
498 
499 static int
stringio_traverse(stringio * self,visitproc visit,void * arg)500 stringio_traverse(stringio *self, visitproc visit, void *arg)
501 {
502     Py_VISIT(self->dict);
503     return 0;
504 }
505 
506 static int
stringio_clear(stringio * self)507 stringio_clear(stringio *self)
508 {
509     Py_CLEAR(self->dict);
510     return 0;
511 }
512 
513 static void
stringio_dealloc(stringio * self)514 stringio_dealloc(stringio *self)
515 {
516     _PyObject_GC_UNTRACK(self);
517     self->ok = 0;
518     if (self->buf) {
519         PyMem_Free(self->buf);
520         self->buf = NULL;
521     }
522     Py_CLEAR(self->readnl);
523     Py_CLEAR(self->writenl);
524     Py_CLEAR(self->decoder);
525     Py_CLEAR(self->dict);
526     if (self->weakreflist != NULL)
527         PyObject_ClearWeakRefs((PyObject *) self);
528     Py_TYPE(self)->tp_free(self);
529 }
530 
531 static PyObject *
stringio_new(PyTypeObject * type,PyObject * args,PyObject * kwds)532 stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
533 {
534     stringio *self;
535 
536     assert(type != NULL && type->tp_alloc != NULL);
537     self = (stringio *)type->tp_alloc(type, 0);
538     if (self == NULL)
539         return NULL;
540 
541     /* tp_alloc initializes all the fields to zero. So we don't have to
542        initialize them here. */
543 
544     self->buf = (Py_UNICODE *)PyMem_Malloc(0);
545     if (self->buf == NULL) {
546         Py_DECREF(self);
547         return PyErr_NoMemory();
548     }
549 
550     return (PyObject *)self;
551 }
552 
553 static int
stringio_init(stringio * self,PyObject * args,PyObject * kwds)554 stringio_init(stringio *self, PyObject *args, PyObject *kwds)
555 {
556     char *kwlist[] = {"initial_value", "newline", NULL};
557     PyObject *value = NULL;
558     char *newline = "\n";
559 
560     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oz:__init__", kwlist,
561                                      &value, &newline))
562         return -1;
563 
564     if (newline && newline[0] != '\0'
565         && !(newline[0] == '\n' && newline[1] == '\0')
566         && !(newline[0] == '\r' && newline[1] == '\0')
567         && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
568         PyErr_Format(PyExc_ValueError,
569                      "illegal newline value: %s", newline);
570         return -1;
571     }
572     if (value && value != Py_None && !PyUnicode_Check(value)) {
573         PyErr_Format(PyExc_TypeError,
574                      "initial_value must be unicode or None, not %.200s",
575                      Py_TYPE(value)->tp_name);
576         return -1;
577     }
578 
579     self->ok = 0;
580 
581     Py_CLEAR(self->readnl);
582     Py_CLEAR(self->writenl);
583     Py_CLEAR(self->decoder);
584 
585     if (newline) {
586         self->readnl = PyString_FromString(newline);
587         if (self->readnl == NULL)
588             return -1;
589     }
590     self->readuniversal = (newline == NULL || newline[0] == '\0');
591     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     if (newline != NULL && newline[0] == '\r') {
599         self->writenl = PyUnicode_FromString(newline);
600     }
601 
602     if (self->readuniversal) {
603         self->decoder = PyObject_CallFunction(
604             (PyObject *)&PyIncrementalNewlineDecoder_Type,
605             "Oi", Py_None, (int) self->readtranslate);
606         if (self->decoder == NULL)
607             return -1;
608     }
609 
610     /* Now everything is set up, resize buffer to size of initial value,
611        and copy it */
612     self->string_size = 0;
613     if (value && value != Py_None) {
614         Py_ssize_t len = PyUnicode_GetSize(value);
615         /* This is a heuristic, for newline translation might change
616            the string length. */
617         if (resize_buffer(self, len) < 0)
618             return -1;
619         self->pos = 0;
620         if (write_str(self, value) < 0)
621             return -1;
622     }
623     else {
624         if (resize_buffer(self, 0) < 0)
625             return -1;
626     }
627     self->pos = 0;
628 
629     self->closed = 0;
630     self->ok = 1;
631     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 *
stringio_seekable(stringio * self,PyObject * args)646 stringio_seekable(stringio *self, PyObject *args)
647 {
648     CHECK_INITIALIZED(self);
649     CHECK_CLOSED(self);
650     Py_RETURN_TRUE;
651 }
652 
653 static PyObject *
stringio_readable(stringio * self,PyObject * args)654 stringio_readable(stringio *self, PyObject *args)
655 {
656     CHECK_INITIALIZED(self);
657     CHECK_CLOSED(self);
658     Py_RETURN_TRUE;
659 }
660 
661 static PyObject *
stringio_writable(stringio * self,PyObject * args)662 stringio_writable(stringio *self, PyObject *args)
663 {
664     CHECK_INITIALIZED(self);
665     CHECK_CLOSED(self);
666     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 *
stringio_getstate(stringio * self)682 stringio_getstate(stringio *self)
683 {
684     PyObject *initvalue = stringio_getvalue(self);
685     PyObject *dict;
686     PyObject *state;
687 
688     if (initvalue == NULL)
689         return NULL;
690     if (self->dict == NULL) {
691         Py_INCREF(Py_None);
692         dict = Py_None;
693     }
694     else {
695         dict = PyDict_Copy(self->dict);
696         if (dict == NULL) {
697             Py_DECREF(initvalue);
698             return NULL;
699         }
700     }
701 
702     state = Py_BuildValue("(OOnN)", initvalue,
703                           self->readnl ? self->readnl : Py_None,
704                           self->pos, dict);
705     Py_DECREF(initvalue);
706     return state;
707 }
708 
709 static PyObject *
stringio_setstate(stringio * self,PyObject * state)710 stringio_setstate(stringio *self, PyObject *state)
711 {
712     PyObject *initarg;
713     PyObject *position_obj;
714     PyObject *dict;
715     Py_ssize_t pos;
716 
717     assert(state != NULL);
718     CHECK_CLOSED(self);
719 
720     /* We allow the state tuple to be longer than 4, because we may need
721        someday to extend the object's state without breaking
722        backward-compatibility. */
723     if (!PyTuple_Check(state) || Py_SIZE(state) < 4) {
724         PyErr_Format(PyExc_TypeError,
725                      "%.200s.__setstate__ argument should be 4-tuple, got %.200s",
726                      Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
727         return NULL;
728     }
729 
730     /* Initialize the object's state. */
731     initarg = PyTuple_GetSlice(state, 0, 2);
732     if (initarg == NULL)
733         return NULL;
734     if (stringio_init(self, initarg, NULL) < 0) {
735         Py_DECREF(initarg);
736         return NULL;
737     }
738     Py_DECREF(initarg);
739 
740     /* Restore the buffer state. Even if __init__ did initialize the buffer,
741        we have to initialize it again since __init__ may translate the
742        newlines in the initial_value string. We clearly do not want that
743        because the string value in the state tuple has already been translated
744        once by __init__. So we do not take any chance and replace object's
745        buffer completely. */
746     {
747         Py_UNICODE *buf = PyUnicode_AS_UNICODE(PyTuple_GET_ITEM(state, 0));
748         Py_ssize_t bufsize = PyUnicode_GET_SIZE(PyTuple_GET_ITEM(state, 0));
749         if (resize_buffer(self, bufsize) < 0)
750             return NULL;
751         memcpy(self->buf, buf, bufsize * sizeof(Py_UNICODE));
752         self->string_size = bufsize;
753     }
754 
755     /* Set carefully the position value. Alternatively, we could use the seek
756        method instead of modifying self->pos directly to better protect the
757        object internal state against errneous (or malicious) inputs. */
758     position_obj = PyTuple_GET_ITEM(state, 2);
759     if (!PyIndex_Check(position_obj)) {
760         PyErr_Format(PyExc_TypeError,
761                      "third item of state must be an integer, got %.200s",
762                      Py_TYPE(position_obj)->tp_name);
763         return NULL;
764     }
765     pos = PyNumber_AsSsize_t(position_obj, PyExc_OverflowError);
766     if (pos == -1 && PyErr_Occurred())
767         return NULL;
768     if (pos < 0) {
769         PyErr_SetString(PyExc_ValueError,
770                         "position value cannot be negative");
771         return NULL;
772     }
773     self->pos = pos;
774 
775     /* Set the dictionary of the instance variables. */
776     dict = PyTuple_GET_ITEM(state, 3);
777     if (dict != Py_None) {
778         if (!PyDict_Check(dict)) {
779             PyErr_Format(PyExc_TypeError,
780                          "fourth item of state should be a dict, got a %.200s",
781                          Py_TYPE(dict)->tp_name);
782             return NULL;
783         }
784         if (self->dict) {
785             /* Alternatively, we could replace the internal dictionary
786                completely. However, it seems more practical to just update it. */
787             if (PyDict_Update(self->dict, dict) < 0)
788                 return NULL;
789         }
790         else {
791             Py_INCREF(dict);
792             self->dict = dict;
793         }
794     }
795 
796     Py_RETURN_NONE;
797 }
798 
799 
800 static PyObject *
stringio_closed(stringio * self,void * context)801 stringio_closed(stringio *self, void *context)
802 {
803     CHECK_INITIALIZED(self);
804     return PyBool_FromLong(self->closed);
805 }
806 
807 static PyObject *
stringio_line_buffering(stringio * self,void * context)808 stringio_line_buffering(stringio *self, void *context)
809 {
810     CHECK_INITIALIZED(self);
811     CHECK_CLOSED(self);
812     Py_RETURN_FALSE;
813 }
814 
815 static PyObject *
stringio_newlines(stringio * self,void * context)816 stringio_newlines(stringio *self, void *context)
817 {
818     CHECK_INITIALIZED(self);
819     CHECK_CLOSED(self);
820     if (self->decoder == NULL)
821         Py_RETURN_NONE;
822     return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
823 }
824 
825 static struct PyMethodDef stringio_methods[] = {
826     {"close",    (PyCFunction)stringio_close,    METH_NOARGS,  stringio_close_doc},
827     {"getvalue", (PyCFunction)stringio_getvalue, METH_NOARGS,  stringio_getvalue_doc},
828     {"read",     (PyCFunction)stringio_read,     METH_VARARGS, stringio_read_doc},
829     {"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
830     {"tell",     (PyCFunction)stringio_tell,     METH_NOARGS,  stringio_tell_doc},
831     {"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
832     {"seek",     (PyCFunction)stringio_seek,     METH_VARARGS, stringio_seek_doc},
833     {"write",    (PyCFunction)stringio_write,    METH_O,       stringio_write_doc},
834 
835     {"seekable", (PyCFunction)stringio_seekable, METH_NOARGS, stringio_seekable_doc},
836     {"readable", (PyCFunction)stringio_readable, METH_NOARGS, stringio_readable_doc},
837     {"writable", (PyCFunction)stringio_writable, METH_NOARGS, stringio_writable_doc},
838 
839     {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS},
840     {"__setstate__", (PyCFunction)stringio_setstate, METH_O},
841     {NULL, NULL}        /* sentinel */
842 };
843 
844 static PyGetSetDef stringio_getset[] = {
845     {"closed",         (getter)stringio_closed,         NULL, NULL},
846     {"newlines",       (getter)stringio_newlines,       NULL, NULL},
847     /*  (following comments straight off of the original Python wrapper:)
848         XXX Cruft to support the TextIOWrapper API. This would only
849         be meaningful if StringIO supported the buffer attribute.
850         Hopefully, a better solution, than adding these pseudo-attributes,
851         will be found.
852     */
853     {"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
854     {NULL}
855 };
856 
857 PyTypeObject PyStringIO_Type = {
858     PyVarObject_HEAD_INIT(NULL, 0)
859     "_io.StringIO",                            /*tp_name*/
860     sizeof(stringio),                    /*tp_basicsize*/
861     0,                                         /*tp_itemsize*/
862     (destructor)stringio_dealloc,              /*tp_dealloc*/
863     0,                                         /*tp_print*/
864     0,                                         /*tp_getattr*/
865     0,                                         /*tp_setattr*/
866     0,                                         /*tp_reserved*/
867     0,                                         /*tp_repr*/
868     0,                                         /*tp_as_number*/
869     0,                                         /*tp_as_sequence*/
870     0,                                         /*tp_as_mapping*/
871     0,                                         /*tp_hash*/
872     0,                                         /*tp_call*/
873     0,                                         /*tp_str*/
874     0,                                         /*tp_getattro*/
875     0,                                         /*tp_setattro*/
876     0,                                         /*tp_as_buffer*/
877     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
878                        | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/
879     stringio_doc,                              /*tp_doc*/
880     (traverseproc)stringio_traverse,           /*tp_traverse*/
881     (inquiry)stringio_clear,                   /*tp_clear*/
882     0,                                         /*tp_richcompare*/
883     offsetof(stringio, weakreflist),            /*tp_weaklistoffset*/
884     0,                                         /*tp_iter*/
885     (iternextfunc)stringio_iternext,           /*tp_iternext*/
886     stringio_methods,                          /*tp_methods*/
887     0,                                         /*tp_members*/
888     stringio_getset,                           /*tp_getset*/
889     0,                                         /*tp_base*/
890     0,                                         /*tp_dict*/
891     0,                                         /*tp_descr_get*/
892     0,                                         /*tp_descr_set*/
893     offsetof(stringio, dict),                  /*tp_dictoffset*/
894     (initproc)stringio_init,                   /*tp_init*/
895     0,                                         /*tp_alloc*/
896     stringio_new,                              /*tp_new*/
897 };
898