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;
51 static PyObject *py_apply_delta(PyObject *self, PyObject *args)
53 uint8_t *src_buf, *delta;
54 int src_buf_len, delta_len;
55 size_t src_size, dest_size;
61 if (!PyArg_ParseTuple(args, "s#s#", (uint8_t *)&src_buf, &src_buf_len,
62 (uint8_t *)&delta, &delta_len))
66 src_size = get_delta_header_size(delta, &index, delta_len);
67 if (src_size != src_buf_len) {
68 PyErr_Format(PyExc_ValueError,
69 "Unexpected source buffer size: %lu vs %d", src_size, src_buf_len);
72 dest_size = get_delta_header_size(delta, &index, delta_len);
73 ret = PyString_FromStringAndSize(NULL, dest_size);
78 out = (uint8_t *)PyString_AsString(ret);
79 while (index < delta_len) {
80 char cmd = delta[index];
83 size_t cp_off = 0, cp_size = 0;
85 for (i = 0; i < 4; i++) {
87 uint8_t x = delta[index];
89 cp_off |= x << (i * 8);
92 for (i = 0; i < 3; i++) {
93 if (cmd & (1 << (4+i))) {
94 uint8_t x = delta[index];
96 cp_size |= x << (i * 8);
101 if (cp_off + cp_size < cp_size ||
102 cp_off + cp_size > src_size ||
105 memcpy(out+outindex, src_buf+cp_off, cp_size);
107 } else if (cmd != 0) {
108 memcpy(out+outindex, delta+index, cmd);
112 PyErr_SetString(PyExc_ValueError, "Invalid opcode 0");
117 if (index != delta_len) {
118 PyErr_SetString(PyExc_ValueError, "delta not empty");
122 if (dest_size != outindex) {
123 PyErr_SetString(PyExc_ValueError, "dest size incorrect");
130 static PyObject *py_bisect_find_sha(PyObject *self, PyObject *args)
132 PyObject *unpack_name;
136 if (!PyArg_ParseTuple(args, "iis#O", &start, &end,
137 &sha, &sha_len, &unpack_name))
141 PyErr_SetString(PyExc_ValueError, "Sha is not 20 bytes long");
145 PyErr_SetString(PyExc_AssertionError, "start > end");
149 while (start <= end) {
151 int i = (start + end)/2;
153 file_sha = PyObject_CallFunction(unpack_name, "i", i);
154 if (file_sha == NULL) {
157 if (!py_is_sha(file_sha)) {
158 PyErr_SetString(PyExc_TypeError, "unpack_name returned non-sha object");
162 cmp = memcmp(PyString_AsString(file_sha), sha, 20);
169 return PyInt_FromLong(i);
176 static PyMethodDef py_pack_methods[] = {
177 { "apply_delta", (PyCFunction)py_apply_delta, METH_VARARGS, NULL },
178 { "bisect_find_sha", (PyCFunction)py_bisect_find_sha, METH_VARARGS, NULL },
185 m = Py_InitModule3("_pack", py_pack_methods, NULL);