2 * Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; version 2
7 * of the License or (at your option) a later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 static int py_is_sha(PyObject *sha)
25 if (!PyString_CheckExact(sha))
28 if (PyString_Size(sha) != 20)
35 static size_t get_delta_header_size(uint8_t *delta, int *index, int length)
39 while ((*index) < length) {
40 uint8_t cmd = delta[*index];
42 size |= (cmd & ~0x80) << i;
50 static PyObject *py_chunked_as_string(PyObject *py_buf)
52 if (PyList_Check(py_buf)) {
53 PyObject *sep = PyString_FromString("");
58 py_buf = _PyString_Join(sep, py_buf);
64 } else if (PyString_Check(py_buf)) {
67 PyErr_SetString(PyExc_TypeError,
68 "src_buf is not a string or a list of chunks");
74 static PyObject *py_apply_delta(PyObject *self, PyObject *args)
76 uint8_t *src_buf, *delta;
77 int src_buf_len, delta_len;
78 size_t src_size, dest_size;
82 PyObject *ret, *py_src_buf, *py_delta;
84 if (!PyArg_ParseTuple(args, "OO", &py_src_buf, &py_delta))
87 py_src_buf = py_chunked_as_string(py_src_buf);
88 if (py_src_buf == NULL)
91 py_delta = py_chunked_as_string(py_delta);
92 if (py_delta == NULL) {
93 Py_DECREF(py_src_buf);
97 src_buf = (uint8_t *)PyString_AS_STRING(py_src_buf);
98 src_buf_len = PyString_GET_SIZE(py_src_buf);
100 delta = (uint8_t *)PyString_AS_STRING(py_delta);
101 delta_len = PyString_GET_SIZE(py_delta);
104 src_size = get_delta_header_size(delta, &index, delta_len);
105 if (src_size != src_buf_len) {
106 PyErr_Format(PyExc_ValueError,
107 "Unexpected source buffer size: %lu vs %d", src_size, src_buf_len);
108 Py_DECREF(py_src_buf);
112 dest_size = get_delta_header_size(delta, &index, delta_len);
113 ret = PyString_FromStringAndSize(NULL, dest_size);
116 Py_DECREF(py_src_buf);
120 out = (uint8_t *)PyString_AsString(ret);
121 while (index < delta_len) {
122 char cmd = delta[index];
125 size_t cp_off = 0, cp_size = 0;
127 for (i = 0; i < 4; i++) {
128 if (cmd & (1 << i)) {
129 uint8_t x = delta[index];
131 cp_off |= x << (i * 8);
134 for (i = 0; i < 3; i++) {
135 if (cmd & (1 << (4+i))) {
136 uint8_t x = delta[index];
138 cp_size |= x << (i * 8);
143 if (cp_off + cp_size < cp_size ||
144 cp_off + cp_size > src_size ||
147 memcpy(out+outindex, src_buf+cp_off, cp_size);
149 } else if (cmd != 0) {
150 memcpy(out+outindex, delta+index, cmd);
154 PyErr_SetString(PyExc_ValueError, "Invalid opcode 0");
157 Py_DECREF(py_src_buf);
161 Py_DECREF(py_src_buf);
164 if (index != delta_len) {
165 PyErr_SetString(PyExc_ValueError, "delta not empty");
170 if (dest_size != outindex) {
171 PyErr_SetString(PyExc_ValueError, "dest size incorrect");
176 return Py_BuildValue("[N]", ret);
179 static PyObject *py_bisect_find_sha(PyObject *self, PyObject *args)
181 PyObject *unpack_name;
185 if (!PyArg_ParseTuple(args, "iis#O", &start, &end,
186 &sha, &sha_len, &unpack_name))
190 PyErr_SetString(PyExc_ValueError, "Sha is not 20 bytes long");
194 PyErr_SetString(PyExc_AssertionError, "start > end");
198 while (start <= end) {
200 int i = (start + end)/2;
202 file_sha = PyObject_CallFunction(unpack_name, "i", i);
203 if (file_sha == NULL) {
206 if (!py_is_sha(file_sha)) {
207 PyErr_SetString(PyExc_TypeError, "unpack_name returned non-sha object");
211 cmp = memcmp(PyString_AsString(file_sha), sha, 20);
218 return PyInt_FromLong(i);
225 static PyMethodDef py_pack_methods[] = {
226 { "apply_delta", (PyCFunction)py_apply_delta, METH_VARARGS, NULL },
227 { "bisect_find_sha", (PyCFunction)py_bisect_find_sha, METH_VARARGS, NULL },
228 { NULL, NULL, 0, NULL }
235 m = Py_InitModule3("_pack", py_pack_methods, NULL);