Home | Trees | Indices | Help |
|
---|
|
1 """ 2 :mod:`pyffi.formats.rockstar.dir_` --- DIR (.dir) 3 ================================================= 4 5 A .dir file simply contains a list of files. 6 7 Implementation 8 -------------- 9 10 .. autoclass:: DirFormat 11 :show-inheritance: 12 :members: 13 14 Regression tests 15 ---------------- 16 17 Read a DIR file 18 ^^^^^^^^^^^^^^^ 19 20 >>> # check and read dir file 21 >>> stream = open('tests/rockstar/dir/test.dir', 'rb') 22 >>> data = DirFormat.Data() 23 >>> data.inspect(stream) 24 >>> # do some stuff with header? 25 >>> # XXX nothing for now 26 >>> # read directory 27 >>> data.read(stream) 28 >>> len(data.files) 29 2 30 >>> data.files[0].offset 31 0 32 >>> data.files[0].size 33 1 34 >>> data.files[0].name 35 'hello.txt' 36 37 Parse all DIR files in a directory tree 38 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 39 40 >>> for stream, data in DirFormat.walkData('tests/rockstar/dir'): 41 ... print(stream.name) 42 tests/rockstar/dir/test.dir 43 44 Create an DIR file from scratch and write to file 45 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 46 47 >>> data = DirFormat.Data() 48 >>> from tempfile import TemporaryFile 49 >>> stream = TemporaryFile() 50 >>> data.write(stream) 51 """ 52 53 # ***** BEGIN LICENSE BLOCK ***** 54 # 55 # Copyright (c) 2007-2011, Python File Format Interface 56 # All rights reserved. 57 # 58 # Redisdirbution and use in source and binary forms, with or without 59 # modification, are permitted provided that the following conditions 60 # are met: 61 # 62 # * Redisdirbutions of source code must retain the above copyright 63 # notice, this list of conditions and the following disclaimer. 64 # 65 # * Redisdirbutions in binary form must reproduce the above 66 # copyright notice, this list of conditions and the following 67 # disclaimer in the documentation and/or other materials provided 68 # with the disdirbution. 69 # 70 # * Neither the name of the Python File Format Interface 71 # project nor the names of its condirbutors may be used to endorse 72 # or promote products derived from this software without specific 73 # prior written permission. 74 # 75 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONDIRBUTORS 76 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 77 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 78 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 79 # COPYRIGHT OWNER OR CONDIRBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 80 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 81 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 82 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 83 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, SDIRCT 84 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 85 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 86 # POSSIBILITY OF SUCH DAMAGE. 87 # 88 # ***** END LICENSE BLOCK ***** 89 90 from itertools import chain, izip 91 import struct 92 import os 93 import re 94 95 import pyffi.object_models.xml 96 import pyffi.object_models.common 97 from pyffi.object_models.xml.basic import BasicBase 98 import pyffi.object_models 99 from pyffi.utils.graph import EdgeFilter 100102 """This class implements the DIR format.""" 103 xml_file_name = 'dir.xml' 104 # where to look for dir.xml 105 xml_file_path = [os.path.dirname(__file__)] 106 # file name regular expression match 107 RE_FILENAME = re.compile(r'^.*\.dir$', re.IGNORECASE) 108 109 # basic types 110 UInt = pyffi.object_models.common.UInt229 230 if __name__=='__main__': 231 import doctest 232 doctest.testmod() 233112 _len = 24113115 """A class to contain the actual dir data.""" 116118 """Initialize empty file list, or take list of files from 119 a folder. 120 """ 121 self.files = [] 122 offset = 0 123 if folder: 124 for filename in sorted(os.listdir(folder)): 125 if not os.path.isfile(os.path.join(folder, filename)): 126 continue 127 fileinfo = os.stat(os.path.join(folder, filename)) 128 file_record = DirFormat.File() 129 file_record.offset = offset 130 file_record.size = (fileinfo.st_size + 2047) // 2048 131 file_record.name = filename 132 self.files.append(file_record) 133 offset += file_record.size134136 """Quickly checks if stream contains DIR data, by looking at 137 the first 36 bytes. 138 139 :param stream: The stream to inspect. 140 :type stream: file 141 """ 142 pos = stream.tell() 143 try: 144 off1, size1, file1 = struct.unpack( 145 "<II24s", stream.read(32)) 146 try: 147 off2, = struct.unpack( 148 "<I", stream.read(4)) 149 except struct.error: 150 # this happens if .dir only contains one file record 151 off2 = size1 152 if not(off1 == 0 153 #and size1 < 1000 # heuristic 154 and off2 == size1 155 and file1[-1] == '\x00'): 156 raise ValueError('Not a Rockstar DIR file.') 157 finally: 158 stream.seek(pos)159 160 # overriding pyffi.object_models.FileFormat.Data methods 161163 """Quickly checks if stream contains DIR data. 164 165 :param stream: The stream to inspect. 166 :type stream: file 167 """ 168 pos = stream.tell() 169 try: 170 self.inspect_quick(stream) 171 finally: 172 stream.seek(pos)173 174176 """Read a dir file. 177 178 :param stream: The stream from which to read. 179 :type stream: ``file`` 180 """ 181 self.inspect_quick(stream) 182 self.files = [] 183 pos = stream.tell() 184 while stream.read(1): 185 stream.seek(pos) 186 file_record = DirFormat.File() 187 file_record.read(stream, self) 188 self.files.append(file_record) 189 pos = stream.tell()190192 """Write a dir file. 193 194 :param stream: The stream to which to write. 195 :type stream: ``file`` 196 """ 197 for file_record in self.files: 198 file_record.write(stream, self)199 200 # GlobalNode 201203 return self.files204206 """Unpack all files, whose data resides in the given 207 image, into the given folder. 208 """ 209 for file_record in self.files: 210 image.seek(file_record.offset * 2048) 211 with open(os.path.join(folder, file_record.name), 'wb') as data: 212 data.write(image.read(file_record.size * 2048))213215 """Pack all files, whose data resides in the given folder, 216 into the given image. 217 """ 218 for file_record in self.files: 219 if image.tell() != file_record.offset * 2048: 220 raise ValueError('file offset mismatch') 221 with open(os.path.join(folder, file_record.name), 'rb') as data: 222 allbytes = data.read() 223 size = file_record.size * 2048 224 if len(allbytes) > size: 225 raise ValueError('file larger than record size') 226 image.write(allbytes) 227 if len(allbytes) < size: 228 image.write('\x00' * (size - len(allbytes)))
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Mon Oct 10 19:04:05 2011 | http://epydoc.sourceforge.net |