LCOV - code coverage report
Current view: top level - Modules/_io - bytesio.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 0 339 0.0 %
Date: 2017-04-19 Functions: 0 28 0.0 %

          Line data    Source code
       1             : #include "Python.h"
       2             : #include "structmember.h"       /* for offsetof() */
       3             : #include "_iomodule.h"
       4             : 
       5             : typedef struct {
       6             :     PyObject_HEAD
       7             :     char *buf;
       8             :     Py_ssize_t pos;
       9             :     Py_ssize_t string_size;
      10             :     size_t buf_size;
      11             :     PyObject *dict;
      12             :     PyObject *weakreflist;
      13             : } bytesio;
      14             : 
      15             : #define CHECK_CLOSED(self)                                  \
      16             :     if ((self)->buf == NULL) {                              \
      17             :         PyErr_SetString(PyExc_ValueError,                   \
      18             :                         "I/O operation on closed file.");   \
      19             :         return NULL;                                        \
      20             :     }
      21             : 
      22             : /* Internal routine to get a line from the buffer of a BytesIO
      23             :    object. Returns the length between the current position to the
      24             :    next newline character. */
      25             : static Py_ssize_t
      26           0 : get_line(bytesio *self, char **output)
      27             : {
      28             :     char *n;
      29             :     const char *str_end;
      30             :     Py_ssize_t len;
      31             : 
      32             :     assert(self->buf != NULL);
      33             : 
      34             :     /* Move to the end of the line, up to the end of the string, s. */
      35           0 :     str_end = self->buf + self->string_size;
      36           0 :     for (n = self->buf + self->pos;
      37           0 :          n < str_end && *n != '\n';
      38           0 :          n++);
      39             : 
      40             :     /* Skip the newline character */
      41           0 :     if (n < str_end)
      42           0 :         n++;
      43             : 
      44             :     /* Get the length from the current position to the end of the line. */
      45           0 :     len = n - (self->buf + self->pos);
      46           0 :     *output = self->buf + self->pos;
      47             : 
      48             :     assert(len >= 0);
      49             :     assert(self->pos < PY_SSIZE_T_MAX - len);
      50           0 :     self->pos += len;
      51             : 
      52           0 :     return len;
      53             : }
      54             : 
      55             : /* Internal routine for changing the size of the buffer of BytesIO objects.
      56             :    The caller should ensure that the 'size' argument is non-negative.  Returns
      57             :    0 on success, -1 otherwise. */
      58             : static int
      59           0 : resize_buffer(bytesio *self, size_t size)
      60             : {
      61             :     /* Here, unsigned types are used to avoid dealing with signed integer
      62             :        overflow, which is undefined in C. */
      63           0 :     size_t alloc = self->buf_size;
      64           0 :     char *new_buf = NULL;
      65             : 
      66             :     assert(self->buf != NULL);
      67             : 
      68             :     /* For simplicity, stay in the range of the signed type. Anyway, Python
      69             :        doesn't allow strings to be longer than this. */
      70           0 :     if (size > PY_SSIZE_T_MAX)
      71           0 :         goto overflow;
      72             : 
      73           0 :     if (size < alloc / 2) {
      74             :         /* Major downsize; resize down to exact size. */
      75           0 :         alloc = size + 1;
      76             :     }
      77           0 :     else if (size < alloc) {
      78             :         /* Within allocated size; quick exit */
      79           0 :         return 0;
      80             :     }
      81           0 :     else if (size <= alloc * 1.125) {
      82             :         /* Moderate upsize; overallocate similar to list_resize() */
      83           0 :         alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
      84             :     }
      85             :     else {
      86             :         /* Major upsize; resize up to exact size */
      87           0 :         alloc = size + 1;
      88             :     }
      89             : 
      90             :     if (alloc > ((size_t)-1) / sizeof(char))
      91             :         goto overflow;
      92           0 :     new_buf = (char *)PyMem_Realloc(self->buf, alloc * sizeof(char));
      93           0 :     if (new_buf == NULL) {
      94           0 :         PyErr_NoMemory();
      95           0 :         return -1;
      96             :     }
      97           0 :     self->buf_size = alloc;
      98           0 :     self->buf = new_buf;
      99             : 
     100           0 :     return 0;
     101             : 
     102             :   overflow:
     103           0 :     PyErr_SetString(PyExc_OverflowError,
     104             :                     "new buffer size too large");
     105           0 :     return -1;
     106             : }
     107             : 
     108             : /* Internal routine for writing a string of bytes to the buffer of a BytesIO
     109             :    object. Returns the number of bytes written, or -1 on error. */
     110             : static Py_ssize_t
     111           0 : write_bytes(bytesio *self, const char *bytes, Py_ssize_t len)
     112             : {
     113             :     assert(self->buf != NULL);
     114             :     assert(self->pos >= 0);
     115             :     assert(len >= 0);
     116             : 
     117           0 :     if ((size_t)self->pos + len > self->buf_size) {
     118           0 :         if (resize_buffer(self, (size_t)self->pos + len) < 0)
     119           0 :             return -1;
     120             :     }
     121             : 
     122           0 :     if (self->pos > self->string_size) {
     123             :         /* In case of overseek, pad with null bytes the buffer region between
     124             :            the end of stream and the current position.
     125             : 
     126             :           0   lo      string_size                           hi
     127             :           |   |<---used--->|<----------available----------->|
     128             :           |   |            <--to pad-->|<---to write--->    |
     129             :           0   buf                   position
     130             :         */
     131           0 :         memset(self->buf + self->string_size, '\0',
     132           0 :                (self->pos - self->string_size) * sizeof(char));
     133             :     }
     134             : 
     135             :     /* Copy the data to the internal buffer, overwriting some of the existing
     136             :        data if self->pos < self->string_size. */
     137           0 :     memcpy(self->buf + self->pos, bytes, len);
     138           0 :     self->pos += len;
     139             : 
     140             :     /* Set the new length of the internal string if it has changed. */
     141           0 :     if (self->string_size < self->pos) {
     142           0 :         self->string_size = self->pos;
     143             :     }
     144             : 
     145           0 :     return len;
     146             : }
     147             : 
     148             : static PyObject *
     149           0 : bytesio_get_closed(bytesio *self)
     150             : {
     151           0 :     if (self->buf == NULL) {
     152           0 :         Py_RETURN_TRUE;
     153             :     }
     154             :     else {
     155           0 :         Py_RETURN_FALSE;
     156             :     }
     157             : }
     158             : 
     159             : PyDoc_STRVAR(readable_doc,
     160             : "readable() -> bool. Returns True if the IO object can be read.");
     161             : 
     162             : PyDoc_STRVAR(writable_doc,
     163             : "writable() -> bool. Returns True if the IO object can be written.");
     164             : 
     165             : PyDoc_STRVAR(seekable_doc,
     166             : "seekable() -> bool. Returns True if the IO object can be seeked.");
     167             : 
     168             : /* Generic getter for the writable, readable and seekable properties */
     169             : static PyObject *
     170           0 : return_not_closed(bytesio *self)
     171             : {
     172           0 :     CHECK_CLOSED(self);
     173           0 :     Py_RETURN_TRUE;
     174             : }
     175             : 
     176             : PyDoc_STRVAR(flush_doc,
     177             : "flush() -> None.  Does nothing.");
     178             : 
     179             : static PyObject *
     180           0 : bytesio_flush(bytesio *self)
     181             : {
     182           0 :     CHECK_CLOSED(self);
     183           0 :     Py_RETURN_NONE;
     184             : }
     185             : 
     186             : PyDoc_STRVAR(getval_doc,
     187             : "getvalue() -> bytes.\n"
     188             : "\n"
     189             : "Retrieve the entire contents of the BytesIO object.");
     190             : 
     191             : static PyObject *
     192           0 : bytesio_getvalue(bytesio *self)
     193             : {
     194           0 :     CHECK_CLOSED(self);
     195           0 :     return PyBytes_FromStringAndSize(self->buf, self->string_size);
     196             : }
     197             : 
     198             : PyDoc_STRVAR(isatty_doc,
     199             : "isatty() -> False.\n"
     200             : "\n"
     201             : "Always returns False since BytesIO objects are not connected\n"
     202             : "to a tty-like device.");
     203             : 
     204             : static PyObject *
     205           0 : bytesio_isatty(bytesio *self)
     206             : {
     207           0 :     CHECK_CLOSED(self);
     208           0 :     Py_RETURN_FALSE;
     209             : }
     210             : 
     211             : PyDoc_STRVAR(tell_doc,
     212             : "tell() -> current file position, an integer\n");
     213             : 
     214             : static PyObject *
     215           0 : bytesio_tell(bytesio *self)
     216             : {
     217           0 :     CHECK_CLOSED(self);
     218           0 :     return PyLong_FromSsize_t(self->pos);
     219             : }
     220             : 
     221             : PyDoc_STRVAR(read_doc,
     222             : "read([size]) -> read at most size bytes, returned as a string.\n"
     223             : "\n"
     224             : "If the size argument is negative, read until EOF is reached.\n"
     225             : "Return an empty string at EOF.");
     226             : 
     227             : static PyObject *
     228           0 : bytesio_read(bytesio *self, PyObject *args)
     229             : {
     230             :     Py_ssize_t size, n;
     231             :     char *output;
     232           0 :     PyObject *arg = Py_None;
     233             : 
     234           0 :     CHECK_CLOSED(self);
     235             : 
     236           0 :     if (!PyArg_ParseTuple(args, "|O:read", &arg))
     237           0 :         return NULL;
     238             : 
     239           0 :     if (PyNumber_Check(arg)) {
     240           0 :         size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
     241           0 :         if (size == -1 && PyErr_Occurred())
     242           0 :             return NULL;
     243             :     }
     244           0 :     else if (arg == Py_None) {
     245             :         /* Read until EOF is reached, by default. */
     246           0 :         size = -1;
     247             :     }
     248             :     else {
     249           0 :         PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
     250           0 :                      Py_TYPE(arg)->tp_name);
     251           0 :         return NULL;
     252             :     }
     253             : 
     254             :     /* adjust invalid sizes */
     255           0 :     n = self->string_size - self->pos;
     256           0 :     if (size < 0 || size > n) {
     257           0 :         size = n;
     258           0 :         if (size < 0)
     259           0 :             size = 0;
     260             :     }
     261             : 
     262             :     assert(self->buf != NULL);
     263           0 :     output = self->buf + self->pos;
     264           0 :     self->pos += size;
     265             : 
     266           0 :     return PyBytes_FromStringAndSize(output, size);
     267             : }
     268             : 
     269             : 
     270             : PyDoc_STRVAR(read1_doc,
     271             : "read1(size) -> read at most size bytes, returned as a string.\n"
     272             : "\n"
     273             : "If the size argument is negative or omitted, read until EOF is reached.\n"
     274             : "Return an empty string at EOF.");
     275             : 
     276             : static PyObject *
     277           0 : bytesio_read1(bytesio *self, PyObject *n)
     278             : {
     279             :     PyObject *arg, *res;
     280             : 
     281           0 :     arg = PyTuple_Pack(1, n);
     282           0 :     if (arg == NULL)
     283           0 :         return NULL;
     284           0 :     res  = bytesio_read(self, arg);
     285           0 :     Py_DECREF(arg);
     286           0 :     return res;
     287             : }
     288             : 
     289             : PyDoc_STRVAR(readline_doc,
     290             : "readline([size]) -> next line from the file, as a string.\n"
     291             : "\n"
     292             : "Retain newline.  A non-negative size argument limits the maximum\n"
     293             : "number of bytes to return (an incomplete line may be returned then).\n"
     294             : "Return an empty string at EOF.\n");
     295             : 
     296             : static PyObject *
     297           0 : bytesio_readline(bytesio *self, PyObject *args)
     298             : {
     299             :     Py_ssize_t size, n;
     300             :     char *output;
     301           0 :     PyObject *arg = Py_None;
     302             : 
     303           0 :     CHECK_CLOSED(self);
     304             : 
     305           0 :     if (!PyArg_ParseTuple(args, "|O:readline", &arg))
     306           0 :         return NULL;
     307             : 
     308           0 :     if (PyNumber_Check(arg)) {
     309           0 :         size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
     310           0 :         if (size == -1 && PyErr_Occurred())
     311           0 :             return NULL;
     312             :     }
     313           0 :     else if (arg == Py_None) {
     314             :         /* No size limit, by default. */
     315           0 :         size = -1;
     316             :     }
     317             :     else {
     318           0 :         PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
     319           0 :                      Py_TYPE(arg)->tp_name);
     320           0 :         return NULL;
     321             :     }
     322             : 
     323           0 :     n = get_line(self, &output);
     324             : 
     325           0 :     if (size >= 0 && size < n) {
     326           0 :         size = n - size;
     327           0 :         n -= size;
     328           0 :         self->pos -= size;
     329             :     }
     330             : 
     331           0 :     return PyBytes_FromStringAndSize(output, n);
     332             : }
     333             : 
     334             : PyDoc_STRVAR(readlines_doc,
     335             : "readlines([size]) -> list of strings, each a line from the file.\n"
     336             : "\n"
     337             : "Call readline() repeatedly and return a list of the lines so read.\n"
     338             : "The optional size argument, if given, is an approximate bound on the\n"
     339             : "total number of bytes in the lines returned.\n");
     340             : 
     341             : static PyObject *
     342           0 : bytesio_readlines(bytesio *self, PyObject *args)
     343             : {
     344             :     Py_ssize_t maxsize, size, n;
     345             :     PyObject *result, *line;
     346             :     char *output;
     347           0 :     PyObject *arg = Py_None;
     348             : 
     349           0 :     CHECK_CLOSED(self);
     350             : 
     351           0 :     if (!PyArg_ParseTuple(args, "|O:readlines", &arg))
     352           0 :         return NULL;
     353             : 
     354           0 :     if (PyNumber_Check(arg)) {
     355           0 :         maxsize = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
     356           0 :         if (maxsize == -1 && PyErr_Occurred())
     357           0 :             return NULL;
     358             :     }
     359           0 :     else if (arg == Py_None) {
     360             :         /* No size limit, by default. */
     361           0 :         maxsize = -1;
     362             :     }
     363             :     else {
     364           0 :         PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
     365           0 :                      Py_TYPE(arg)->tp_name);
     366           0 :         return NULL;
     367             :     }
     368             : 
     369           0 :     size = 0;
     370           0 :     result = PyList_New(0);
     371           0 :     if (!result)
     372           0 :         return NULL;
     373             : 
     374           0 :     while ((n = get_line(self, &output)) != 0) {
     375           0 :         line = PyBytes_FromStringAndSize(output, n);
     376           0 :         if (!line)
     377           0 :             goto on_error;
     378           0 :         if (PyList_Append(result, line) == -1) {
     379           0 :             Py_DECREF(line);
     380           0 :             goto on_error;
     381             :         }
     382           0 :         Py_DECREF(line);
     383           0 :         size += n;
     384           0 :         if (maxsize > 0 && size >= maxsize)
     385           0 :             break;
     386             :     }
     387           0 :     return result;
     388             : 
     389             :   on_error:
     390           0 :     Py_DECREF(result);
     391           0 :     return NULL;
     392             : }
     393             : 
     394             : PyDoc_STRVAR(readinto_doc,
     395             : "readinto(b) -> int.  Read up to len(b) bytes into b.\n"
     396             : "\n"
     397             : "Returns number of bytes read (0 for EOF), or None if the object\n"
     398             : "is set not to block and has no data to read.");
     399             : 
     400             : static PyObject *
     401           0 : bytesio_readinto(bytesio *self, PyObject *args)
     402             : {
     403             :     Py_buffer buf;
     404             :     Py_ssize_t len, n;
     405             : 
     406           0 :     CHECK_CLOSED(self);
     407             : 
     408           0 :     if (!PyArg_ParseTuple(args, "w*", &buf))
     409           0 :         return NULL;
     410             : 
     411           0 :     len = buf.len;
     412             :     /* adjust invalid sizes */
     413           0 :     n = self->string_size - self->pos;
     414           0 :     if (len > n) {
     415           0 :         len = n;
     416           0 :         if (len < 0)
     417           0 :             len = 0;
     418             :     }
     419             : 
     420           0 :     memcpy(buf.buf, self->buf + self->pos, len);
     421             :     assert(self->pos + len < PY_SSIZE_T_MAX);
     422             :     assert(len >= 0);
     423           0 :     self->pos += len;
     424             : 
     425           0 :     PyBuffer_Release(&buf);
     426           0 :     return PyLong_FromSsize_t(len);
     427             : }
     428             : 
     429             : PyDoc_STRVAR(truncate_doc,
     430             : "truncate([size]) -> int.  Truncate the file to at most size bytes.\n"
     431             : "\n"
     432             : "Size defaults to the current file position, as returned by tell().\n"
     433             : "The current file position is unchanged.  Returns the new size.\n");
     434             : 
     435             : static PyObject *
     436           0 : bytesio_truncate(bytesio *self, PyObject *args)
     437             : {
     438             :     Py_ssize_t size;
     439           0 :     PyObject *arg = Py_None;
     440             : 
     441           0 :     CHECK_CLOSED(self);
     442             : 
     443           0 :     if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
     444           0 :         return NULL;
     445             : 
     446           0 :     if (PyNumber_Check(arg)) {
     447           0 :         size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
     448           0 :         if (size == -1 && PyErr_Occurred())
     449           0 :             return NULL;
     450             :     }
     451           0 :     else if (arg == Py_None) {
     452             :         /* Truncate to current position if no argument is passed. */
     453           0 :         size = self->pos;
     454             :     }
     455             :     else {
     456           0 :         PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
     457           0 :                      Py_TYPE(arg)->tp_name);
     458           0 :         return NULL;
     459             :     }
     460             : 
     461           0 :     if (size < 0) {
     462           0 :         PyErr_Format(PyExc_ValueError,
     463             :                      "negative size value %zd", size);
     464           0 :         return NULL;
     465             :     }
     466             : 
     467           0 :     if (size < self->string_size) {
     468           0 :         self->string_size = size;
     469           0 :         if (resize_buffer(self, size) < 0)
     470           0 :             return NULL;
     471             :     }
     472             : 
     473           0 :     return PyLong_FromSsize_t(size);
     474             : }
     475             : 
     476             : static PyObject *
     477           0 : bytesio_iternext(bytesio *self)
     478             : {
     479             :     char *next;
     480             :     Py_ssize_t n;
     481             : 
     482           0 :     CHECK_CLOSED(self);
     483             : 
     484           0 :     n = get_line(self, &next);
     485             : 
     486           0 :     if (!next || n == 0)
     487           0 :         return NULL;
     488             : 
     489           0 :     return PyBytes_FromStringAndSize(next, n);
     490             : }
     491             : 
     492             : PyDoc_STRVAR(seek_doc,
     493             : "seek(pos[, whence]) -> int.  Change stream position.\n"
     494             : "\n"
     495             : "Seek to byte offset pos relative to position indicated by whence:\n"
     496             : "     0  Start of stream (the default).  pos should be >= 0;\n"
     497             : "     1  Current position - pos may be negative;\n"
     498             : "     2  End of stream - pos usually negative.\n"
     499             : "Returns the new absolute position.");
     500             : 
     501             : static PyObject *
     502           0 : bytesio_seek(bytesio *self, PyObject *args)
     503             : {
     504             :     PyObject *posobj;
     505             :     Py_ssize_t pos;
     506           0 :     int mode = 0;
     507             : 
     508           0 :     CHECK_CLOSED(self);
     509             : 
     510           0 :     if (!PyArg_ParseTuple(args, "O|i:seek", &posobj, &mode))
     511           0 :         return NULL;
     512             : 
     513           0 :     pos = PyNumber_AsSsize_t(posobj, PyExc_OverflowError);
     514           0 :     if (pos == -1 && PyErr_Occurred())
     515           0 :         return NULL;
     516             :     
     517           0 :     if (pos < 0 && mode == 0) {
     518           0 :         PyErr_Format(PyExc_ValueError,
     519             :                      "negative seek value %zd", pos);
     520           0 :         return NULL;
     521             :     }
     522             : 
     523             :     /* mode 0: offset relative to beginning of the string.
     524             :        mode 1: offset relative to current position.
     525             :        mode 2: offset relative the end of the string. */
     526           0 :     if (mode == 1) {
     527           0 :         if (pos > PY_SSIZE_T_MAX - self->pos) {
     528           0 :             PyErr_SetString(PyExc_OverflowError,
     529             :                             "new position too large");
     530           0 :             return NULL;
     531             :         }
     532           0 :         pos += self->pos;
     533             :     }
     534           0 :     else if (mode == 2) {
     535           0 :         if (pos > PY_SSIZE_T_MAX - self->string_size) {
     536           0 :             PyErr_SetString(PyExc_OverflowError,
     537             :                             "new position too large");
     538           0 :             return NULL;
     539             :         }
     540           0 :         pos += self->string_size;
     541             :     }
     542           0 :     else if (mode != 0) {
     543           0 :         PyErr_Format(PyExc_ValueError,
     544             :                      "invalid whence (%i, should be 0, 1 or 2)", mode);
     545           0 :         return NULL;
     546             :     }
     547             : 
     548           0 :     if (pos < 0)
     549           0 :         pos = 0;
     550           0 :     self->pos = pos;
     551             : 
     552           0 :     return PyLong_FromSsize_t(self->pos);
     553             : }
     554             : 
     555             : PyDoc_STRVAR(write_doc,
     556             : "write(bytes) -> int.  Write bytes to file.\n"
     557             : "\n"
     558             : "Return the number of bytes written.");
     559             : 
     560             : static PyObject *
     561           0 : bytesio_write(bytesio *self, PyObject *obj)
     562             : {
     563           0 :     Py_ssize_t n = 0;
     564             :     Py_buffer buf;
     565           0 :     PyObject *result = NULL;
     566             : 
     567           0 :     CHECK_CLOSED(self);
     568             : 
     569           0 :     if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0)
     570           0 :         return NULL;
     571             : 
     572           0 :     if (buf.len != 0)
     573           0 :         n = write_bytes(self, buf.buf, buf.len);
     574           0 :     if (n >= 0)
     575           0 :         result = PyLong_FromSsize_t(n);
     576             : 
     577           0 :     PyBuffer_Release(&buf);
     578           0 :     return result;
     579             : }
     580             : 
     581             : PyDoc_STRVAR(writelines_doc,
     582             : "writelines(sequence_of_strings) -> None.  Write strings to the file.\n"
     583             : "\n"
     584             : "Note that newlines are not added.  The sequence can be any iterable\n"
     585             : "object producing strings. This is equivalent to calling write() for\n"
     586             : "each string.");
     587             : 
     588             : static PyObject *
     589           0 : bytesio_writelines(bytesio *self, PyObject *v)
     590             : {
     591             :     PyObject *it, *item;
     592             :     PyObject *ret;
     593             : 
     594           0 :     CHECK_CLOSED(self);
     595             : 
     596           0 :     it = PyObject_GetIter(v);
     597           0 :     if (it == NULL)
     598           0 :         return NULL;
     599             : 
     600           0 :     while ((item = PyIter_Next(it)) != NULL) {
     601           0 :         ret = bytesio_write(self, item);
     602           0 :         Py_DECREF(item);
     603           0 :         if (ret == NULL) {
     604           0 :             Py_DECREF(it);
     605           0 :             return NULL;
     606             :         }
     607           0 :         Py_DECREF(ret);
     608             :     }
     609           0 :     Py_DECREF(it);
     610             : 
     611             :     /* See if PyIter_Next failed */
     612           0 :     if (PyErr_Occurred())
     613           0 :         return NULL;
     614             : 
     615           0 :     Py_RETURN_NONE;
     616             : }
     617             : 
     618             : PyDoc_STRVAR(close_doc,
     619             : "close() -> None.  Disable all I/O operations.");
     620             : 
     621             : static PyObject *
     622           0 : bytesio_close(bytesio *self)
     623             : {
     624           0 :     if (self->buf != NULL) {
     625           0 :         PyMem_Free(self->buf);
     626           0 :         self->buf = NULL;
     627             :     }
     628           0 :     Py_RETURN_NONE;
     629             : }
     630             : 
     631             : /* Pickling support.
     632             : 
     633             :    Note that only pickle protocol 2 and onward are supported since we use
     634             :    extended __reduce__ API of PEP 307 to make BytesIO instances picklable.
     635             : 
     636             :    Providing support for protocol < 2 would require the __reduce_ex__ method
     637             :    which is notably long-winded when defined properly.
     638             : 
     639             :    For BytesIO, the implementation would similar to one coded for
     640             :    object.__reduce_ex__, but slightly less general. To be more specific, we
     641             :    could call bytesio_getstate directly and avoid checking for the presence of
     642             :    a fallback __reduce__ method. However, we would still need a __newobj__
     643             :    function to use the efficient instance representation of PEP 307.
     644             :  */
     645             : 
     646             : static PyObject *
     647           0 : bytesio_getstate(bytesio *self)
     648             : {
     649           0 :     PyObject *initvalue = bytesio_getvalue(self);
     650             :     PyObject *dict;
     651             :     PyObject *state;
     652             : 
     653           0 :     if (initvalue == NULL)
     654           0 :         return NULL;
     655           0 :     if (self->dict == NULL) {
     656           0 :         Py_INCREF(Py_None);
     657           0 :         dict = Py_None;
     658             :     }
     659             :     else {
     660           0 :         dict = PyDict_Copy(self->dict);
     661           0 :         if (dict == NULL)
     662           0 :             return NULL;
     663             :     }
     664             : 
     665           0 :     state = Py_BuildValue("(OnN)", initvalue, self->pos, dict);
     666           0 :     Py_DECREF(initvalue);
     667           0 :     return state;
     668             : }
     669             : 
     670             : static PyObject *
     671           0 : bytesio_setstate(bytesio *self, PyObject *state)
     672             : {
     673             :     PyObject *result;
     674             :     PyObject *position_obj;
     675             :     PyObject *dict;
     676             :     Py_ssize_t pos;
     677             : 
     678             :     assert(state != NULL);
     679             : 
     680             :     /* We allow the state tuple to be longer than 3, because we may need
     681             :        someday to extend the object's state without breaking
     682             :        backward-compatibility. */
     683           0 :     if (!PyTuple_Check(state) || Py_SIZE(state) < 3) {
     684           0 :         PyErr_Format(PyExc_TypeError,
     685             :                      "%.200s.__setstate__ argument should be 3-tuple, got %.200s",
     686           0 :                      Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
     687           0 :         return NULL;
     688             :     }
     689             :     /* Reset the object to its default state. This is only needed to handle
     690             :        the case of repeated calls to __setstate__. */
     691           0 :     self->string_size = 0;
     692           0 :     self->pos = 0;
     693             : 
     694             :     /* Set the value of the internal buffer. If state[0] does not support the
     695             :        buffer protocol, bytesio_write will raise the appropriate TypeError. */
     696           0 :     result = bytesio_write(self, PyTuple_GET_ITEM(state, 0));
     697           0 :     if (result == NULL)
     698           0 :         return NULL;
     699           0 :     Py_DECREF(result);
     700             : 
     701             :     /* Set carefully the position value. Alternatively, we could use the seek
     702             :        method instead of modifying self->pos directly to better protect the
     703             :        object internal state against errneous (or malicious) inputs. */
     704           0 :     position_obj = PyTuple_GET_ITEM(state, 1);
     705           0 :     if (!PyIndex_Check(position_obj)) {
     706           0 :         PyErr_Format(PyExc_TypeError,
     707             :                      "second item of state must be an integer, not %.200s",
     708           0 :                      Py_TYPE(position_obj)->tp_name);
     709           0 :         return NULL;
     710             :     }
     711           0 :     pos = PyNumber_AsSsize_t(position_obj, PyExc_OverflowError);
     712           0 :     if (pos == -1 && PyErr_Occurred())
     713           0 :         return NULL;
     714           0 :     if (pos < 0) {
     715           0 :         PyErr_SetString(PyExc_ValueError,
     716             :                         "position value cannot be negative");
     717           0 :         return NULL;
     718             :     }
     719           0 :     self->pos = pos;
     720             : 
     721             :     /* Set the dictionary of the instance variables. */
     722           0 :     dict = PyTuple_GET_ITEM(state, 2);
     723           0 :     if (dict != Py_None) {
     724           0 :         if (!PyDict_Check(dict)) {
     725           0 :             PyErr_Format(PyExc_TypeError,
     726             :                          "third item of state should be a dict, got a %.200s",
     727           0 :                          Py_TYPE(dict)->tp_name);
     728           0 :             return NULL;
     729             :         }
     730           0 :         if (self->dict) {
     731             :             /* Alternatively, we could replace the internal dictionary
     732             :                completely. However, it seems more practical to just update it. */
     733           0 :             if (PyDict_Update(self->dict, dict) < 0)
     734           0 :                 return NULL;
     735             :         }
     736             :         else {
     737           0 :             Py_INCREF(dict);
     738           0 :             self->dict = dict;
     739             :         }
     740             :     }
     741             : 
     742           0 :     Py_RETURN_NONE;
     743             : }
     744             : 
     745             : static void
     746           0 : bytesio_dealloc(bytesio *self)
     747             : {
     748           0 :     _PyObject_GC_UNTRACK(self);
     749           0 :     if (self->buf != NULL) {
     750           0 :         PyMem_Free(self->buf);
     751           0 :         self->buf = NULL;
     752             :     }
     753           0 :     Py_CLEAR(self->dict);
     754           0 :     if (self->weakreflist != NULL)
     755           0 :         PyObject_ClearWeakRefs((PyObject *) self);
     756           0 :     Py_TYPE(self)->tp_free(self);
     757           0 : }
     758             : 
     759             : static PyObject *
     760           0 : bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     761             : {
     762             :     bytesio *self;
     763             : 
     764             :     assert(type != NULL && type->tp_alloc != NULL);
     765           0 :     self = (bytesio *)type->tp_alloc(type, 0);
     766           0 :     if (self == NULL)
     767           0 :         return NULL;
     768             : 
     769             :     /* tp_alloc initializes all the fields to zero. So we don't have to
     770             :        initialize them here. */
     771             : 
     772           0 :     self->buf = (char *)PyMem_Malloc(0);
     773           0 :     if (self->buf == NULL) {
     774           0 :         Py_DECREF(self);
     775           0 :         return PyErr_NoMemory();
     776             :     }
     777             : 
     778           0 :     return (PyObject *)self;
     779             : }
     780             : 
     781             : static int
     782           0 : bytesio_init(bytesio *self, PyObject *args, PyObject *kwds)
     783             : {
     784           0 :     char *kwlist[] = {"initial_bytes", NULL};
     785           0 :     PyObject *initvalue = NULL;
     786             : 
     787           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:BytesIO", kwlist,
     788             :                                      &initvalue))
     789           0 :         return -1;
     790             : 
     791             :     /* In case, __init__ is called multiple times. */
     792           0 :     self->string_size = 0;
     793           0 :     self->pos = 0;
     794             : 
     795           0 :     if (initvalue && initvalue != Py_None) {
     796             :         PyObject *res;
     797           0 :         res = bytesio_write(self, initvalue);
     798           0 :         if (res == NULL)
     799           0 :             return -1;
     800           0 :         Py_DECREF(res);
     801           0 :         self->pos = 0;
     802             :     }
     803             : 
     804           0 :     return 0;
     805             : }
     806             : 
     807             : static PyObject *
     808           0 : bytesio_sizeof(bytesio *self, void *unused)
     809             : {
     810             :     Py_ssize_t res;
     811             : 
     812           0 :     res = _PyObject_SIZE(Py_TYPE(self));
     813           0 :     if (self->buf)
     814           0 :         res += self->buf_size;
     815           0 :     return PyLong_FromSsize_t(res);
     816             : }
     817             : 
     818             : static int
     819           0 : bytesio_traverse(bytesio *self, visitproc visit, void *arg)
     820             : {
     821           0 :     Py_VISIT(self->dict);
     822           0 :     return 0;
     823             : }
     824             : 
     825             : static int
     826           0 : bytesio_clear(bytesio *self)
     827             : {
     828           0 :     Py_CLEAR(self->dict);
     829           0 :     return 0;
     830             : }
     831             : 
     832             : 
     833             : static PyGetSetDef bytesio_getsetlist[] = {
     834             :     {"closed",  (getter)bytesio_get_closed, NULL,
     835             :      "True if the file is closed."},
     836             :     {NULL},            /* sentinel */
     837             : };
     838             : 
     839             : static struct PyMethodDef bytesio_methods[] = {
     840             :     {"readable",   (PyCFunction)return_not_closed,  METH_NOARGS, readable_doc},
     841             :     {"seekable",   (PyCFunction)return_not_closed,  METH_NOARGS, seekable_doc},
     842             :     {"writable",   (PyCFunction)return_not_closed,  METH_NOARGS, writable_doc},
     843             :     {"close",      (PyCFunction)bytesio_close,      METH_NOARGS, close_doc},
     844             :     {"flush",      (PyCFunction)bytesio_flush,      METH_NOARGS, flush_doc},
     845             :     {"isatty",     (PyCFunction)bytesio_isatty,     METH_NOARGS, isatty_doc},
     846             :     {"tell",       (PyCFunction)bytesio_tell,       METH_NOARGS, tell_doc},
     847             :     {"write",      (PyCFunction)bytesio_write,      METH_O, write_doc},
     848             :     {"writelines", (PyCFunction)bytesio_writelines, METH_O, writelines_doc},
     849             :     {"read1",      (PyCFunction)bytesio_read1,      METH_O, read1_doc},
     850             :     {"readinto",   (PyCFunction)bytesio_readinto,   METH_VARARGS, readinto_doc},
     851             :     {"readline",   (PyCFunction)bytesio_readline,   METH_VARARGS, readline_doc},
     852             :     {"readlines",  (PyCFunction)bytesio_readlines,  METH_VARARGS, readlines_doc},
     853             :     {"read",       (PyCFunction)bytesio_read,       METH_VARARGS, read_doc},
     854             :     {"getvalue",   (PyCFunction)bytesio_getvalue,   METH_NOARGS,  getval_doc},
     855             :     {"seek",       (PyCFunction)bytesio_seek,       METH_VARARGS, seek_doc},
     856             :     {"truncate",   (PyCFunction)bytesio_truncate,   METH_VARARGS, truncate_doc},
     857             :     {"__getstate__",  (PyCFunction)bytesio_getstate,  METH_NOARGS, NULL},
     858             :     {"__setstate__",  (PyCFunction)bytesio_setstate,  METH_O, NULL},
     859             :     {"__sizeof__", (PyCFunction)bytesio_sizeof,     METH_NOARGS, NULL},
     860             :     {NULL, NULL}        /* sentinel */
     861             : };
     862             : 
     863             : PyDoc_STRVAR(bytesio_doc,
     864             : "BytesIO([buffer]) -> object\n"
     865             : "\n"
     866             : "Create a buffered I/O implementation using an in-memory bytes\n"
     867             : "buffer, ready for reading and writing.");
     868             : 
     869             : PyTypeObject PyBytesIO_Type = {
     870             :     PyVarObject_HEAD_INIT(NULL, 0)
     871             :     "_io.BytesIO",                             /*tp_name*/
     872             :     sizeof(bytesio),                     /*tp_basicsize*/
     873             :     0,                                         /*tp_itemsize*/
     874             :     (destructor)bytesio_dealloc,               /*tp_dealloc*/
     875             :     0,                                         /*tp_print*/
     876             :     0,                                         /*tp_getattr*/
     877             :     0,                                         /*tp_setattr*/
     878             :     0,                                         /*tp_reserved*/
     879             :     0,                                         /*tp_repr*/
     880             :     0,                                         /*tp_as_number*/
     881             :     0,                                         /*tp_as_sequence*/
     882             :     0,                                         /*tp_as_mapping*/
     883             :     0,                                         /*tp_hash*/
     884             :     0,                                         /*tp_call*/
     885             :     0,                                         /*tp_str*/
     886             :     0,                                         /*tp_getattro*/
     887             :     0,                                         /*tp_setattro*/
     888             :     0,                                         /*tp_as_buffer*/
     889             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
     890             :     Py_TPFLAGS_HAVE_GC,                        /*tp_flags*/
     891             :     bytesio_doc,                               /*tp_doc*/
     892             :     (traverseproc)bytesio_traverse,            /*tp_traverse*/
     893             :     (inquiry)bytesio_clear,                    /*tp_clear*/
     894             :     0,                                         /*tp_richcompare*/
     895             :     offsetof(bytesio, weakreflist),      /*tp_weaklistoffset*/
     896             :     PyObject_SelfIter,                         /*tp_iter*/
     897             :     (iternextfunc)bytesio_iternext,            /*tp_iternext*/
     898             :     bytesio_methods,                           /*tp_methods*/
     899             :     0,                                         /*tp_members*/
     900             :     bytesio_getsetlist,                        /*tp_getset*/
     901             :     0,                                         /*tp_base*/
     902             :     0,                                         /*tp_dict*/
     903             :     0,                                         /*tp_descr_get*/
     904             :     0,                                         /*tp_descr_set*/
     905             :     offsetof(bytesio, dict),             /*tp_dictoffset*/
     906             :     (initproc)bytesio_init,                    /*tp_init*/
     907             :     0,                                         /*tp_alloc*/
     908             :     bytesio_new,                               /*tp_new*/
     909             : };

Generated by: LCOV version 1.10