diff --git a/dulwich/_diff_tree.c b/dulwich/_diff_tree.c index ebed2d7f..88d17ed9 100644 --- a/dulwich/_diff_tree.c +++ b/dulwich/_diff_tree.c @@ -1,510 +1,470 @@ /* * Copyright (C) 2010 Google, Inc. * * Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU * General Public License as public by the Free Software Foundation; version 2.0 * or (at your option) any later version. You can redistribute it and/or * modify it under the terms of either of these two licenses. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * You should have received a copy of the licenses; if not, see * for a copy of the GNU General Public License * and for a copy of the Apache * License, Version 2.0. */ #define PY_SSIZE_T_CLEAN #include #include #ifdef _MSC_VER typedef unsigned short mode_t; #endif -#if PY_MAJOR_VERSION < 3 -typedef long Py_hash_t; -#endif - -#if PY_MAJOR_VERSION >= 3 -#define PyInt_FromLong PyLong_FromLong -#define PyInt_AsLong PyLong_AsLong -#define PyInt_AS_LONG PyLong_AS_LONG -#define PyString_AS_STRING PyBytes_AS_STRING -#define PyString_AsStringAndSize PyBytes_AsStringAndSize -#define PyString_Check PyBytes_Check -#define PyString_CheckExact PyBytes_CheckExact -#define PyString_FromStringAndSize PyBytes_FromStringAndSize -#define PyString_FromString PyBytes_FromString -#define PyString_GET_SIZE PyBytes_GET_SIZE -#define PyString_Size PyBytes_Size -#define _PyString_Join _PyBytes_Join -#endif - static PyObject *tree_entry_cls = NULL, *null_entry = NULL, *defaultdict_cls = NULL, *int_cls = NULL; static int block_size; /** * Free an array of PyObject pointers, decrementing any references. */ static void free_objects(PyObject **objs, Py_ssize_t n) { Py_ssize_t i; for (i = 0; i < n; i++) Py_XDECREF(objs[i]); PyMem_Free(objs); } /** * Get the entries of a tree, prepending the given path. * * Args: * path: The path to prepend, without trailing slashes. * path_len: The length of path. * tree: The Tree object to iterate. * n: Set to the length of result. * Returns: A (C) array of PyObject pointers to TreeEntry objects for each path * in tree. */ static PyObject **tree_entries(char *path, Py_ssize_t path_len, PyObject *tree, Py_ssize_t *n) { PyObject *iteritems, *items, **result = NULL; PyObject *old_entry, *name, *sha; Py_ssize_t i = 0, name_len, new_path_len; char *new_path; if (tree == Py_None) { *n = 0; result = PyMem_New(PyObject*, 0); if (!result) { PyErr_NoMemory(); return NULL; } return result; } iteritems = PyObject_GetAttrString(tree, "iteritems"); if (!iteritems) return NULL; items = PyObject_CallFunctionObjArgs(iteritems, Py_True, NULL); Py_DECREF(iteritems); if (items == NULL) { return NULL; } /* The C implementation of iteritems returns a list, so depend on that. */ if (!PyList_Check(items)) { PyErr_SetString(PyExc_TypeError, "Tree.iteritems() did not return a list"); return NULL; } *n = PyList_Size(items); result = PyMem_New(PyObject*, *n); if (!result) { PyErr_NoMemory(); goto error; } for (i = 0; i < *n; i++) { old_entry = PyList_GetItem(items, i); if (!old_entry) goto error; sha = PyTuple_GetItem(old_entry, 2); if (!sha) goto error; name = PyTuple_GET_ITEM(old_entry, 0); - name_len = PyString_Size(name); + name_len = PyBytes_Size(name); if (PyErr_Occurred()) goto error; new_path_len = name_len; if (path_len) new_path_len += path_len + 1; new_path = PyMem_Malloc(new_path_len); if (!new_path) { PyErr_NoMemory(); goto error; } if (path_len) { memcpy(new_path, path, path_len); new_path[path_len] = '/'; - memcpy(new_path + path_len + 1, PyString_AS_STRING(name), name_len); + memcpy(new_path + path_len + 1, PyBytes_AS_STRING(name), name_len); } else { - memcpy(new_path, PyString_AS_STRING(name), name_len); + memcpy(new_path, PyBytes_AS_STRING(name), name_len); } -#if PY_MAJOR_VERSION >= 3 result[i] = PyObject_CallFunction(tree_entry_cls, "y#OO", new_path, new_path_len, PyTuple_GET_ITEM(old_entry, 1), sha); -#else - result[i] = PyObject_CallFunction(tree_entry_cls, "s#OO", new_path, - new_path_len, PyTuple_GET_ITEM(old_entry, 1), sha); -#endif PyMem_Free(new_path); if (!result[i]) { goto error; } } Py_DECREF(items); return result; error: if (result) free_objects(result, i); Py_DECREF(items); return NULL; } /** * Use strcmp to compare the paths of two TreeEntry objects. */ static int entry_path_cmp(PyObject *entry1, PyObject *entry2) { PyObject *path1 = NULL, *path2 = NULL; int result = 0; path1 = PyObject_GetAttrString(entry1, "path"); if (!path1) goto done; - if (!PyString_Check(path1)) { + if (!PyBytes_Check(path1)) { PyErr_SetString(PyExc_TypeError, "path is not a (byte)string"); goto done; } path2 = PyObject_GetAttrString(entry2, "path"); if (!path2) goto done; - if (!PyString_Check(path2)) { + if (!PyBytes_Check(path2)) { PyErr_SetString(PyExc_TypeError, "path is not a (byte)string"); goto done; } - result = strcmp(PyString_AS_STRING(path1), PyString_AS_STRING(path2)); + result = strcmp(PyBytes_AS_STRING(path1), PyBytes_AS_STRING(path2)); done: Py_XDECREF(path1); Py_XDECREF(path2); return result; } static PyObject *py_merge_entries(PyObject *self, PyObject *args) { PyObject *tree1, *tree2, **entries1 = NULL, **entries2 = NULL; PyObject *e1, *e2, *pair, *result = NULL; Py_ssize_t n1 = 0, n2 = 0, i1 = 0, i2 = 0, path_len; char *path_str; int cmp; -#if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTuple(args, "y#OO", &path_str, &path_len, &tree1, &tree2)) -#else - if (!PyArg_ParseTuple(args, "s#OO", &path_str, &path_len, &tree1, &tree2)) -#endif return NULL; entries1 = tree_entries(path_str, path_len, tree1, &n1); if (!entries1) goto error; entries2 = tree_entries(path_str, path_len, tree2, &n2); if (!entries2) goto error; result = PyList_New(0); if (!result) goto error; while (i1 < n1 && i2 < n2) { cmp = entry_path_cmp(entries1[i1], entries2[i2]); if (PyErr_Occurred()) goto error; if (!cmp) { e1 = entries1[i1++]; e2 = entries2[i2++]; } else if (cmp < 0) { e1 = entries1[i1++]; e2 = null_entry; } else { e1 = null_entry; e2 = entries2[i2++]; } pair = PyTuple_Pack(2, e1, e2); if (!pair) goto error; PyList_Append(result, pair); Py_DECREF(pair); } while (i1 < n1) { pair = PyTuple_Pack(2, entries1[i1++], null_entry); if (!pair) goto error; PyList_Append(result, pair); Py_DECREF(pair); } while (i2 < n2) { pair = PyTuple_Pack(2, null_entry, entries2[i2++]); if (!pair) goto error; PyList_Append(result, pair); Py_DECREF(pair); } goto done; error: Py_XDECREF(result); result = NULL; done: if (entries1) free_objects(entries1, n1); if (entries2) free_objects(entries2, n2); return result; } /* Not all environments define S_ISDIR */ #if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif static PyObject *py_is_tree(PyObject *self, PyObject *args) { PyObject *entry, *mode, *result; long lmode; if (!PyArg_ParseTuple(args, "O", &entry)) return NULL; mode = PyObject_GetAttrString(entry, "mode"); if (!mode) return NULL; if (mode == Py_None) { result = Py_False; Py_INCREF(result); } else { - lmode = PyInt_AsLong(mode); + lmode = PyLong_AsLong(mode); if (lmode == -1 && PyErr_Occurred()) { Py_DECREF(mode); return NULL; } result = PyBool_FromLong(S_ISDIR((mode_t)lmode)); } Py_DECREF(mode); return result; } static Py_hash_t add_hash(PyObject *get, PyObject *set, char *str, int n) { PyObject *str_obj = NULL, *hash_obj = NULL, *value = NULL, *set_value = NULL; Py_hash_t hash; /* It would be nice to hash without copying str into a PyString, but that * isn't exposed by the API. */ - str_obj = PyString_FromStringAndSize(str, n); + str_obj = PyBytes_FromStringAndSize(str, n); if (!str_obj) goto error; hash = PyObject_Hash(str_obj); if (hash == -1) goto error; - hash_obj = PyInt_FromLong(hash); + hash_obj = PyLong_FromLong(hash); if (!hash_obj) goto error; value = PyObject_CallFunctionObjArgs(get, hash_obj, NULL); if (!value) goto error; set_value = PyObject_CallFunction(set, "(Ol)", hash_obj, - PyInt_AS_LONG(value) + n); + PyLong_AS_LONG(value) + n); if (!set_value) goto error; Py_DECREF(str_obj); Py_DECREF(hash_obj); Py_DECREF(value); Py_DECREF(set_value); return 0; error: Py_XDECREF(str_obj); Py_XDECREF(hash_obj); Py_XDECREF(value); Py_XDECREF(set_value); return -1; } static PyObject *py_count_blocks(PyObject *self, PyObject *args) { PyObject *obj, *chunks = NULL, *chunk, *counts = NULL, *get = NULL, *set = NULL; char *chunk_str, *block = NULL; Py_ssize_t num_chunks, chunk_len; int i, j, n = 0; char c; if (!PyArg_ParseTuple(args, "O", &obj)) goto error; counts = PyObject_CallFunctionObjArgs(defaultdict_cls, int_cls, NULL); if (!counts) goto error; get = PyObject_GetAttrString(counts, "__getitem__"); set = PyObject_GetAttrString(counts, "__setitem__"); chunks = PyObject_CallMethod(obj, "as_raw_chunks", NULL); if (!chunks) goto error; if (!PyList_Check(chunks)) { PyErr_SetString(PyExc_TypeError, "as_raw_chunks() did not return a list"); goto error; } num_chunks = PyList_GET_SIZE(chunks); block = PyMem_New(char, block_size); if (!block) { PyErr_NoMemory(); goto error; } for (i = 0; i < num_chunks; i++) { chunk = PyList_GET_ITEM(chunks, i); - if (!PyString_Check(chunk)) { + if (!PyBytes_Check(chunk)) { PyErr_SetString(PyExc_TypeError, "chunk is not a string"); goto error; } - if (PyString_AsStringAndSize(chunk, &chunk_str, &chunk_len) == -1) + if (PyBytes_AsStringAndSize(chunk, &chunk_str, &chunk_len) == -1) goto error; for (j = 0; j < chunk_len; j++) { c = chunk_str[j]; block[n++] = c; if (c == '\n' || n == block_size) { if (add_hash(get, set, block, n) == -1) goto error; n = 0; } } } if (n && add_hash(get, set, block, n) == -1) goto error; Py_DECREF(chunks); Py_DECREF(get); Py_DECREF(set); PyMem_Free(block); return counts; error: Py_XDECREF(chunks); Py_XDECREF(get); Py_XDECREF(set); Py_XDECREF(counts); PyMem_Free(block); return NULL; } static PyMethodDef py_diff_tree_methods[] = { { "_is_tree", (PyCFunction)py_is_tree, METH_VARARGS, NULL }, { "_merge_entries", (PyCFunction)py_merge_entries, METH_VARARGS, NULL }, { "_count_blocks", (PyCFunction)py_count_blocks, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; static PyObject * moduleinit(void) { PyObject *m, *objects_mod = NULL, *diff_tree_mod = NULL; PyObject *block_size_obj = NULL; -#if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "_diff_tree", /* m_name */ NULL, /* m_doc */ -1, /* m_size */ py_diff_tree_methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear*/ NULL, /* m_free */ }; m = PyModule_Create(&moduledef); -#else - m = Py_InitModule("_diff_tree", py_diff_tree_methods); -#endif if (!m) goto error; objects_mod = PyImport_ImportModule("dulwich.objects"); if (!objects_mod) goto error; tree_entry_cls = PyObject_GetAttrString(objects_mod, "TreeEntry"); Py_DECREF(objects_mod); if (!tree_entry_cls) goto error; diff_tree_mod = PyImport_ImportModule("dulwich.diff_tree"); if (!diff_tree_mod) goto error; null_entry = PyObject_GetAttrString(diff_tree_mod, "_NULL_ENTRY"); if (!null_entry) goto error; block_size_obj = PyObject_GetAttrString(diff_tree_mod, "_BLOCK_SIZE"); if (!block_size_obj) goto error; - block_size = (int)PyInt_AsLong(block_size_obj); + block_size = (int)PyLong_AsLong(block_size_obj); if (PyErr_Occurred()) goto error; defaultdict_cls = PyObject_GetAttrString(diff_tree_mod, "defaultdict"); if (!defaultdict_cls) goto error; /* This is kind of hacky, but I don't know of a better way to get the * PyObject* version of int. */ int_cls = PyDict_GetItemString(PyEval_GetBuiltins(), "int"); if (!int_cls) { PyErr_SetString(PyExc_NameError, "int"); goto error; } Py_DECREF(diff_tree_mod); return m; error: Py_XDECREF(objects_mod); Py_XDECREF(diff_tree_mod); Py_XDECREF(null_entry); Py_XDECREF(block_size_obj); Py_XDECREF(defaultdict_cls); Py_XDECREF(int_cls); return NULL; } -#if PY_MAJOR_VERSION >= 3 PyMODINIT_FUNC PyInit__diff_tree(void) { return moduleinit(); } -#else -PyMODINIT_FUNC -init_diff_tree(void) -{ - moduleinit(); -} -#endif diff --git a/dulwich/_objects.c b/dulwich/_objects.c index eb8b9e5b..34635e82 100644 --- a/dulwich/_objects.c +++ b/dulwich/_objects.c @@ -1,335 +1,309 @@ /* * Copyright (C) 2009 Jelmer Vernooij * * Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU * General Public License as public by the Free Software Foundation; version 2.0 * or (at your option) any later version. You can redistribute it and/or * modify it under the terms of either of these two licenses. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * You should have received a copy of the licenses; if not, see * for a copy of the GNU General Public License * and for a copy of the Apache * License, Version 2.0. */ #define PY_SSIZE_T_CLEAN #include #include #include -#if PY_MAJOR_VERSION >= 3 -#define PyInt_Check(obj) 0 -#define PyInt_CheckExact(obj) 0 -#define PyInt_AsLong PyLong_AsLong -#define PyString_AS_STRING PyBytes_AS_STRING -#define PyString_Check PyBytes_Check -#define PyString_FromStringAndSize PyBytes_FromStringAndSize -#endif - #if defined(__MINGW32_VERSION) || defined(__APPLE__) size_t rep_strnlen(char *text, size_t maxlen); size_t rep_strnlen(char *text, size_t maxlen) { const char *last = memchr(text, '\0', maxlen); return last ? (size_t) (last - text) : maxlen; } #define strnlen rep_strnlen #endif #define bytehex(x) (((x)<0xa)?('0'+(x)):('a'-0xa+(x))) static PyObject *tree_entry_cls; static PyObject *object_format_exception_cls; static PyObject *sha_to_pyhex(const unsigned char *sha) { char hexsha[41]; int i; for (i = 0; i < 20; i++) { hexsha[i*2] = bytehex((sha[i] & 0xF0) >> 4); hexsha[i*2+1] = bytehex(sha[i] & 0x0F); } - return PyString_FromStringAndSize(hexsha, 40); + return PyBytes_FromStringAndSize(hexsha, 40); } static PyObject *py_parse_tree(PyObject *self, PyObject *args, PyObject *kw) { char *text, *start, *end; Py_ssize_t len; int strict; size_t namelen; PyObject *ret, *item, *name, *sha, *py_strict = NULL; static char *kwlist[] = {"text", "strict", NULL}; -#if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kw, "y#|O", kwlist, &text, &len, &py_strict)) -#else - if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|O", kwlist, - &text, &len, &py_strict)) -#endif return NULL; strict = py_strict ? PyObject_IsTrue(py_strict) : 0; /* TODO: currently this returns a list; if memory usage is a concern, * consider rewriting as a custom iterator object */ ret = PyList_New(0); if (ret == NULL) { return NULL; } start = text; end = text + len; while (text < end) { long mode; if (strict && text[0] == '0') { PyErr_SetString(object_format_exception_cls, "Illegal leading zero on mode"); Py_DECREF(ret); return NULL; } mode = strtol(text, &text, 8); if (*text != ' ') { PyErr_SetString(PyExc_ValueError, "Expected space"); Py_DECREF(ret); return NULL; } text++; namelen = strnlen(text, len - (text - start)); - name = PyString_FromStringAndSize(text, namelen); + name = PyBytes_FromStringAndSize(text, namelen); if (name == NULL) { Py_DECREF(ret); return NULL; } if (text + namelen + 20 >= end) { PyErr_SetString(PyExc_ValueError, "SHA truncated"); Py_DECREF(ret); Py_DECREF(name); return NULL; } sha = sha_to_pyhex((unsigned char *)text+namelen+1); if (sha == NULL) { Py_DECREF(ret); Py_DECREF(name); return NULL; } item = Py_BuildValue("(NlN)", name, mode, sha); if (item == NULL) { Py_DECREF(ret); Py_DECREF(sha); Py_DECREF(name); return NULL; } if (PyList_Append(ret, item) == -1) { Py_DECREF(ret); Py_DECREF(item); return NULL; } Py_DECREF(item); text += namelen+21; } return ret; } struct tree_item { const char *name; int mode; PyObject *tuple; }; /* Not all environments define S_ISDIR */ #if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif int cmp_tree_item(const void *_a, const void *_b) { const struct tree_item *a = _a, *b = _b; const char *remain_a, *remain_b; int ret; size_t common; if (strlen(a->name) > strlen(b->name)) { common = strlen(b->name); remain_a = a->name + common; remain_b = (S_ISDIR(b->mode)?"/":""); } else if (strlen(b->name) > strlen(a->name)) { common = strlen(a->name); remain_a = (S_ISDIR(a->mode)?"/":""); remain_b = b->name + common; } else { /* strlen(a->name) == strlen(b->name) */ common = 0; remain_a = a->name; remain_b = b->name; } ret = strncmp(a->name, b->name, common); if (ret != 0) return ret; return strcmp(remain_a, remain_b); } int cmp_tree_item_name_order(const void *_a, const void *_b) { const struct tree_item *a = _a, *b = _b; return strcmp(a->name, b->name); } static PyObject *py_sorted_tree_items(PyObject *self, PyObject *args) { struct tree_item *qsort_entries = NULL; int name_order, n = 0, i; PyObject *entries, *py_name_order, *ret, *key, *value, *py_mode, *py_sha; Py_ssize_t pos = 0, num_entries; int (*cmp)(const void *, const void *); if (!PyArg_ParseTuple(args, "OO", &entries, &py_name_order)) goto error; if (!PyDict_Check(entries)) { PyErr_SetString(PyExc_TypeError, "Argument not a dictionary"); goto error; } name_order = PyObject_IsTrue(py_name_order); if (name_order == -1) goto error; cmp = name_order ? cmp_tree_item_name_order : cmp_tree_item; num_entries = PyDict_Size(entries); if (PyErr_Occurred()) goto error; qsort_entries = PyMem_New(struct tree_item, num_entries); if (!qsort_entries) { PyErr_NoMemory(); goto error; } while (PyDict_Next(entries, &pos, &key, &value)) { - if (!PyString_Check(key)) { + if (!PyBytes_Check(key)) { PyErr_SetString(PyExc_TypeError, "Name is not a string"); goto error; } if (PyTuple_Size(value) != 2) { PyErr_SetString(PyExc_ValueError, "Tuple has invalid size"); goto error; } py_mode = PyTuple_GET_ITEM(value, 0); - if (!PyInt_Check(py_mode) && !PyLong_Check(py_mode)) { + if (!PyLong_Check(py_mode)) { PyErr_SetString(PyExc_TypeError, "Mode is not an integral type"); goto error; } py_sha = PyTuple_GET_ITEM(value, 1); - if (!PyString_Check(py_sha)) { + if (!PyBytes_Check(py_sha)) { PyErr_SetString(PyExc_TypeError, "SHA is not a string"); goto error; } - qsort_entries[n].name = PyString_AS_STRING(key); - qsort_entries[n].mode = PyInt_AsLong(py_mode); + qsort_entries[n].name = PyBytes_AS_STRING(key); + qsort_entries[n].mode = PyLong_AsLong(py_mode); qsort_entries[n].tuple = PyObject_CallFunctionObjArgs( tree_entry_cls, key, py_mode, py_sha, NULL); if (qsort_entries[n].tuple == NULL) goto error; n++; } qsort(qsort_entries, num_entries, sizeof(struct tree_item), cmp); ret = PyList_New(num_entries); if (ret == NULL) { PyErr_NoMemory(); goto error; } for (i = 0; i < num_entries; i++) { PyList_SET_ITEM(ret, i, qsort_entries[i].tuple); } PyMem_Free(qsort_entries); return ret; error: for (i = 0; i < n; i++) { Py_XDECREF(qsort_entries[i].tuple); } PyMem_Free(qsort_entries); return NULL; } static PyMethodDef py_objects_methods[] = { { "parse_tree", (PyCFunction)py_parse_tree, METH_VARARGS | METH_KEYWORDS, NULL }, { "sorted_tree_items", py_sorted_tree_items, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; static PyObject * moduleinit(void) { PyObject *m, *objects_mod, *errors_mod; -#if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "_objects", /* m_name */ NULL, /* m_doc */ -1, /* m_size */ py_objects_methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear*/ NULL, /* m_free */ }; m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_objects", py_objects_methods, NULL); -#endif if (m == NULL) { return NULL; } errors_mod = PyImport_ImportModule("dulwich.errors"); if (errors_mod == NULL) { return NULL; } object_format_exception_cls = PyObject_GetAttrString( errors_mod, "ObjectFormatException"); Py_DECREF(errors_mod); if (object_format_exception_cls == NULL) { return NULL; } /* This is a circular import but should be safe since this module is * imported at at the very bottom of objects.py. */ objects_mod = PyImport_ImportModule("dulwich.objects"); if (objects_mod == NULL) { return NULL; } tree_entry_cls = PyObject_GetAttrString(objects_mod, "TreeEntry"); Py_DECREF(objects_mod); if (tree_entry_cls == NULL) { return NULL; } return m; } -#if PY_MAJOR_VERSION >= 3 PyMODINIT_FUNC PyInit__objects(void) { return moduleinit(); } -#else -PyMODINIT_FUNC -init_objects(void) -{ - moduleinit(); -} -#endif diff --git a/dulwich/_pack.c b/dulwich/_pack.c index f2ef0649..3ee9828d 100644 --- a/dulwich/_pack.c +++ b/dulwich/_pack.c @@ -1,314 +1,282 @@ /* * Copyright (C) 2009 Jelmer Vernooij * * Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU * General Public License as public by the Free Software Foundation; version 2.0 * or (at your option) any later version. You can redistribute it and/or * modify it under the terms of either of these two licenses. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * You should have received a copy of the licenses; if not, see * for a copy of the GNU General Public License * and for a copy of the Apache * License, Version 2.0. */ #define PY_SSIZE_T_CLEAN #include #include -#if PY_MAJOR_VERSION >= 3 -#define PyInt_FromLong PyLong_FromLong -#define PyString_AS_STRING PyBytes_AS_STRING -#define PyString_AS_STRING PyBytes_AS_STRING -#define PyString_Check PyBytes_Check -#define PyString_CheckExact PyBytes_CheckExact -#define PyString_FromStringAndSize PyBytes_FromStringAndSize -#define PyString_FromString PyBytes_FromString -#define PyString_GET_SIZE PyBytes_GET_SIZE -#define PyString_Size PyBytes_Size -#define _PyString_Join _PyBytes_Join -#endif - static PyObject *PyExc_ApplyDeltaError = NULL; static int py_is_sha(PyObject *sha) { - if (!PyString_CheckExact(sha)) + if (!PyBytes_CheckExact(sha)) return 0; - if (PyString_Size(sha) != 20) + if (PyBytes_Size(sha) != 20) return 0; return 1; } static size_t get_delta_header_size(uint8_t *delta, size_t *index, size_t length) { size_t size = 0; size_t i = 0; while ((*index) < length) { uint8_t cmd = delta[*index]; (*index)++; size |= (cmd & ~0x80) << i; i += 7; if (!(cmd & 0x80)) break; } return size; } static PyObject *py_chunked_as_string(PyObject *py_buf) { if (PyList_Check(py_buf)) { - PyObject *sep = PyString_FromString(""); + PyObject *sep = PyBytes_FromString(""); if (sep == NULL) { PyErr_NoMemory(); return NULL; } - py_buf = _PyString_Join(sep, py_buf); + py_buf = _PyBytes_Join(sep, py_buf); Py_DECREF(sep); if (py_buf == NULL) { PyErr_NoMemory(); return NULL; } - } else if (PyString_Check(py_buf)) { + } else if (PyBytes_Check(py_buf)) { Py_INCREF(py_buf); } else { PyErr_SetString(PyExc_TypeError, "src_buf is not a string or a list of chunks"); return NULL; } return py_buf; } static PyObject *py_apply_delta(PyObject *self, PyObject *args) { uint8_t *src_buf, *delta; size_t src_buf_len, delta_len; size_t src_size, dest_size; size_t outindex = 0; size_t index; uint8_t *out; PyObject *ret, *py_src_buf, *py_delta, *ret_list; if (!PyArg_ParseTuple(args, "OO", &py_src_buf, &py_delta)) return NULL; py_src_buf = py_chunked_as_string(py_src_buf); if (py_src_buf == NULL) return NULL; py_delta = py_chunked_as_string(py_delta); if (py_delta == NULL) { Py_DECREF(py_src_buf); return NULL; } - src_buf = (uint8_t *)PyString_AS_STRING(py_src_buf); - src_buf_len = (size_t)PyString_GET_SIZE(py_src_buf); + src_buf = (uint8_t *)PyBytes_AS_STRING(py_src_buf); + src_buf_len = (size_t)PyBytes_GET_SIZE(py_src_buf); - delta = (uint8_t *)PyString_AS_STRING(py_delta); - delta_len = (size_t)PyString_GET_SIZE(py_delta); + delta = (uint8_t *)PyBytes_AS_STRING(py_delta); + delta_len = (size_t)PyBytes_GET_SIZE(py_delta); index = 0; src_size = get_delta_header_size(delta, &index, delta_len); if (src_size != src_buf_len) { PyErr_Format(PyExc_ApplyDeltaError, "Unexpected source buffer size: %lu vs %ld", src_size, src_buf_len); Py_DECREF(py_src_buf); Py_DECREF(py_delta); return NULL; } dest_size = get_delta_header_size(delta, &index, delta_len); - ret = PyString_FromStringAndSize(NULL, dest_size); + ret = PyBytes_FromStringAndSize(NULL, dest_size); if (ret == NULL) { PyErr_NoMemory(); Py_DECREF(py_src_buf); Py_DECREF(py_delta); return NULL; } - out = (uint8_t *)PyString_AS_STRING(ret); + out = (uint8_t *)PyBytes_AS_STRING(ret); while (index < delta_len) { uint8_t cmd = delta[index]; index++; if (cmd & 0x80) { size_t cp_off = 0, cp_size = 0; int i; for (i = 0; i < 4; i++) { if (cmd & (1 << i)) { uint8_t x = delta[index]; index++; cp_off |= x << (i * 8); } } for (i = 0; i < 3; i++) { if (cmd & (1 << (4+i))) { uint8_t x = delta[index]; index++; cp_size |= x << (i * 8); } } if (cp_size == 0) cp_size = 0x10000; if (cp_off + cp_size < cp_size || cp_off + cp_size > src_size || cp_size > dest_size) break; memcpy(out+outindex, src_buf+cp_off, cp_size); outindex += cp_size; dest_size -= cp_size; } else if (cmd != 0) { if (cmd > dest_size) break; memcpy(out+outindex, delta+index, cmd); outindex += cmd; index += cmd; dest_size -= cmd; } else { PyErr_SetString(PyExc_ApplyDeltaError, "Invalid opcode 0"); Py_DECREF(ret); Py_DECREF(py_delta); Py_DECREF(py_src_buf); return NULL; } } Py_DECREF(py_src_buf); Py_DECREF(py_delta); if (index != delta_len) { PyErr_SetString(PyExc_ApplyDeltaError, "delta not empty"); Py_DECREF(ret); return NULL; } if (dest_size != 0) { PyErr_SetString(PyExc_ApplyDeltaError, "dest size incorrect"); Py_DECREF(ret); return NULL; } ret_list = Py_BuildValue("[N]", ret); if (ret_list == NULL) { Py_DECREF(ret); return NULL; } return ret_list; } static PyObject *py_bisect_find_sha(PyObject *self, PyObject *args) { PyObject *unpack_name; char *sha; Py_ssize_t sha_len; int start, end; -#if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTuple(args, "iiy#O", &start, &end, &sha, &sha_len, &unpack_name)) -#else - if (!PyArg_ParseTuple(args, "iis#O", &start, &end, - &sha, &sha_len, &unpack_name)) -#endif return NULL; if (sha_len != 20) { PyErr_SetString(PyExc_ValueError, "Sha is not 20 bytes long"); return NULL; } if (start > end) { PyErr_SetString(PyExc_AssertionError, "start > end"); return NULL; } while (start <= end) { PyObject *file_sha; Py_ssize_t i = (start + end)/2; int cmp; file_sha = PyObject_CallFunction(unpack_name, "i", i); if (file_sha == NULL) { return NULL; } if (!py_is_sha(file_sha)) { PyErr_SetString(PyExc_TypeError, "unpack_name returned non-sha object"); Py_DECREF(file_sha); return NULL; } - cmp = memcmp(PyString_AS_STRING(file_sha), sha, 20); + cmp = memcmp(PyBytes_AS_STRING(file_sha), sha, 20); Py_DECREF(file_sha); if (cmp < 0) start = i + 1; else if (cmp > 0) end = i - 1; else { - return PyInt_FromLong(i); + return PyLong_FromLong(i); } } Py_RETURN_NONE; } static PyMethodDef py_pack_methods[] = { { "apply_delta", (PyCFunction)py_apply_delta, METH_VARARGS, NULL }, { "bisect_find_sha", (PyCFunction)py_bisect_find_sha, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; static PyObject * moduleinit(void) { PyObject *m; PyObject *errors_module; -#if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "_pack", /* m_name */ NULL, /* m_doc */ -1, /* m_size */ py_pack_methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear*/ NULL, /* m_free */ }; -#endif errors_module = PyImport_ImportModule("dulwich.errors"); if (errors_module == NULL) return NULL; PyExc_ApplyDeltaError = PyObject_GetAttrString(errors_module, "ApplyDeltaError"); Py_DECREF(errors_module); if (PyExc_ApplyDeltaError == NULL) return NULL; -#if PY_MAJOR_VERSION >= 3 m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_pack", py_pack_methods, NULL); -#endif if (m == NULL) return NULL; return m; } -#if PY_MAJOR_VERSION >= 3 PyMODINIT_FUNC PyInit__pack(void) { return moduleinit(); } -#else -PyMODINIT_FUNC -init_pack(void) -{ - moduleinit(); -} -#endif