tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

write_framework_hmap.py (3204B)


      1 # Copyright 2016 The Chromium Authors
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 
      6 import os
      7 import struct
      8 import sys
      9 
     10 def Main(args):
     11  if len(args) < 4:
     12    print(
     13        "Usage: %s output.hmap Foo.framework header1.h..." % args[0],
     14        file=sys.stderr)
     15    return 1
     16 
     17  (out, framework, all_headers) = args[1], args[2], args[3:]
     18 
     19  framework_name = os.path.basename(framework).split('.')[0]
     20  all_headers = map(os.path.abspath, all_headers)
     21  filelist = {}
     22  for header in all_headers:
     23    filename = os.path.basename(header)
     24    filelist[filename] = header
     25    filelist[os.path.join(framework_name, filename)] = header
     26  WriteHmap(out, filelist)
     27  return 0
     28 
     29 
     30 def NextGreaterPowerOf2(x):
     31  return 2**(x).bit_length()
     32 
     33 
     34 def WriteHmap(output_name, filelist):
     35  """Generates a header map based on |filelist|.
     36 
     37  Per Mark Mentovai:
     38    A header map is structured essentially as a hash table, keyed by names used
     39    in #includes, and providing pathnames to the actual files.
     40 
     41  The implementation below and the comment above comes from inspecting:
     42    http://www.opensource.apple.com/source/distcc/distcc-2503/distcc_dist/include_server/headermap.py?txt
     43  while also looking at the implementation in clang in:
     44    https://llvm.org/svn/llvm-project/cfe/trunk/lib/Lex/HeaderMap.cpp
     45  """
     46  magic = 1751998832
     47  version = 1
     48  _reserved = 0
     49  count = len(filelist)
     50  capacity = NextGreaterPowerOf2(count)
     51  strings_offset = 24 + (12 * capacity)
     52  max_value_length = len(max(filelist.values(), key=lambda v: len(v)))
     53 
     54  out = open(output_name, 'wb')
     55  out.write(struct.pack('<LHHLLLL', magic, version, _reserved, strings_offset,
     56                        count, capacity, max_value_length))
     57 
     58  # Create empty hashmap buckets.
     59  buckets = [None] * capacity
     60  for file, path in filelist.items():
     61    key = 0
     62    for c in file:
     63      key += ord(c.lower()) * 13
     64 
     65    # Fill next empty bucket.
     66    while buckets[key & capacity - 1] is not None:
     67      key = key + 1
     68    buckets[key & capacity - 1] = (file, path)
     69 
     70  next_offset = 1
     71  for bucket in buckets:
     72    if bucket is None:
     73      out.write(struct.pack('<LLL', 0, 0, 0))
     74    else:
     75      (file, path) = bucket
     76      key_offset = next_offset
     77      prefix_offset = key_offset + len(file) + 1
     78      suffix_offset = prefix_offset + len(os.path.dirname(path) + os.sep) + 1
     79      next_offset = suffix_offset + len(os.path.basename(path)) + 1
     80      out.write(struct.pack('<LLL', key_offset, prefix_offset, suffix_offset))
     81 
     82  # Pad byte since next offset starts at 1.
     83  out.write(struct.pack('<x'))
     84 
     85  for bucket in buckets:
     86    if bucket is not None:
     87      (file, path) = bucket
     88      base = os.path.dirname(path) + os.sep
     89      path = os.path.basename(path)
     90      file = file.encode('UTF-8')
     91      base = base.encode('UTF-8')
     92      path = path.encode('UTF-8')
     93      out.write(struct.pack('<%ds' % len(file), file))
     94      out.write(struct.pack('<s', b'\0'))
     95      out.write(struct.pack('<%ds' % len(base), base))
     96      out.write(struct.pack('<s', b'\0'))
     97      out.write(struct.pack('<%ds' % len(path), path))
     98      out.write(struct.pack('<s', b'\0'))
     99 
    100 
    101 if __name__ == '__main__':
    102  sys.exit(Main(sys.argv))