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