This file is indexed.

/usr/share/pyshared/musiclibrarian/serialize.py is in musiclibrarian 1.6-2.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
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# serialize.py - serialize a restricted set of Python data objects.
#
#   Copyright (C) 2003 Daniel Burrows <dburrows@debian.org>
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# The file format of ConfigParser is poorly specified and tends to be
# a lossy way to store Python values.  It's also rather unpleasant to
# put structured data in it.
#
# These routines read and write a well-defined file format which can
# losslessly represent a subset of Python objects (a plus over
# ConfigParser); they *only* handle a particular subset of Python
# objects, so they can be safely used on arbitrary input files (a plus
# over pickle -- sometimes there's such a thing as being TOO
# expressive!), and they are extensible: you can add your own object
# types and syntax.
#
# This is sort of an "s-expressions on steroids for Python".  It is
# distinguished from XML mainly in that the input files are meant to
# be read-write without the aid of a specialized editor.
#
# Note: if you pass in a file object generated by codecs.open(), the
#       underlying file will have the appropriate encoding (eg, utf8).

import re
import types

# Helpers:

# Skip leading whitespace on a seekable file, return the next
# non-whitespace character and the location immediately preceding it.
def skip_ws(f):
    loc=f.tell()
    c=f.read(1)
    while c.isspace():
        loc=f.tell()
        c=f.read(1)

    return loc,c

# A class which can read Python expressions from files.
#
# The method "read" returns the next Python expression in the file.
#
# This class recognizes the following syntax:
#
#   PEXP ::=  <integer>
#           | <float>
#           | None | True | False
#           | <string-with-escaping>
#           | \( (PEXP ,?)* \)
#           | [ (PEXP ,?)* ]
#           | { (PEXP : PEXP ,?)* }
#           | <identifier> \( PEXP ,?)* \)
#
# All tokens MUST be whitespace-separated.  The only exception: the
# delimiters of tuples, lists, and dictionaries are exempt from this
# requirement, as are commas.
#
# <string-with-escaping> is a string bracketed by single quotes (').
# Presently known escape sequences are \\, \', \b, and \n.  Unknown
# escape sequences are handled as in Python (the backslash is left
# in).
#
# The last case is what allows extension by plugging in a new parser.
# Currently no support is provided for cross-references, so graphs
# cannot be directly represented (but of course you can convert a
# graph to a sequence of tuples)
#
# The idea is to allow all non-executable (=safe) data types.  Of
# course, since the extensions can be general functions, the burden is
# on the extension writer to ensure their safety.
#
# A given Reader can apply to any file which supports
# seeking. (handling lookahead internally would allow this to
# generalize to any file)
#
# FIXME: handle more of the many types of integers that Python knows
# about. (mainly requires more tests when "starting" a number?)
#
# FIXME: This is dreadfully inefficient.  Could regexes be used?
#
# FIXME: Don't require a seekable file.  I only need one character of
#        lookahead, so this shouldn't be too hard. (OTOH, how often is
#        seeking necessary and how expensive is it?)
class Reader:
    # Each extension is a function which takes a tuple of arguments
    # and returns a Python object.
    def __init__(self, extensions = {}):
        self.extensions=extensions

    # Read one Python expression from the given file.
    def read(self, file):
        # Get the first character.
        loc,c=skip_ws(file)

        # Dispatch.
        if c == '':
            raise IOError, 'Unexpected end of file'
        elif (c >= '0' and c <='9') or c=='-' or c == '.':
            file.seek(loc)
            return self.__read_number(file)
        elif c == '\'':
            return self.__read_string_tail(file)
        elif c == '(':
            return self.__read_tuple_tail(file)
        elif c == '[':
            return self.__read_list_tail(file)
        elif c == '{':
            return self.__read_dict_tail(file)
        elif c.isalpha():
            file.seek(loc)
            return self.__read_extension_or_constant(file)
        else:
            raise IOError, 'Can\'t parse token starting with \'%s\''%c

    def __read_number(self, file):
        s=file.read(1)
        if s == '':
            raise IOError, 'Unexpected end of file'

        loc=file.tell()
        c=file.read(1)
        while not c.isspace() and not c in ['', '(','{','[',']','}',')',',']:
            s+=c
            loc=file.tell()
            c=file.read(1)

        file.seek(loc)

        # Make integers by default
        try:
            return int(s)
        except ValueError:
            try:
                return long(s)
            except ValueError:
                return float(s)

    def __read_string_tail(self, file):
        s=''

        c=file.read(1)
        while c <> '\'':
            if c == '\\':
                c=file.read(1)
                if c == '\\' or c == '\'':
                    s+=c
                elif c == 'n':
                    s+='\n'
                elif c == 'b':
                    s+='\b'
                else:
                    s+='\\'
                    s+=c
            elif c == '':
                raise IOError, 'EOF inside string'
            else:
                s+=c

            c=file.read(1)

        return s

    def __read_tuple_tail(self, file):
        loc,c=skip_ws(file)

        lst=[]

        while c <> ')':
            if c == '':
                raise IOError, 'EOF inside tuple'

            file.seek(loc)
            lst.append(self.read(file))
            loc,c=skip_ws(file)
            if c == ',':
                loc,c=skip_ws(file)

        return tuple(lst)

    def __read_list_tail(self, file):
        loc,c=skip_ws(file)

        lst=[]

        while c <> ']':
            if c == '':
                raise IOError, 'EOF inside list'

            file.seek(loc)
            lst.append(self.read(file))
            loc,c=skip_ws(file)
            if c == ',':
                loc,c=skip_ws(file)

        return lst

    def __read_dict_tail(self, file):
        loc,c=skip_ws(file)

        dict={}

        while c <> '}':
            if c == '':
                raise IOError, 'EOF inside dictionary'

            file.seek(loc)
            key=self.read(file)

            loc,c=skip_ws(file)
            if c <> ':':
                raise IOError, 'Parse error: expected \':\''

            val=self.read(file)
            dict[key]=val
            loc,c=skip_ws(file)
            if c == ',':
                loc,c=skip_ws(file)

        return dict

    def __read_extension_or_constant(self, file):
        # Get the identifier:
        name=''

        loc=file.tell()
        c=file.read(1)
        # Assume that the first character was already found to be
        # alphabetic.
        while c.isalnum():
            name+=c
            loc=file.tell()
            c=file.read(1)

        if name == 'None':
            return None
        elif name == 'True':
            return True
        elif name == 'False':
            return False
        elif not self.extensions.has_key(name):
            raise IOError, 'Parse error: "%s" is not a function'%name

        if c.isspace():
            loc,c=skip_ws(file)

        if c <> '(':
            raise IOError, 'Expected \'(\' after call of function "%s"'%name

        args=self.__read_tuple_tail(file)
        return apply(self.extensions[name], args)

# Converse to the above.
#
# Extensions are supported only under the condition that there is a
# simple test for their applicability.
class Writer:
    # Each extension is a tuple (applies, name, writer): applies takes a
    # Python object and returns a boolean value; if it returns True,
    # the writer is called with a single argument (obj); it should return
    # a tuple indicating the "arguments" to the extension.
    def __init__(self, extensions=[]):
        self.extensions=extensions

    # convenience for debugging
    def writeln(self, file, obj, indent=0):
        self.write(file, obj, indent)
        file.write('\n')

    def write(self, file, obj, indent=0):
        t=type(obj)

        if obj == None:
            file.write('None')
        elif obj == True:
            file.write('True')
        elif obj == False:
            file.write('False')
        elif isinstance(obj, basestring):
            self.__write_string(file, obj)
        elif t == types.IntType or t == types.LongType or t == types.FloatType:
            file.write(`obj`)
        elif t == types.ListType:
            self.__write_list(file, obj, indent)
        elif t == types.TupleType:
            self.__write_tuple(file, obj, indent)
        elif t == types.DictType:
            self.__write_dict(file, obj, indent)
        else:
            for test, name, writer in self.extensions:
                if test(obj):
                    output=writer(obj)

                    if type(output) <> types.TupleType:
                        raise IOError,'Extension tried to write a non-tuple: %s'%obj
                    file.write(name)

                    self.__write_tuple(file, output, indent+len(name))
                    return
            raise IOError,'I don\'t know how to serialize %s'%`obj`

    # What to escape
    __escapere=re.compile('([\\\\\'\n\b])')

    def __write_string(self, file, obj):
        def doescape(g):
            c=g.group(0)
            if c == '\\' or c == '\'':
                return '\\'+c
            elif c == '\n':
                return '\\n'
            elif c == '\b':
                return '\\b'
            else:
                raise IOError, 'No inverse to escape %s'%c

        file.write('\'')
        file.write(re.sub(Writer.__escapere, doescape, obj))
        file.write('\'')

    # Very aggressive about linewrapping here: perhaps I should buffer
    # things instead?
    def __write_seq(self, file, obj, indent, start, end):
        file.write(start)
        first=True
        for x in obj:
            if not first:
                file.write(',\n'+(' '*(indent+1)))
            else:
                first=False
            self.write(file, x, indent+1)
        file.write(end)

    def __write_list(self, file, obj, indent):
        self.__write_seq(file, obj, indent, '[', ']')

    def __write_tuple(self, file, obj, indent):
        self.__write_seq(file, obj, indent, '(', ',)')

    def __write_dict(self, file, obj, indent):
        file.write('{')
        items=obj.items()
        # Sort the items, to make the dictionary 'nicer'
        items.sort(lambda a,b:cmp(a[0], b[0]))
        first=True

        for key,val in items:
            if not first:
                file.write(',\n'+(' '*(indent+1)))
            else:
                first=False
            self.write(file, key, indent+1)
            file.write('\n'+ (' '*(indent+5))+': ')
            self.write(file, val, indent+7)

        file.write('}')