This file is indexed.

/usr/lib/python2.7/dist-packages/svgwrite/data/typechecker.py is in python-svgwrite 1.1.8-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#!/usr/bin/env python
#coding:utf-8
# Author:  mozman --<mozman@gmx.at>
# Purpose: typechecker
# Created: 15.10.2010
# Copyright (C) 2010, Manfred Moitzi
# License: MIT License

import re

from svgwrite.data import pattern
from svgwrite.data.colors import colornames
from svgwrite.data.svgparser import is_valid_transferlist, is_valid_pathdata, is_valid_animation_timing
from svgwrite.utils import is_string, to_unicode

def iterflatlist(values):
    """ Flatten nested *values*, returns an *iterator*. """
    for element in values:
        if hasattr(element, "__iter__") and not is_string(element):
            for item in iterflatlist(element):
                yield item
        else:
            yield element

INVALID_NAME_CHARS = frozenset([' ', '\t', '\r', '\n', ',', '(', ')'])
WHITESPACE = frozenset([' ', '\t', '\r', '\n'])
SHAPE_PATTERN = re.compile(r"^rect\((.*),(.*),(.*),(.*)\)$")
FUNCIRI_PATTERN = re.compile(r"^url\((.*)\)$")
ICCCOLOR_PATTERN = re.compile(r"^icc-color\((.*)\)$")
COLOR_HEXDIGIT_PATTERN = re.compile(r"^#[a-fA-F0-9]{3}([a-fA-F0-9]{3})?$")
COLOR_RGB_INTEGER_PATTERN = re.compile(r"^rgb\( *\d+ *, *\d+ *, *\d+ *\)$")
COLOR_RGB_PERCENTAGE_PATTERN = re.compile(r"^rgb\( *\d+(\.\d*)?% *, *\d+(\.\d*)?% *, *\d+(\.\d*)?% *\)$")
NMTOKEN_PATTERN = re.compile(r"^[a-zA-Z_:][\w\-\.:]*$")


class Full11TypeChecker(object):
    def get_version(self):
        return '1.1', 'full'

    def is_angle(self, value):
        #angle ::= number (~"deg" | ~"grad" | ~"rad")?
        if self.is_number(value):
            return True
        elif is_string(value):
            return pattern.angle.match(value.strip()) is not None
        return False

    def is_anything(self, value):
        #anything ::= Char*
        return bool(str(value).strip())
    is_string = is_anything
    is_content_type = is_anything

    def is_color(self, value):
        #color    ::= "#" hexdigit hexdigit hexdigit (hexdigit hexdigit hexdigit)?
        #             | "rgb(" wsp* integer comma integer comma integer wsp* ")"
        #             | "rgb(" wsp* number "%" comma number "%" comma number "%" wsp* ")"
        #             | color-keyword
        #hexdigit ::= [0-9A-Fa-f]
        #comma    ::= wsp* "," wsp*
        value = str(value).strip()
        if value.startswith('#'):
            if COLOR_HEXDIGIT_PATTERN.match(value):
                return True
            else:
                return False
        elif value.startswith('rgb('):
            if COLOR_RGB_INTEGER_PATTERN.match(value):
                return True
            elif COLOR_RGB_PERCENTAGE_PATTERN.match(value):
                return True
            return False
        return self.is_color_keyword(value)

    def is_color_keyword(self, value):
        return value.strip() in colornames

    def is_frequency(self, value):
        #frequency ::= number (~"Hz" | ~"kHz")
        if self.is_number(value):
            return True
        elif is_string(value):
            return pattern.frequency.match(value.strip()) is not None
        return False

    def is_FuncIRI(self, value):
        #FuncIRI ::= "url(" <IRI> ")"
        res = FUNCIRI_PATTERN.match(str(value).strip())
        if res:
            return self.is_IRI(res.group(1))
        return False

    def is_icccolor(self, value):
        #icccolor ::= "icc-color(" name (comma-wsp number)+ ")"
        res = ICCCOLOR_PATTERN.match(str(value).strip())
        if res:
            return self.is_list_of_T(res.group(1), 'name')
        return False

    def is_integer(self, value):
        if isinstance(value, float):
            return False
        try:
            number = int(value)
            return True
        except:
            return False

    def is_IRI(self, value):
        # Internationalized Resource Identifiers
        # a more generalized complement to Uniform Resource Identifiers (URIs)
        # nearly everything can be a valid <IRI>
        # only a none-empty string ist a valid input
        if is_string(value):
            return bool(value.strip())
        else:
            return False

    def is_length(self, value):
        #length ::= number ("em" | "ex" | "px" | "in" | "cm" | "mm" | "pt" | "pc" | "%")?
        if value is None:
            return False
        if isinstance(value, (int, float)):
            return self.is_number(value)
        elif is_string(value):
            result = pattern.length.match(value.strip())
            if result:
                number, tmp, unit = result.groups()
                return self.is_number(number) # for tiny check!
        return False

    is_coordinate = is_length

    def is_list_of_T(self, value, t='string'):
        def split(value):
            #TODO: improve split function!!!!
            if isinstance(value, (int, float)):
                return (value, )
            if is_string(value):
                return iterflatlist(v.split(',') for v in value.split(' '))
            return value
        #list-of-Ts ::= T
        #               | T comma-wsp list-of-Ts
        #comma-wsp  ::= (wsp+ ","? wsp*) | ("," wsp*)
        #wsp        ::= (#x20 | #x9 | #xD | #xA)
        checker = self.get_func_by_name(t)
        for v in split(value):
            if not checker(v):
                return False
        return True

    def is_four_numbers(self, value):
        def split(value):
            if is_string(value):
                values = iterflatlist( (v.strip().split(' ') for v in value.split(',')) )
                return (v for v in values if v)
            else:
                return iterflatlist(value)

        values = list(split(value))
        if len(values) != 4:
            return False
        checker = self.get_func_by_name('number')
        for v in values:
            if not checker(v):
                return False
        return True

    def is_semicolon_list(self, value):
        #a semicolon-separated list of values
        #               | value comma-wsp list-of-values
        #comma-wsp  ::= (wsp+ ";" wsp*) | ("," wsp*)
        #wsp        ::= (#x20 | #x9 | #xD | #xA)
        return self.is_list_of_T(value.replace(';', ' '), 'number')

    def is_name(self, value):
        #name  ::= [^,()#x20#x9#xD#xA] /* any char except ",", "(", ")" or wsp */
        chars = frozenset(str(value).strip())
        if not chars or INVALID_NAME_CHARS.intersection(chars):
            return False
        else:
            return True

    def is_number(self, value):
        try:
            number = float(value)
            return True
        except:
            return False

    def is_number_optional_number(self, value):
        #number-optional-number ::= number
        #                           | number comma-wsp number
        if is_string(value):
            values = re.split(' *,? *', value.strip())
            if 0 < len(values) < 3: # 1 or 2 numbers
                for v in values:
                    if not self.is_number(v):
                        return False
                return True
        else:
            try: # is it a 2-tuple
                n1, n2 = value
                if self.is_number(n1) and \
                   self.is_number(n2):
                    return True
            except TypeError: # just one value
                return self.is_number(value)
            except ValueError: # more than 2 values
                pass
        return False

    def is_paint(self, value):
        #paint ::=	"none" |
        #           "currentColor" |
        #           <color> [<icccolor>] |
        #           <funciri> [ "none" | "currentColor" | <color> [<icccolor>] |
        #           "inherit"
        def split_values(value):
            try:
                funcIRI, value = value.split(")", 1)
                values = [funcIRI+")"]
                values.extend(split_values(value))
                return values
            except ValueError:
                return value.split()

        values = split_values(str(value).strip())
        for value in [v.strip() for v in values]:
            if value in ('none', 'currentColor', 'inherit'):
                continue
            elif self.is_color(value):
                continue
            elif self.is_icccolor(value):
                continue
            elif self.is_FuncIRI(value):
                continue
            return False
        return True

    def is_percentage(self, value):
        #percentage ::= number "%"
        if self.is_number(value):
            return True
        elif is_string(value):
            return pattern.percentage.match(value.strip()) is not None
        return False

    def is_time(self, value):
        #time ::= <number> (~"ms" | ~"s")?
        if self.is_number(value):
            return True
        elif is_string(value):
            return pattern.time.match(value.strip()) is not None
        return False

    def is_transform_list(self, value):
        if is_string(value):
            return is_valid_transferlist(value)
        else:
            return False

    def is_path_data(self, value):
        if is_string(value):
            return is_valid_pathdata(value)
        else:
            return False

    def is_XML_Name(self, value):
        # http://www.w3.org/TR/2006/REC-xml-20060816/#NT-Name
        # Nmtoken
        return bool(NMTOKEN_PATTERN.match(str(value).strip()))


    def is_shape(self, value):
        #shape ::= (<top> <right> <bottom> <left>)
        # where <top>, <bottom> <right>, and <left> specify offsets from the
        # respective sides of the box.
        # <top>, <right>, <bottom>, and <left> are <length> values
        # i.e. 'rect(5px, 10px, 10px, 5px)'
        res = SHAPE_PATTERN.match(value.strip())
        if res:
            for arg in res.groups():
                if arg.strip() == 'auto':
                    continue
                if not self.is_length(arg):
                    return False
        else:
            return False
        return True

    def is_timing_value_list(self, value):
        if is_string(value):
            return is_valid_animation_timing(value)
        else:
            return False

    def get_func_by_name(self, funcname):
        return getattr(self,
                       'is_'+funcname.replace('-', '_'),
                       self.is_anything)

    def check(self, typename, value):
        if typename.startswith('list-of-'):
            t = typename[8:]
            return self.is_list_of_T(value, t)
        return self.get_func_by_name(typename)(value)

FOCUS_CONST = frozenset(['nav-next', 'nav-prev', 'nav-up', 'nav-down', 'nav-left',
                         'nav-right', 'nav-up-left', 'nav-up-right', 'nav-down-left',
                         'nav-down-right'])


class Tiny12TypeChecker(Full11TypeChecker):
    def get_version(self):
        return '1.2', 'tiny'

    def is_boolean(self, value):
        if isinstance(value, bool):
            return True
        if is_string(value):
            return value.strip().lower() in ('true', 'false')
        return False

    def is_number(self, value):
        try:
            number = float(value)
            if -32767.9999 <= number <= 32767.9999:
                return True
            else:
                return False
        except:
            return False

    def is_focus(self, value):
        return str(value).strip() in FOCUS_CONST