1# This file is part of Xpra.
2# Copyright (C) 2012-2021 Antoine Martin <antoine@xpra.org>
3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
4# later version. See the file COPYING for details.
5
6#cython: wraparound=False, boundscheck=False
7
8from libc.stdint cimport uint32_t, uintptr_t  #pylint: disable=syntax-error
9from xpra.buffers.membuf cimport getbuf, MemBuf
10from libc.string cimport memset
11
12
13cdef extern from "Python.h":
14    int PyObject_GetBuffer(object obj, Py_buffer *view, int flags)
15    void PyBuffer_Release(Py_buffer *view)
16    int PyBUF_ANY_CONTIGUOUS
17
18
19def xor_str(a, b):
20    assert len(a)==len(b), "cyxor cannot xor strings of different lengths (%s:%s vs %s:%s)" % (type(a), len(a), type(b), len(b))
21    cdef Py_buffer py_bufa
22    memset(&py_bufa, 0, sizeof(Py_buffer))
23    if PyObject_GetBuffer(a, &py_bufa, PyBUF_ANY_CONTIGUOUS):
24        raise Exception("failed to read pixel data from %s" % type(a))
25    cdef Py_buffer py_bufb
26    memset(&py_bufb, 0, sizeof(Py_buffer))
27    if PyObject_GetBuffer(b, &py_bufb, PyBUF_ANY_CONTIGUOUS):
28        PyBuffer_Release(&py_bufa)
29        raise Exception("failed to read pixel data from %s" % type(b))
30    cdef Py_ssize_t alen = py_bufa.len
31    cdef Py_ssize_t blen = py_bufb.len
32    if alen!=blen:
33        PyBuffer_Release(&py_bufa)
34        PyBuffer_Release(&py_bufb)
35        raise Exception("python or cython bug? buffers don't have the same length?")
36    cdef MemBuf out_buf = getbuf(alen)
37    cdef uintptr_t op = <uintptr_t> out_buf.get_mem()
38    cdef unsigned char *acbuf = <unsigned char *> py_bufa.buf
39    cdef unsigned char *bcbuf = <unsigned char *> py_bufb.buf
40    cdef unsigned char *ocbuf = <unsigned char *> op
41    cdef uint32_t *obuf = <uint32_t*> op
42    cdef uint32_t *abuf = <uint32_t*> py_bufa.buf
43    cdef uint32_t *bbuf = <uint32_t*> py_bufb.buf
44    cdef unsigned int i, j, steps, char_steps
45    if (alen % 4)!=0 or (blen % 4)!=0:
46        #unaligned access, use byte at a time slow path:
47        char_steps = alen
48        for 0 <= i < char_steps:
49            ocbuf[i] = acbuf[i] ^ bcbuf[i]
50    else:
51        #do 4 bytes at a time:
52        steps = alen // 4
53        if steps>0:
54            for 0 <= i < steps:
55                obuf[i] = abuf[i] ^ bbuf[i]
56        #bytes at a time again at the end:
57        char_steps = alen % 4
58        if char_steps>0:
59            for 0 <= i < char_steps:
60                j = alen-char_steps+i
61                ocbuf[j] = acbuf[j] ^ bcbuf[j]
62    PyBuffer_Release(&py_bufa)
63    PyBuffer_Release(&py_bufb)
64    return memoryview(out_buf)
65