1###############################################################################
2##
3##  Copyright (C) 2012-2013 Tavendo GmbH
4##
5##  Licensed under the Apache License, Version 2.0 (the "License");
6##  you may not use this file except in compliance with the License.
7##  You may obtain a copy of the License at
8##
9##      http://www.apache.org/licenses/LICENSE-2.0
10##
11##  Unless required by applicable law or agreed to in writing, software
12##  distributed under the License is distributed on an "AS IS" BASIS,
13##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14##  See the License for the specific language governing permissions and
15##  limitations under the License.
16##
17###############################################################################
18
19import six
20
21
22## use Cython implementation of XorMasker validator if available
23##
24try:
25   from wsaccel.xormask import XorMaskerNull, createXorMasker
26
27except:
28   ## fallback to pure Python implementation
29
30   ## http://stackoverflow.com/questions/15014310/python3-xrange-lack-hurts
31   try:
32      xrange
33   except NameError:
34      ## Python 3
35      xrange = range
36
37   from array import array
38
39   class XorMaskerNull:
40
41      # noinspection PyUnusedLocal
42      def __init__(self, mask = None):
43         self.ptr = 0
44
45      def pointer(self):
46         return self.ptr
47
48      def reset(self):
49         self.ptr = 0
50
51      def process(self, data):
52         self.ptr += len(data)
53         return data
54
55
56   class XorMaskerSimple:
57
58      def __init__(self, mask):
59         assert len(mask) == 4
60         self.ptr = 0
61         self.msk = array('B', mask)
62
63      def pointer(self):
64         return self.ptr
65
66      def reset(self):
67         self.ptr = 0
68
69      def process(self, data):
70         dlen = len(data)
71         payload = array('B', data)
72         for k in xrange(dlen):
73            payload[k] ^= self.msk[self.ptr & 3]
74            self.ptr += 1
75         return payload.tostring()
76
77
78   class XorMaskerShifted1:
79
80      def __init__(self, mask):
81         assert len(mask) == 4
82         self.ptr = 0
83         self.mskarray = [array('B'), array('B'), array('B'), array('B')]
84         if six.PY3:
85            for j in xrange(4):
86               self.mskarray[0].append(mask[ j & 3])
87               self.mskarray[1].append(mask[(j + 1) & 3])
88               self.mskarray[2].append(mask[(j + 2) & 3])
89               self.mskarray[3].append(mask[(j + 3) & 3])
90         else:
91            for j in xrange(4):
92               self.mskarray[0].append(ord(mask[ j & 3]))
93               self.mskarray[1].append(ord(mask[(j + 1) & 3]))
94               self.mskarray[2].append(ord(mask[(j + 2) & 3]))
95               self.mskarray[3].append(ord(mask[(j + 3) & 3]))
96
97      def pointer(self):
98         return self.ptr
99
100      def reset(self):
101         self.ptr = 0
102
103      def process(self, data):
104         dlen = len(data)
105         payload = array('B', data)
106         msk = self.mskarray[self.ptr & 3]
107         for k in xrange(dlen):
108            payload[k] ^= msk[k & 3]
109         self.ptr += dlen
110         return payload.tostring()
111
112
113   def createXorMasker(mask, len = None):
114      if len is None or len < 128:
115         return XorMaskerSimple(mask)
116      else:
117         return XorMaskerShifted1(mask)
118