python-adfs
changeset 50:86844fe8700b
Made corrections to the ADFS E format map reading mechanisms thanks to
information provided by John Kortink. The read_new_map function has now
been reinstated and the find_in_new_map function is now just a wrapper for
the disc_map dictionary of file pieces.
| author | David Boddie <david@boddie.org.uk> |
|---|---|
| date | Sat Jul 19 18:30:56 2003 +0200 |
| parents | 8fe9de493130 |
| children | a8eead849e21 |
| files | ADFSlib.py |
| diffstat | 1 files changed, 223 insertions(+), 193 deletions(-) [+] |
line diff
1.1 --- a/ADFSlib.py Thu Jul 03 01:05:49 2003 +0200 1.2 +++ b/ADFSlib.py Sat Jul 19 18:30:56 2003 +0200 1.3 @@ -220,6 +220,7 @@ 1.4 # LinkBits 1.5 # BitSize (size of ID field?) 1.6 bit_size = self.str2num(1, self.sectors[offset + 6 : offset + 7]) 1.7 + #print "Bit size: %s" % hex(bit_size) 1.8 # RASkew 1.9 # BootOpt 1.10 # Zones 1.11 @@ -246,125 +247,240 @@ 1.12 1.13 checksum = ord(self.sectors[0]) 1.14 first_free = self.str2num(2, self.sectors[1:3]) 1.15 - 1.16 + 1.17 if self.disc_type == 'adE': 1.18 - 1.19 + 1.20 self.record = self.read_disc_record(4) 1.21 + self.map_header = 0 1.22 self.map_start, self.map_end = 0x40, 0x400 1.23 - #map = self.read_new_map(map_start, map_end) 1.24 - #map = self.scan_new_map(self.map_start, self.map_end) 1.25 + self.free_space = self.read_free_space( 1.26 + self.map_header, self.map_start, self.map_end 1.27 + ) 1.28 + self.disc_map = self.read_new_map( 1.29 + self.map_header, self.map_start, self.map_end 1.30 + ) 1.31 1.32 return self.record['disc name'] #, map 1.33 - 1.34 + 1.35 if self.disc_type == 'adEbig': 1.36 1.37 self.record = self.read_disc_record(0xc6804) 1.38 + self.map_header = 0xc6800 1.39 self.map_start, self.map_end = 0xc6840, 0xc7800 1.40 - #map = self.read_new_map(map_start, map_end) 1.41 - #map = self.scan_new_map(self.map_start, self.map_end) 1.42 - 1.43 + self.free_space = self.read_free_space( 1.44 + self.map_header, self.map_start, self.map_end 1.45 + ) 1.46 + self.disc_map = self.read_new_map( 1.47 + self.map_header, self.map_start, self.map_end 1.48 + ) 1.49 + 1.50 return self.record['disc name'] #, map 1.51 - 1.52 + 1.53 else: 1.54 return 'Unknown' 1.55 1.56 # zone_size = 819200 / record['zones'] 1.57 # ids_per_zone = zone_size / 1.58 1.59 - def read_new_map(self, begin, end): 1.60 + def read_new_map(self, header, begin, end): 1.61 1.62 - map = {} 1.63 + disc_map = {} 1.64 1.65 a = begin 1.66 1.67 - current = None 1.68 + current_piece = None 1.69 + current_start = 0 1.70 + 1.71 + next_zone = header + self.sector_size 1.72 + 1.73 + # Copy the free space map. 1.74 + free_space = self.free_space[:] 1.75 1.76 while a < end: 1.77 1.78 - entry = self.str2num(2, self.sectors[a:a+2]) 1.79 - 1.80 # The next entry to be read will occur one byte after this one 1.81 # unless one of the following checks override this behaviour. 1.82 next = a + 1 1.83 1.84 - # Entry must be above 1 (defect) 1.85 - if current is None: 1.86 + if (a % self.sector_size) < 4: 1.87 1.88 - if (entry & 0x00ff) > 1 and (entry & 0x00ff) != 0xff: 1.89 + # In a zone header. 1.90 + next = a + 4 - (a % self.sector_size) 1.91 1.92 + # Set the next zone offset. 1.93 + next_zone = next_zone + self.sector_size 1.94 + 1.95 + elif free_space != [] and a >= free_space[0][0]: 1.96 + 1.97 + # In the next free space entry. Go to the entry following 1.98 + # it and discard this free space entry. 1.99 + next = free_space[0][1] 1.100 + 1.101 + free_space.pop(0) 1.102 + 1.103 + elif current_piece is None and (next_zone - a) >= 2: 1.104 + 1.105 + value = self.str2num(2, self.sectors[a:a+2]) 1.106 + 1.107 + entry = value & 0x7fff 1.108 + 1.109 + # See ADFS/EAddrs.htm document for restriction on 1.110 + # the disc address and hence the file number. 1.111 + # i.e.the top bit of the file number cannot be set. 1.112 + 1.113 + # Entry must be above 1 (defect) 1.114 + if entry > 1: 1.115 + 1.116 + next = a + 2 1.117 + 1.118 # Define a new entry. 1.119 - current = entry & 0x7fff 1.120 - #print "Begin:", hex(current), hex(a) 1.121 + #print "Begin:", hex(entry), hex(a) 1.122 1.123 - if not map.has_key(current): 1.124 + if not disc_map.has_key(entry): 1.125 1.126 - map[current] = [] 1.127 + disc_map[entry] = [] 1.128 1.129 - if self.disc_type == 'adE': 1.130 + # For the relevant entry, add the block to the list 1.131 + # of pieces found and implicitly finish reading this 1.132 + # fragment. 1.133 1.134 - address = ((a - begin) * self.sector_size) 1.135 + disc_map[entry].append( 1.136 + [ self.find_address_from_map(a, begin, entry), 1.137 + self.find_address_from_map(next, begin, entry) 1.138 + ] ) 1.139 1.140 - elif self.disc_type == 'adEbig': 1.141 + if (value & 0x8000) == 0: 1.142 1.143 - upper = (entry & 0x7f00) >> 8 1.144 - 1.145 - if upper > 1: 1.146 - upper = upper - 1 1.147 - if upper > 3: 1.148 - upper = 3 1.149 - 1.150 - address = ((a - begin) - (upper * 0xc8)) * 0x200 1.151 + # Record the file number and start of this fragment. 1.152 + current_piece = entry 1.153 + current_start = a 1.154 + 1.155 + else: 1.156 + 1.157 + # Search for a valid file number. 1.158 + next = a + 1 1.159 + 1.160 + else: 1.161 + 1.162 + # In a piece being read. 1.163 + 1.164 + value = ord(self.sectors[a]) 1.165 + 1.166 + if value == 0: 1.167 + 1.168 + # Still in the block. 1.169 + next = a + 1 1.170 + 1.171 + elif value == 0x80: 1.172 + 1.173 + # At the end of the block. 1.174 + next = a + 1 1.175 1.176 - # Add a list containing the start address of the 1.177 - # file/directory to the list of objects associated 1.178 - # with this file number. 1.179 - map[current].append( [address] ) 1.180 + # For relevant entries add the block to the list of 1.181 + # pieces found. 1.182 + disc_map[current_piece].append( 1.183 + [ self.find_address_from_map( 1.184 + current_start, begin, current_piece 1.185 + ), 1.186 + self.find_address_from_map( 1.187 + next, begin, current_piece 1.188 + ) 1.189 + ] ) 1.190 + 1.191 + current_piece = None 1.192 1.193 - next = a + 1 1.194 + else: 1.195 + 1.196 + # The byte found was unexpected - backtrack to the 1.197 + # byte after the start of this block and try again. 1.198 + print "Backtrack from %s to %s" % (hex(a), hex(current_start+1)) 1.199 + 1.200 + next = current_start + 1 1.201 + current_piece = None 1.202 1.203 - if (entry & 0x8000) != 0: 1.204 - 1.205 - if current is not None: 1.206 - 1.207 - if self.disc_type == 'adE': 1.208 - 1.209 - address = ((a + 2 - begin) * self.sector_size) 1.210 - 1.211 - elif self.disc_type == 'adEbig': 1.212 - 1.213 - upper = (entry & 0x7f00) >> 8 1.214 - 1.215 - if upper > 1: 1.216 - upper = upper - 1 1.217 - if upper > 3: 1.218 - upper = 3 1.219 - 1.220 - address = ((a + 2 - begin) - (upper * 0xc8)) * 0x200 1.221 - 1.222 - # This is the end of the current entry. Modify the latest 1.223 - # address to indicate a range of addresses. 1.224 - #print "End:", hex(current), hex(a) 1.225 - map[current][-1].append(address) 1.226 - 1.227 - # Unset the current file number. 1.228 - current = None 1.229 - 1.230 - next = a + 2 1.231 - 1.232 - # Move past the ending bit to an evenly aligned byte. 1.233 - #if next % 2 != 0: 1.234 - # 1.235 - # next = next + 1 1.236 - 1.237 + # Move to the next relevant byte. 1.238 a = next 1.239 1.240 - #for k, v in map.items(): 1.241 + #for k, v in disc_map.items(): 1.242 # 1.243 - # print hex(k), \ 1.244 - # __builtins__.map(lambda x: __builtins__.map(hex, x), v) 1.245 + # print hex(k), map(lambda x: map(hex, x), v) 1.246 1.247 - return map 1.248 + return disc_map 1.249 1.250 + def read_free_space(self, header, begin, end): 1.251 + 1.252 + free_space = [] 1.253 + 1.254 + a = header 1.255 + 1.256 + while a < end: 1.257 + 1.258 + # The next zone starts a sector after this one. 1.259 + next_zone = a + self.sector_size 1.260 + 1.261 + a = a + 1 1.262 + 1.263 + # Start by reading the offset in bits from the start of the header 1.264 + # of the first item of free space in the map. 1.265 + offset = self.str2num(2, self.sectors[a:a+2]) 1.266 + 1.267 + # The top bit is apparently always set, so mask it off and convert 1.268 + # the result into bytes. * Not sure if this is the case for 1.269 + # entries in the map. * 1.270 + next = ((offset & 0x7fff) >> 3) 1.271 + 1.272 + if next == 0: 1.273 + 1.274 + # No more free space in this zone. Look at the free 1.275 + # space field in the next zone. 1.276 + a = next_zone 1.277 + continue 1.278 + 1.279 + # Update the offset to point to the free space in this zone. 1.280 + a = a + next 1.281 + 1.282 + while a < next_zone: 1.283 + 1.284 + # Read the offset to the next free fragment in this zone. 1.285 + offset = self.str2num(2, self.sectors[a:a+2]) 1.286 + 1.287 + # Convert this to a byte offset. 1.288 + next = ((offset & 0x7fff) >> 3) 1.289 + 1.290 + # Find the end of the free space. 1.291 + b = a + 1 1.292 + 1.293 + while b < next_zone: 1.294 + 1.295 + c = b + 1 1.296 + 1.297 + value = self.str2num(1, self.sectors[b]) 1.298 + 1.299 + if (value & 0x80) != 0: 1.300 + 1.301 + break 1.302 + 1.303 + b = c 1.304 + 1.305 + # Record the offset into the map of this item of free space 1.306 + # and the offset of the byte after it ends. 1.307 + free_space.append( (a, c) ) 1.308 + 1.309 + if next == 0: 1.310 + 1.311 + break 1.312 + 1.313 + # Move to the next free space entry. 1.314 + a = a + next 1.315 + 1.316 + # Whether we are at the end of the zone or not, move to the 1.317 + # beginning of the next zone. 1.318 + a = next_zone 1.319 + 1.320 + #print map(lambda x: (hex(x[0]), hex(x[1])), free_space) 1.321 + 1.322 + # Return the free space list. 1.323 + return free_space 1.324 1.325 def find_address_from_map(self, addr, begin, entry): 1.326 1.327 @@ -385,108 +501,15 @@ 1.328 1.329 return address 1.330 1.331 - def find_in_new_map(self, begin, end, file_no): 1.332 + def find_in_new_map(self, file_no): 1.333 1.334 - #print "File number:", hex(file_no) 1.335 + try: 1.336 1.337 - if file_no < 2: 1.338 + return self.disc_map[file_no] 1.339 + 1.340 + except KeyError: 1.341 1.342 return [] 1.343 - 1.344 - a = begin 1.345 - 1.346 - # Create a list containing the start and end addresses of the 1.347 - # file/directory associated with this file number. 1.348 - pieces = [] 1.349 - 1.350 - current_piece = None 1.351 - current_start = 0 1.352 - 1.353 - while a < end: 1.354 - 1.355 - # The next entry to be read will occur one byte after this one 1.356 - # unless one of the following checks override this behaviour. 1.357 - next = a + 1 1.358 - 1.359 - if current_piece is None: 1.360 - 1.361 - value = self.str2num(2, self.sectors[a:a+2]) 1.362 - 1.363 - entry = value & 0x7fff 1.364 - 1.365 - if entry == file_no: 1.366 - 1.367 - next = a + 2 1.368 - 1.369 - if (value & 0x8000) == 0: 1.370 - 1.371 - current_piece = entry 1.372 - current_start = a 1.373 - 1.374 - else: 1.375 - 1.376 - # Add the block to the list of pieces found. 1.377 - pieces.append( 1.378 - [ self.find_address_from_map(a, begin, entry), 1.379 - self.find_address_from_map(next, begin, entry) 1.380 - ] ) 1.381 - 1.382 - else: 1.383 - 1.384 - # Search for a valid file number. 1.385 - next = a + 1 1.386 - 1.387 - else: 1.388 - 1.389 - # In a piece being read. 1.390 - 1.391 - value = ord(self.sectors[a]) 1.392 - 1.393 - if value == 0: 1.394 - 1.395 - # Still in the block. 1.396 - next = a + 1 1.397 - 1.398 - elif value == 0x80: 1.399 - 1.400 - # At the end of the block. 1.401 - next = a + 1 1.402 - 1.403 - # Add the block to the list of pieces found. 1.404 - pieces.append( 1.405 - [ self.find_address_from_map( 1.406 - current_start, begin, current_piece 1.407 - ), 1.408 - self.find_address_from_map( 1.409 - next, begin, current_piece 1.410 - ) 1.411 - ] ) 1.412 - 1.413 - current_piece = None 1.414 - 1.415 - else: 1.416 - 1.417 - # The byte found was unexpected - backtrack to the 1.418 - # byte after the start of this block and try again. 1.419 - next = current_start + 1 1.420 - current_piece = None 1.421 - 1.422 - a = next 1.423 - 1.424 - # If the last piece is incomplete then use the end of the map as 1.425 - # the end of the piece. 1.426 - if current_piece is not None: 1.427 - 1.428 - pieces.append( 1.429 - [ self.find_address_from_map( 1.430 - current_start, begin, current_piece 1.431 - ), 1.432 - self.find_address_from_map(end, begin, current_piece) 1.433 - ] ) 1.434 - 1.435 - #print "Pieces:", map(lambda x: map(hex, x), pieces) 1.436 - 1.437 - return pieces 1.438 1.439 def read_tracks(self, f, inter): 1.440 1.441 @@ -804,10 +827,12 @@ 1.442 file_no = value >> 8 1.443 1.444 #print "File number:", hex(file_no) 1.445 + #self.verify_log.append("File number: %s" % hex(file_no)) 1.446 1.447 # The pieces of the object are returned as a list of pairs of 1.448 # addresses. 1.449 - pieces = self.find_in_new_map(self.map_start, self.map_end, file_no) 1.450 + #pieces = self.find_in_new_map(self.map_start, self.map_end, file_no) 1.451 + pieces = self.find_in_new_map(file_no) 1.452 1.453 #print map(lambda x: map(hex, x), pieces) 1.454 1.455 @@ -839,11 +864,11 @@ 1.456 self.verify_log.append('Not a directory: %x' % head) 1.457 1.458 return '', [] 1.459 - 1.460 + 1.461 p = p + 5 1.462 - 1.463 + 1.464 files = [] 1.465 - 1.466 + 1.467 while ord(self.sectors[head+p]) != 0: 1.468 1.469 old_name = self.sectors[head+p:head+p+10] 1.470 @@ -853,22 +878,26 @@ 1.471 if (ord(i) & 128) != 0: 1.472 top_set = counter 1.473 counter = counter + 1 1.474 - 1.475 + 1.476 name = self.safe(self.sectors[head+p:head+p+10]) 1.477 - 1.478 + 1.479 #print hex(head+p), name 1.480 - 1.481 + 1.482 load = self.str2num(4, self.sectors[head+p+10:head+p+14]) 1.483 exe = self.str2num(4, self.sectors[head+p+14:head+p+18]) 1.484 length = self.str2num(4, self.sectors[head+p+18:head+p+22]) 1.485 - 1.486 + 1.487 + #print hex(ord(self.sectors[head+p+22])), \ 1.488 + # hex(ord(self.sectors[head+p+23])), \ 1.489 + # hex(ord(self.sectors[head+p+24])) 1.490 + 1.491 inddiscadd = self.read_new_address( 1.492 self.sectors[head+p+22:head+p+25] 1.493 ) 1.494 newdiratts = self.str2num(1, self.sectors[head+p+25]) 1.495 1.496 if inddiscadd == -1: 1.497 - 1.498 + 1.499 if (newdiratts & 0x8) != 0: 1.500 1.501 if self.verify: 1.502 @@ -908,7 +937,7 @@ 1.503 files.append([name, "", load, exe, length]) 1.504 1.505 #print hex(head+p), hex(head+p+22) 1.506 - 1.507 + 1.508 else: 1.509 1.510 if (newdiratts & 0x8) != 0: 1.511 @@ -925,6 +954,7 @@ 1.512 for start, end in inddiscadd: 1.513 1.514 #print hex(start), hex(end), "-->" 1.515 + 1.516 # Try to interpret the data at the referenced address 1.517 # as a directory. 1.518 1.519 @@ -955,14 +985,14 @@ 1.520 files.append([name, file, load, exe, length]) 1.521 1.522 p = p + 26 1.523 - 1.524 - 1.525 + 1.526 + 1.527 # Go to tail of directory structure (0x800 -- 0xc00) 1.528 - 1.529 + 1.530 tail = head + self.sector_size 1.531 - 1.532 + 1.533 dir_end = self.sectors[tail+self.sector_size-5:tail+self.sector_size-1] 1.534 - 1.535 + 1.536 if dir_end != 'Nick': 1.537 1.538 if self.verify: 1.539 @@ -973,7 +1003,7 @@ 1.540 ) 1.541 1.542 return '', files 1.543 - 1.544 + 1.545 dir_name = self.safe( 1.546 self.sectors[tail+self.sector_size-16:tail+self.sector_size-6] 1.547 ) 1.548 @@ -992,12 +1022,12 @@ 1.549 1.550 dir_title = \ 1.551 self.sectors[tail+self.sector_size-35:tail+self.sector_size-16] 1.552 - 1.553 + 1.554 if head == 0x800 and self.disc_type == 'adE': 1.555 dir_name = '$' 1.556 if head == 0xc8800 and self.disc_type == 'adEbig': 1.557 dir_name = '$' 1.558 - 1.559 + 1.560 endseq = self.sectors[tail+self.sector_size-6] 1.561 if endseq != dir_seq: 1.562 1.563 @@ -1009,10 +1039,10 @@ 1.564 ) 1.565 1.566 return dir_name, files 1.567 - 1.568 + 1.569 #print '<--' 1.570 #print 1.571 - 1.572 + 1.573 return dir_name, files 1.574 1.575
