# A script for analyzing the output of NPSPY and merging data about streams.

import sys


def ReadFile(filename, flags='rb'):
  """Returns the contents of a file."""
  file = open(filename, flags)
  result = file.read()
  file.close()
  return result


def WriteFile(filename, contents):
  """Overwrites the file with the given contents."""
  file = open(filename, 'w')
  file.write(contents)
  file.close()  
  

# sample line: 'NPP_NewStream(0x645c898, 0x56ba900("application/x-shockwave-flash"), 0x64bb3b0 (http://weeklyad.target.com/target/flash/target/target.swf?ver=090326), TRUE, NP_NORMAL)'
class Stream:
  def __init__(self, line):
    split = line.split(', ')
    
    self.mime_type = split[1].split('"')[1]
    self.url = split[2].split(' ')[1].strip('()')
    self.seekable = split[3]
    self.type = split[4].strip(')')
    self.size = 0
    self.status = ''
    try:
      self.address = split[2].split(' ')[0]
    except:
      print 'parsing error on ' + line
      self.address = ''

    if self.type != 'NP_NORMAL':
      print 'line got unexpected type: ' + line

    
def main(argv=None):
  if argv is None:
    argv = sys.argv
    
  streams = []

  if len(argv) != 2:
    print 'need filename'
    return
  file = ReadFile(argv[1])
  for line in file.splitlines():
    if line.startswith('NPP_NewStream('):
      if line.count('(') < 3:
        print 'unknown format for line: ' + line
        continue

      s = Stream(line)
      streams.append(s)
    elif line.startswith('NPP_Write('):
      # sample: NPP_Write(0x645c898, 0x64bb3b0, 0, 16384, 0x56c1000("CW")))
      split = line.split(', ')
      address = split[1]
      start = int(split[2])
      size = int(split[3])
      found = False
      for stream in streams:
        if stream.address == address:
          if stream.size != start:
            print 'error: starting at wrong place for write ' + stream.url + ' ' + str(stream.size) + ' ' + str(start)
          stream.size += size
          found = True
          break
          
      if not found:
        print "couldn't find stream to match NPP_Write " + line
    elif line.startswith('NPP_DestroyStream('):
      # sample: NPP_DestroyStream(0x645c898, 0x64bb3b0, NPRES_DONE)
      split = line.split(', ')
      address = split[1]
      status = split[2].strip(')')
      found = False
      for stream in streams:
        if stream.address == address:
          stream.status = status
          stream.address = ''  # address can be reused
          found = True
          break
          
      if not found:
        print "couldn't find stream to match NPP_DestroyStream " + line


  output = []
  for stream in streams:
    if stream.status != 'NPRES_DONE':
      print 'error: no NPP_DestroyStream with success for ' + stream.url + ' ' + stream.status + '.'
    output.append(', '.join([stream.url, stream.mime_type, str(stream.size), stream.seekable]))
  output_file = argv[1].replace('.', '_analyzed.')
  
  WriteFile(output_file, '\n'.join(output))
  
  
if __name__ == "__main__":
  sys.exit(main())
