python-2.5.2/win32/Lib/multifile.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """A readline()-style interface to the parts of a multipart message.
       
     2 
       
     3 The MultiFile class makes each part of a multipart message "feel" like
       
     4 an ordinary file, as long as you use fp.readline().  Allows recursive
       
     5 use, for nested multipart messages.  Probably best used together
       
     6 with module mimetools.
       
     7 
       
     8 Suggested use:
       
     9 
       
    10 real_fp = open(...)
       
    11 fp = MultiFile(real_fp)
       
    12 
       
    13 "read some lines from fp"
       
    14 fp.push(separator)
       
    15 while 1:
       
    16         "read lines from fp until it returns an empty string" (A)
       
    17         if not fp.next(): break
       
    18 fp.pop()
       
    19 "read remaining lines from fp until it returns an empty string"
       
    20 
       
    21 The latter sequence may be used recursively at (A).
       
    22 It is also allowed to use multiple push()...pop() sequences.
       
    23 
       
    24 If seekable is given as 0, the class code will not do the bookkeeping
       
    25 it normally attempts in order to make seeks relative to the beginning of the
       
    26 current file part.  This may be useful when using MultiFile with a non-
       
    27 seekable stream object.
       
    28 """
       
    29 
       
    30 __all__ = ["MultiFile","Error"]
       
    31 
       
    32 class Error(Exception):
       
    33     pass
       
    34 
       
    35 class MultiFile:
       
    36 
       
    37     seekable = 0
       
    38 
       
    39     def __init__(self, fp, seekable=1):
       
    40         self.fp = fp
       
    41         self.stack = []
       
    42         self.level = 0
       
    43         self.last = 0
       
    44         if seekable:
       
    45             self.seekable = 1
       
    46             self.start = self.fp.tell()
       
    47             self.posstack = []
       
    48 
       
    49     def tell(self):
       
    50         if self.level > 0:
       
    51             return self.lastpos
       
    52         return self.fp.tell() - self.start
       
    53 
       
    54     def seek(self, pos, whence=0):
       
    55         here = self.tell()
       
    56         if whence:
       
    57             if whence == 1:
       
    58                 pos = pos + here
       
    59             elif whence == 2:
       
    60                 if self.level > 0:
       
    61                     pos = pos + self.lastpos
       
    62                 else:
       
    63                     raise Error, "can't use whence=2 yet"
       
    64         if not 0 <= pos <= here or \
       
    65                         self.level > 0 and pos > self.lastpos:
       
    66             raise Error, 'bad MultiFile.seek() call'
       
    67         self.fp.seek(pos + self.start)
       
    68         self.level = 0
       
    69         self.last = 0
       
    70 
       
    71     def readline(self):
       
    72         if self.level > 0:
       
    73             return ''
       
    74         line = self.fp.readline()
       
    75         # Real EOF?
       
    76         if not line:
       
    77             self.level = len(self.stack)
       
    78             self.last = (self.level > 0)
       
    79             if self.last:
       
    80                 raise Error, 'sudden EOF in MultiFile.readline()'
       
    81             return ''
       
    82         assert self.level == 0
       
    83         # Fast check to see if this is just data
       
    84         if self.is_data(line):
       
    85             return line
       
    86         else:
       
    87             # Ignore trailing whitespace on marker lines
       
    88             marker = line.rstrip()
       
    89         # No?  OK, try to match a boundary.
       
    90         # Return the line (unstripped) if we don't.
       
    91         for i, sep in enumerate(reversed(self.stack)):
       
    92             if marker == self.section_divider(sep):
       
    93                 self.last = 0
       
    94                 break
       
    95             elif marker == self.end_marker(sep):
       
    96                 self.last = 1
       
    97                 break
       
    98         else:
       
    99             return line
       
   100         # We only get here if we see a section divider or EOM line
       
   101         if self.seekable:
       
   102             self.lastpos = self.tell() - len(line)
       
   103         self.level = i+1
       
   104         if self.level > 1:
       
   105             raise Error,'Missing endmarker in MultiFile.readline()'
       
   106         return ''
       
   107 
       
   108     def readlines(self):
       
   109         list = []
       
   110         while 1:
       
   111             line = self.readline()
       
   112             if not line: break
       
   113             list.append(line)
       
   114         return list
       
   115 
       
   116     def read(self): # Note: no size argument -- read until EOF only!
       
   117         return ''.join(self.readlines())
       
   118 
       
   119     def next(self):
       
   120         while self.readline(): pass
       
   121         if self.level > 1 or self.last:
       
   122             return 0
       
   123         self.level = 0
       
   124         self.last = 0
       
   125         if self.seekable:
       
   126             self.start = self.fp.tell()
       
   127         return 1
       
   128 
       
   129     def push(self, sep):
       
   130         if self.level > 0:
       
   131             raise Error, 'bad MultiFile.push() call'
       
   132         self.stack.append(sep)
       
   133         if self.seekable:
       
   134             self.posstack.append(self.start)
       
   135             self.start = self.fp.tell()
       
   136 
       
   137     def pop(self):
       
   138         if self.stack == []:
       
   139             raise Error, 'bad MultiFile.pop() call'
       
   140         if self.level <= 1:
       
   141             self.last = 0
       
   142         else:
       
   143             abslastpos = self.lastpos + self.start
       
   144         self.level = max(0, self.level - 1)
       
   145         self.stack.pop()
       
   146         if self.seekable:
       
   147             self.start = self.posstack.pop()
       
   148             if self.level > 0:
       
   149                 self.lastpos = abslastpos - self.start
       
   150 
       
   151     def is_data(self, line):
       
   152         return line[:2] != '--'
       
   153 
       
   154     def section_divider(self, str):
       
   155         return "--" + str
       
   156 
       
   157     def end_marker(self, str):
       
   158         return "--" + str + "--"