title: Translating a C binary data read function to Python
body: <p>(I've edited this for clarity, and changed the actual question a bit based on EOL's answer)
  I'm trying to translate the following function in C to Python but failing miserably (see C code below). As I understand it, it takes four 1-byte chars starting from the memory location pointed to by <code>from</code>, treats them as unsigned long ints in order to give each one 4 bytes of space, and does some bitshifting to arrange them as a big-endian 32-bit integer. It's then used in an algorithm of checking file validity. (from the <a href="http://babel.ifarchive.org/" rel="nofollow">Treaty of Babel</a>)</p>
  
  <pre><code>static int32 read_alan_int(unsigned char *from)
  {
   return ((unsigned long int) from[3])| ((unsigned long int)from[2] &lt;&lt; 8) |
         ((unsigned long int) from[1]&lt;&lt;16)| ((unsigned long int)from[0] &lt;&lt; 24);
  }
  /*
    The claim algorithm for Alan files is:
     * For Alan 3, check for the magic word
     * load the file length in blocks
     * check that the file length is correct
     * For alan 2, each word between byte address 24 and 81 is a
        word address within the file, so check that they're all within
        the file
     * Locate the checksum and verify that it is correct
  */
  static int32 claim_story_file(void *story_file, int32 extent)
  {
   unsigned char *sf = (unsigned char *) story_file;
   int32 bf, i, crc=0;
   if (extent &lt; 160) return INVALID_STORY_FILE_RV;
   if (memcmp(sf,"ALAN",4))
   { /* Identify Alan 2.x */
   bf=read_alan_int(sf+4);
   if (bf &gt; extent/4) return INVALID_STORY_FILE_RV;
   for (i=24;i&lt;81;i+=4)
   if (read_alan_int(sf+i) &gt; extent/4) return INVALID_STORY_FILE_RV;
   for (i=160;i&lt;(bf*4);i++)
   crc+=sf[i];
   if (crc!=read_alan_int(sf+152)) return INVALID_STORY_FILE_RV;
   return VALID_STORY_FILE_RV;
   }
   else
   { /* Identify Alan 3 */
     bf=read_alan_int(sf+12);
     if (bf &gt; (extent/4)) return INVALID_STORY_FILE_RV;
     for (i=184;i&lt;(bf*4);i++)
      crc+=sf[i];
   if (crc!=read_alan_int(sf+176)) return INVALID_STORY_FILE_RV;
  
   }
   return INVALID_STORY_FILE_RV;
  }
  </code></pre>
  
  <p>I'm trying to reimplement this in Python. For implementing the <code>read_alan_int</code> function, I would think that importing <code>struct</code> and doing <code>struct.unpack_from('&gt;L', data, offset)</code> would work. However, on valid files, this always returns 24 for the value <code>bf</code>, which means that the <code>for</code> loop is skipped.</p>
  
  <pre><code>def read_alan_int(file_buffer, i):
      i0 = ord(file_buffer[i]) * (2 ** 24)
      i1 = ord(file_buffer[i + 1]) * (2 ** 16)
      i2 = ord(file_buffer[i + 2]) * (2 ** 8)
      i3 = ord(file_buffer[i + 3])
      return i0 + i1 + i2 + i3
  
  def is_a(file_buffer):
      crc = 0
      if len(file_buffer) &lt; 160:
          return False
      if file_buffer[0:4] == 'ALAN':
          # Identify Alan 2.x
          bf = read_alan_int(file_buffer, 4)
          if bf &gt; len(file_buffer)/4:
              return False
          for i in range(24, 81, 4):
              if read_alan_int(file_buffer, i) &gt; len(file_buffer)/4:
                  return False
          for i in range(160, bf * 4):
              crc += ord(file_buffer[i])
          if crc != read_alan_int(file_buffer, 152):
              return False
          return True
      else:
          # Identify Alan 3.x
          #bf = read_long(file_buffer, 12, '&gt;')
          bf = read_alan_int(file_buffer, 12)
          print bf
          if bf &gt; len(file_buffer)/4:
              return False
          for i in range(184, bf * 4):
              crc += ord(file_buffer[i])
          if crc != read_alan_int(file_buffer, 176):
              return False
          return True
      return False
  
  
  if __name__ == '__main__':
      import sys, struct
      data = open(sys.argv[1], 'rb').read()
      print is_a(data)
  </code></pre>
  
  <p>...but the damn thing still returns 24. Unfortunately, my C skills are non-existent so I'm having trouble getting the original program to print some debug output so I can know what bf is supposed to be.</p>
  
  <p>What am I doing wrong?</p>
  
  <hr>
  
  <p>Ok, so I'm apparently doing read_alan_int correctly. However, what's failing for me is the check that the first 4 characters are "ALAN". All of my test files fail this test. I've changed the code to remove this if/else statement and to instead just take advantage of early returns, and now all of my unit tests pass. So, on a practical level, I'm done. However, I'll keep the question open to address the new problem: how can I possibly wrangle the bits to get "ALAN" out of the first 4 chars?</p>
  
  <pre><code>def is_a(file_buffer):
      crc = 0
      if len(file_buffer) &lt; 160:
          return False
      #if file_buffer.startswith('ALAN'):
          # Identify Alan 2.x
      bf = read_long(file_buffer, 4)
      if bf &gt; len(file_buffer)/4:
          return False
      for i in range(24, 81, 4):
          if read_long(file_buffer, i) &gt; len(file_buffer)/4:
              return False
      for i in range(160, bf * 4):
          crc += ord(file_buffer[i])
      if crc == read_long(file_buffer, 152):
          return True
      # Identify Alan 3.x
      crc = 0
      bf = read_long(file_buffer, 12)
      if bf &gt; len(file_buffer)/4:
          return False
      for i in range(184, bf * 4):
          crc += ord(file_buffer[i])
      if crc == read_long(file_buffer, 176):
          return True
      return False
  </code></pre>