castleraider
changeset 315:74ace2757d84
Added a module to help with creating disk images.
| author | David Boddie <david@boddie.org.uk> |
|---|---|
| date | Sat Aug 09 18:27:13 2014 +0200 |
| parents | 7f95ec7aca72 |
| children | 2fcaa1b4c711 |
| files | tools/diskutils.py |
| diffstat | 1 files changed, 222 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/diskutils.py Sat Aug 09 18:27:13 2014 +0200 1.3 @@ -0,0 +1,222 @@ 1.4 +""" 1.5 +Copyright (C) 2014 David Boddie <david@boddie.org.uk> 1.6 + 1.7 +This program is free software: you can redistribute it and/or modify 1.8 +it under the terms of the GNU General Public License as published by 1.9 +the Free Software Foundation, either version 3 of the License, or 1.10 +(at your option) any later version. 1.11 + 1.12 +This program is distributed in the hope that it will be useful, 1.13 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.15 +GNU General Public License for more details. 1.16 + 1.17 +You should have received a copy of the GNU General Public License 1.18 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.19 +""" 1.20 + 1.21 +import struct, time 1.22 + 1.23 +# Find the number of centiseconds between 1900 and 1970. 1.24 +between_epochs = ((365 * 70) + 17) * 24 * 360000L 1.25 + 1.26 +class DiskError(Exception): 1.27 + pass 1.28 + 1.29 + 1.30 +class Utilities: 1.31 + 1.32 + # Little endian reading 1.33 + 1.34 + def _read_signed_word(self, s): 1.35 + 1.36 + return struct.unpack("<i", s)[0] 1.37 + 1.38 + def _read_unsigned_word(self, s): 1.39 + 1.40 + return struct.unpack("<I", s)[0] 1.41 + 1.42 + def _read_signed_byte(self, s): 1.43 + 1.44 + return struct.unpack("<b", s)[0] 1.45 + 1.46 + def _read_unsigned_byte(self, s): 1.47 + 1.48 + return struct.unpack("<B", s)[0] 1.49 + 1.50 + def _read_unsigned_half_word(self, s): 1.51 + 1.52 + return struct.unpack("<H", s)[0] 1.53 + 1.54 + def _read_signed_half_word(self, s): 1.55 + 1.56 + return struct.unpack("<h", s)[0] 1.57 + 1.58 + def _read(self, offset, length = 1): 1.59 + 1.60 + self.file.seek(offset, 0) 1.61 + return self.file.read(length) 1.62 + 1.63 + def _write_unsigned_word(self, v): 1.64 + 1.65 + return struct.pack("<I", v) 1.66 + 1.67 + def _write_unsigned_half_word(self, v): 1.68 + 1.69 + return struct.pack("<H", v) 1.70 + 1.71 + def _write_unsigned_byte(self, v): 1.72 + 1.73 + return struct.pack("<B", v) 1.74 + 1.75 + def _write(self, offset, data): 1.76 + 1.77 + self.file.seek(offset, 0) 1.78 + self.file.write(data) 1.79 + 1.80 + def _str2num(self, s): 1.81 + 1.82 + i = 0 1.83 + n = 0 1.84 + while i < len(s): 1.85 + 1.86 + n = n | (ord(s[i]) << (i*8)) 1.87 + i = i + 1 1.88 + 1.89 + return n 1.90 + 1.91 + def _num2str(self, size, n): 1.92 + 1.93 + i = 0 1.94 + s = "" 1.95 + while i < size: 1.96 + 1.97 + s += chr(n & 0xff) 1.98 + n = n >> 8 1.99 + i += 1 1.100 + 1.101 + return s 1.102 + 1.103 + def _binary(self, size, n): 1.104 + 1.105 + new = "" 1.106 + while (n != 0) & (size > 0): 1.107 + 1.108 + if (n & 1)==1: 1.109 + new = "1" + new 1.110 + else: 1.111 + new = "0" + new 1.112 + 1.113 + n = n >> 1 1.114 + size = size - 1 1.115 + 1.116 + if size > 0: 1.117 + new = ("0"*size) + new 1.118 + 1.119 + return new 1.120 + 1.121 + def _safe(self, s, with_space = 0): 1.122 + 1.123 + new = "" 1.124 + if with_space == 1: 1.125 + lower = 31 1.126 + else: 1.127 + lower = 32 1.128 + 1.129 + for c in s: 1.130 + 1.131 + if ord(c) >= 128: 1.132 + i = ord(c) ^ 128 1.133 + c = chr(i) 1.134 + 1.135 + if ord(c) <= lower: 1.136 + break 1.137 + 1.138 + new = new + c 1.139 + 1.140 + return new 1.141 + 1.142 + def _pad(self, s, length, ch): 1.143 + 1.144 + s = s[:length] 1.145 + if len(s) < length: 1.146 + s += (length - len(s)) * ch 1.147 + 1.148 + return s 1.149 + 1.150 + 1.151 +class Directory: 1.152 + 1.153 + """directory = Directory(name, address) 1.154 + 1.155 + The directory created contains name and files attributes containing the 1.156 + directory name and the objects it contains. 1.157 + """ 1.158 + 1.159 + def __init__(self, name, files): 1.160 + 1.161 + self.name = name 1.162 + self.files = files 1.163 + 1.164 + def __repr__(self): 1.165 + 1.166 + return '<%s instance, "%s", at %x>' % (self.__class__, self.name, id(self)) 1.167 + 1.168 + 1.169 +class File: 1.170 + 1.171 + """file = File(name, data, load_address, execution_address, length) 1.172 + """ 1.173 + 1.174 + def __init__(self, name, data, load_address, execution_address, length, 1.175 + locked = False, disk_address = 0): 1.176 + 1.177 + self.name = name 1.178 + self.data = data 1.179 + self.load_address = load_address 1.180 + self.execution_address = execution_address 1.181 + self.length = length 1.182 + self.locked = locked 1.183 + self.disk_address = disk_address 1.184 + 1.185 + def __repr__(self): 1.186 + 1.187 + return '<%s instance, "%s", at %x>' % (self.__class__, self.name, id(self)) 1.188 + 1.189 + def has_filetype(self): 1.190 + 1.191 + """Returns True if the file's meta-data contains filetype information.""" 1.192 + return self.load_address & 0xfff00000 == 0xfff00000 1.193 + 1.194 + def filetype(self): 1.195 + 1.196 + """Returns the meta-data containing the filetype information. 1.197 + 1.198 + Note that a filetype can be obtained for all files, though it may not 1.199 + necessarily be valid. Use has_filetype() to determine whether the file 1.200 + is likely to have a valid filetype.""" 1.201 + 1.202 + return "%03x" % ((self.load_address >> 8) & 0xfff) 1.203 + 1.204 + def time_stamp(self): 1.205 + 1.206 + """Returns the time stamp for the file as a tuple of values containing 1.207 + the local time, or an empty tuple if the file does not have a time stamp.""" 1.208 + 1.209 + # RISC OS time is given as a five byte block containing the 1.210 + # number of centiseconds since 1900 (presumably 1st January 1900). 1.211 + 1.212 + # Convert the time to the time elapsed since the Epoch (assuming 1.213 + # 1970 for this value). 1.214 + date_num = struct.unpack("<Q", 1.215 + struct.pack("<IBxxx", self.execution_address, self.load_address & 0xff))[0] 1.216 + 1.217 + centiseconds = date_num - between_epochs 1.218 + 1.219 + # Convert this to a value in seconds and return a time tuple. 1.220 + try: 1.221 + return time.localtime(centiseconds / 100.0) 1.222 + except ValueError: 1.223 + return () 1.224 + 1.225 +
