| 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
100
102 """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.UInt
112 _len = 24
113
115 """A class to contain the actual dir data."""
116
118 """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.size
134
136 """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
161
163 """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
174
176 """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()
190
192 """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
201
203 return self.files
204
206 """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))
213
215 """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)))
229
230 if __name__=='__main__':
231 import doctest
232 doctest.testmod()
233
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Oct 10 19:04:05 2011 | http://epydoc.sourceforge.net |