~ubuntu-branches/ubuntu/hardy/psycopg2/hardy

« back to all changes in this revision

Viewing changes to psycopg/typecast_binary.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio Tranchitella
  • Date: 2006-08-09 10:28:30 UTC
  • Revision ID: james.westby@ubuntu.com-20060809102830-grac1dsp24uyqfp4
Tags: upstream-2.0.4
ImportĀ upstreamĀ versionĀ 2.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* typecast_binary.c - binary typecasting functions to python types
 
2
 *
 
3
 * Copyright (C) 2001-2003 Federico Di Gregorio <fog@debian.org>
 
4
 *
 
5
 * This file is part of the psycopg module.
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License
 
9
 * as published by the Free Software Foundation; either version 2,
 
10
 * or (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include "typecast_binary.h"
 
23
 
 
24
#include <libpq-fe.h>
 
25
#include <stdlib.h>
 
26
 
 
27
 
 
28
/* Python object holding a memory chunk. The memory is deallocated when
 
29
   the object is destroyed. This type is used to let users directly access
 
30
   memory chunks holding unescaped binary data through the buffer interface.
 
31
 */
 
32
 
 
33
static void
 
34
chunk_dealloc(chunkObject *self)
 
35
{
 
36
    Dprintf("chunk_dealloc: deallocating memory at %p, size %d",
 
37
            self->base, self->len);
 
38
    free(self->base);
 
39
    self->ob_type->tp_free((PyObject *) self);
 
40
}
 
41
 
 
42
static PyObject *
 
43
chunk_repr(chunkObject *self)
 
44
{
 
45
    return PyString_FromFormat("<memory chunk at %p size %d>",
 
46
                               self->base, self->len);
 
47
}
 
48
 
 
49
static int
 
50
chunk_getreadbuffer(chunkObject *self, int segment, void **ptr)
 
51
{
 
52
    if (segment != 0)
 
53
    {
 
54
        PyErr_SetString(PyExc_SystemError,
 
55
                        "acessing non-existant buffer segment");
 
56
        return -1;
 
57
    }
 
58
    *ptr = self->base;
 
59
    return self->len;
 
60
}
 
61
 
 
62
static int
 
63
chunk_getsegcount(chunkObject *self, int *lenp)
 
64
{
 
65
    if (lenp != NULL)
 
66
        *lenp = self->len;
 
67
    return 1;
 
68
}
 
69
 
 
70
static PyBufferProcs chunk_as_buffer =
 
71
{
 
72
    (getreadbufferproc) chunk_getreadbuffer,
 
73
    (getwritebufferproc) NULL,
 
74
    (getsegcountproc) chunk_getsegcount,
 
75
    (getcharbufferproc) NULL
 
76
};
 
77
 
 
78
#define chunk_doc "memory chunk"
 
79
 
 
80
PyTypeObject chunkType = {
 
81
    PyObject_HEAD_INIT(NULL)
 
82
    0,                          /* ob_size */
 
83
    "psycopg2._psycopg.chunk",   /* tp_name */
 
84
    sizeof(chunkObject),        /* tp_basicsize */
 
85
    0,                          /* tp_itemsize */
 
86
    (destructor) chunk_dealloc, /* tp_dealloc*/
 
87
    0,                          /* tp_print */
 
88
    0,                          /* tp_getattr */
 
89
    0,                          /* tp_setattr */
 
90
    0,                          /* tp_compare */
 
91
    (reprfunc) chunk_repr,      /* tp_repr */
 
92
    0,                          /* tp_as_number */
 
93
    0,                          /* tp_as_sequence */
 
94
    0,                          /* tp_as_mapping */
 
95
    0,                          /* tp_hash */
 
96
    0,                          /* tp_call */
 
97
    0,                          /* tp_str */
 
98
    0,                          /* tp_getattro */
 
99
    0,                          /* tp_setattro */
 
100
    &chunk_as_buffer,           /* tp_as_buffer */
 
101
    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
 
102
    chunk_doc                   /* tp_doc */
 
103
};
 
104
 
 
105
/* the function typecast_BINARY_cast_unescape is used when libpq does not
 
106
   provide PQunescapeBytea: it convert all the \xxx octal sequences to the
 
107
   proper byte value */
 
108
 
 
109
#ifdef PSYCOPG_OWN_QUOTING
 
110
static unsigned char *
 
111
typecast_BINARY_cast_unescape(unsigned char *str, size_t *to_length)
 
112
{
 
113
    char *dstptr, *dststr;
 
114
    int len, i;
 
115
 
 
116
    len = strlen(str);
 
117
    dststr = (char*)calloc(len, sizeof(char));
 
118
    dstptr = dststr;
 
119
 
 
120
    if (dststr == NULL) return NULL;
 
121
 
 
122
    Py_BEGIN_ALLOW_THREADS;
 
123
   
 
124
    for (i = 0; i < len; i++) {
 
125
        if (str[i] == '\\') {
 
126
            if ( ++i < len) {
 
127
                if (str[i] == '\\') {
 
128
                    *dstptr = '\\';
 
129
                }
 
130
                else {
 
131
                    *dstptr = 0;
 
132
                    *dstptr |= (str[i++] & 7) << 6;
 
133
                    *dstptr |= (str[i++] & 7) << 3;
 
134
                    *dstptr |= (str[i] & 7);
 
135
                }
 
136
            }
 
137
        }
 
138
        else {
 
139
            *dstptr = str[i];
 
140
        }
 
141
        dstptr++;
 
142
    }
 
143
    
 
144
    Py_END_ALLOW_THREADS;
 
145
 
 
146
    *to_length = (size_t)(dstptr-dststr);
 
147
    
 
148
    return dststr;
 
149
}
 
150
 
 
151
#define PQunescapeBytea typecast_BINARY_cast_unescape
 
152
#endif
 
153
    
 
154
static PyObject *
 
155
typecast_BINARY_cast(char *s, int l, PyObject *curs)
 
156
{
 
157
    chunkObject *chunk;
 
158
    PyObject *res;
 
159
    char *str, *buffer = NULL;
 
160
    size_t len;
 
161
 
 
162
    if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
 
163
 
 
164
    /* PQunescapeBytea absolutely wants a 0-terminated string and we don't
 
165
       want to copy the whole buffer, right? Wrong, but there isn't any other
 
166
       way <g> */
 
167
    if (s[l] != '\0') {
 
168
        if ((buffer = PyMem_Malloc(l+1)) == NULL)
 
169
            PyErr_NoMemory();
 
170
        strncpy(buffer, s, l);
 
171
        buffer[l] = '\0';
 
172
        s = buffer;
 
173
    }
 
174
    str = (char*)PQunescapeBytea((unsigned char*)s, &len);
 
175
    Dprintf("typecast_BINARY_cast: unescaped %d bytes", len);
 
176
    if (buffer) PyMem_Free(buffer);
 
177
 
 
178
    chunk = (chunkObject *) PyObject_New(chunkObject, &chunkType);
 
179
    if (chunk == NULL) return NULL;
 
180
    
 
181
    chunk->base = str;
 
182
    chunk->len = len;
 
183
    if ((res = PyBuffer_FromObject((PyObject *)chunk, 0, len)) == NULL)
 
184
        return NULL;
 
185
 
 
186
    /* PyBuffer_FromObject() created a new reference. Release our reference so
 
187
       that the memory can be freed once the buffer is garbage collected. */
 
188
    Py_DECREF(chunk);
 
189
 
 
190
    return res;
 
191
}