parameters: (self, signature, offset)
return_statement: return tags
docstring: Analyzes self.data for the specified signature data at the specified offset .
  
          @signature - The signature to apply to the data.
          @offset    - The offset in self.data to apply the signature to.
  
          Returns a dictionary of tags parsed from the data.
docstring_summary: Analyzes self.data for the specified signature data at the specified offset .
docstring_tokens: Analyzes self . data for the specified signature data at the specified offset .
function: def _analyze(self, signature, offset):
          '''
          Analyzes self.data for the specified signature data at the specified offset .
  
          @signature - The signature to apply to the data.
          @offset    - The offset in self.data to apply the signature to.
  
          Returns a dictionary of tags parsed from the data.
          '''
          description = []
          tag_strlen = None
          max_line_level = 0
          previous_line_end = 0
          tags = {'id' : signature.id, 'offset' : offset, 'invalid' : False, 'once' : False}
  
          # Apply each line of the signature to self.data, starting at the specified offset
          for n in range(0, len(signature.lines)):
              line = signature.lines[n]
  
              # Ignore indentation levels above the current max indent level
              if line.level <= max_line_level:
                  # If the relative offset of this signature line is just an integer value, use it
                  if isinstance(line.offset, int):
                      line_offset = line.offset
                  # Else, evaluate the complex expression
                  else:
                      # Format the previous_line_end value into a string. Add the '+' sign to explicitly
                      # state that this value is to be added to any subsequent values in the expression
                      # (e.g., '&0' becomes '4+0').
                      ple = '%d+' % previous_line_end
                      # Allow users to use either the '&0' (libmagic) or '&+0' (explcit addition) sytaxes;
                      # replace both with the ple text.
                      line_offset_text = line.offset.replace('&+', ple).replace('&', ple)
                      # Evaluate the expression
                      line_offset = self._do_math(offset, line_offset_text)
  
                  # Sanity check
                  if not isinstance(line_offset, int):
                      raise ParserException("Failed to convert offset '%s' to a number: '%s'" % (line.offset, line.text))
  
                  # The start of the data needed by this line is at offset + line_offset.
                  # The end of the data will be line.size bytes later.
                  start = offset + line_offset
                  end = start + line.size
  
                  # If the line has a packed format string, unpack it
                  if line.pkfmt:
                      try:
                          dvalue = struct.unpack(line.pkfmt, binwalk.core.compat.str2bytes(self.data[start:end]))[0]
                      # Not enough bytes left in self.data for the specified format size
                      except struct.error as e:
                          dvalue = 0
                  # Else, this is a string
                  else:
                      # Wildcard strings have line.value == None
                      if line.value is None:
                          # Check to see if this is a string whose size is known and has been specified on a previous
                          # signature line.
                          if binwalk.core.compat.has_key(tags, 'strlen') and binwalk.core.compat.has_key(line.tags, 'string'):
                              dvalue = self.data[start:(start+tags['strlen'])]
                          # Else, just terminate the string at the first newline, carriage return, or NULL byte
                          else:
                              dvalue = self.data[start:end].split('\x00')[0].split('\r')[0].split('\n')[0]
                      # Non-wildcard strings have a known length, specified in the signature line
                      else:
                          dvalue = self.data[start:end]
  
                  # Some integer values have special operations that need to be performed on them
                  # before comparison (e.g., "belong&0x0000FFFF"). Complex math expressions are
                  # supported here as well.
                  #if isinstance(dvalue, int) and line.operator:
                  if line.operator:
                      try:
                          # If the operator value of this signature line is just an integer value, use it
                          if isinstance(line.opvalue, int) or isinstance(line.opvalue, long):
                              opval = line.opvalue
                          # Else, evaluate the complex expression
                          else:
                              opval = self._do_math(offset, line.opvalue)
  
                          # Perform the specified operation
                          if line.operator == '&':
                              dvalue &= opval
                          elif line.operator == '|':
                              dvalue |= opval
                          elif line.operator == '*':
                              dvalue *= opval
                          elif line.operator == '+':
                              dvalue += opval
                          elif line.operator == '-':
                              dvalue -= opval
                          elif line.operator == '/':
                              dvalue /= opval
                          elif line.operator == '~':
                              dvalue = ~opval
                          elif line.operator == '^':
                              dvalue ^= opval
                      except KeyboardInterrupt as e:
                          raise e
                      except Exception as e:
                          raise ParserException("Operation '" + str(dvalue) + " " + str(line.operator) + "= " + str(line.opvalue) + "' failed: " + str(e))
  
                  # Does the data (dvalue) match the specified comparison?
                  if ((line.value is None) or
                      (line.regex and line.value.match(dvalue)) or
                      (line.condition == '=' and dvalue == line.value) or
                      (line.condition == '>' and dvalue > line.value) or
                      (line.condition == '<' and dvalue < line.value) or
                      (line.condition == '!' and dvalue != line.value) or
                      (line.condition == '~' and (dvalue == ~line.value)) or
                      (line.condition == '^' and (dvalue ^ line.value)) or
                      (line.condition == '&' and (dvalue & line.value)) or
                      (line.condition == '|' and (dvalue | line.value))):
  
                      # Up until this point, date fields are treated as integer values,
                      # but we want to display them as nicely formatted strings.
                      if line.type == 'date':
                          ts = datetime.datetime.utcfromtimestamp(dvalue)
                          dvalue = ts.strftime("%Y-%m-%d %H:%M:%S")
  
                      # Generate the tuple for the format string
                      dvalue_tuple = ()
                      for x in self.fmtstr.finditer(line.format):
                          dvalue_tuple += (dvalue,)
  
                      # Format the description string
                      desc = line.format % dvalue_tuple
  
                      # If there was any description string, append it to the list of description string parts
                      if desc:
                          description.append(desc)
  
                      # Process tag keywords specified in the signature line. These have already been parsed out of the
                      # original format string so that they can be processed separately from the printed description string.
                      for (tag_name, tag_value) in binwalk.core.compat.iterator(line.tags):
                          # If the tag value is a string, try to format it
                          if isinstance(tag_value, str):
                              # Generate the tuple for the format string
                              dvalue_tuple = ()
                              for x in self.fmtstr.finditer(tag_value):
                                  dvalue_tuple += (dvalue,)
  
                              # Format the tag string
                              tags[tag_name] = tag_value % dvalue_tuple
                          # Else, just use the raw tag value
                          else:
                              tags[tag_name] = tag_value
  
                          # Some tag values are intended to be integer values, so try to convert them as such
                          try:
                              tags[tag_name] = int(tags[tag_name], 0)
                          except KeyboardInterrupt as e:
                              raise e
                          except Exception as e:
                              pass
  
                      # Abort processing soon as this signature is marked invalid, unless invalid results
                      # were explicitly requested. This means that the sooner invalid checks are made in a
                      # given signature, the faster the scan can filter out false positives.
                      if not self.show_invalid and tags['invalid']:
                          break
  
                      # Look ahead to the next line in the signature; if its indent level is greater than
                      # that of the current line, then track the end of data for the current line. This is
                      # so that subsequent lines can use the '>>&0' offset syntax to specify relative offsets
                      # from previous lines.
                      try:
                          next_line = signature.lines[n+1]
                          if next_line.level > line.level:
                              if line.type == 'string':
                                  previous_line_end = line_offset + len(dvalue)
                              else:
                                  previous_line_end = line_offset + line.size
                      except IndexError as e:
                          pass
  
                      # If this line satisfied its comparison, +1 the max indentation level
                      max_line_level = line.level + 1
                  else:
                      # No match on the first line, abort
                      if line.level == 0:
                          break
                      else:
                          # If this line did not satisfy its comparison, then higher
                          # indentation levels will not be accepted.
                          max_line_level = line.level
  
          # Join the formatted description strings and remove backspace characters (plus the preceeding character as well)
          tags['description'] = self.bspace.sub('', " ".join(description))
  
          # This should never happen
          if not tags['description']:
              tags['display'] = False
              tags['invalid'] = True
  
          # If the formatted string contains non-printable characters, consider it invalid
          if self.printable.match(tags['description']).group() != tags['description']:
              tags['invalid'] = True
  
          return tags
function_tokens: def _analyze ( self , signature , offset ) : description = [ ] tag_strlen = None max_line_level = 0 previous_line_end = 0 tags = { 'id' : signature . id , 'offset' : offset , 'invalid' : False , 'once' : False } # Apply each line of the signature to self.data, starting at the specified offset for n in range ( 0 , len ( signature . lines ) ) : line = signature . lines [ n ] # Ignore indentation levels above the current max indent level if line . level <= max_line_level : # If the relative offset of this signature line is just an integer value, use it if isinstance ( line . offset , int ) : line_offset = line . offset # Else, evaluate the complex expression else : # Format the previous_line_end value into a string. Add the '+' sign to explicitly # state that this value is to be added to any subsequent values in the expression # (e.g., '&0' becomes '4+0'). ple = '%d+' % previous_line_end # Allow users to use either the '&0' (libmagic) or '&+0' (explcit addition) sytaxes; # replace both with the ple text. line_offset_text = line . offset . replace ( '&+' , ple ) . replace ( '&' , ple ) # Evaluate the expression line_offset = self . _do_math ( offset , line_offset_text ) # Sanity check if not isinstance ( line_offset , int ) : raise ParserException ( "Failed to convert offset '%s' to a number: '%s'" % ( line . offset , line . text ) ) # The start of the data needed by this line is at offset + line_offset. # The end of the data will be line.size bytes later. start = offset + line_offset end = start + line . size # If the line has a packed format string, unpack it if line . pkfmt : try : dvalue = struct . unpack ( line . pkfmt , binwalk . core . compat . str2bytes ( self . data [ start : end ] ) ) [ 0 ] # Not enough bytes left in self.data for the specified format size except struct . error as e : dvalue = 0 # Else, this is a string else : # Wildcard strings have line.value == None if line . value is None : # Check to see if this is a string whose size is known and has been specified on a previous # signature line. if binwalk . core . compat . has_key ( tags , 'strlen' ) and binwalk . core . compat . has_key ( line . tags , 'string' ) : dvalue = self . data [ start : ( start + tags [ 'strlen' ] ) ] # Else, just terminate the string at the first newline, carriage return, or NULL byte else : dvalue = self . data [ start : end ] . split ( '\x00' ) [ 0 ] . split ( '\r' ) [ 0 ] . split ( '\n' ) [ 0 ] # Non-wildcard strings have a known length, specified in the signature line else : dvalue = self . data [ start : end ] # Some integer values have special operations that need to be performed on them # before comparison (e.g., "belong&0x0000FFFF"). Complex math expressions are # supported here as well. #if isinstance(dvalue, int) and line.operator: if line . operator : try : # If the operator value of this signature line is just an integer value, use it if isinstance ( line . opvalue , int ) or isinstance ( line . opvalue , long ) : opval = line . opvalue # Else, evaluate the complex expression else : opval = self . _do_math ( offset , line . opvalue ) # Perform the specified operation if line . operator == '&' : dvalue &= opval elif line . operator == '|' : dvalue |= opval elif line . operator == '*' : dvalue *= opval elif line . operator == '+' : dvalue += opval elif line . operator == '-' : dvalue -= opval elif line . operator == '/' : dvalue /= opval elif line . operator == '~' : dvalue = ~ opval elif line . operator == '^' : dvalue ^= opval except KeyboardInterrupt as e : raise e except Exception as e : raise ParserException ( "Operation '" + str ( dvalue ) + " " + str ( line . operator ) + "= " + str ( line . opvalue ) + "' failed: " + str ( e ) ) # Does the data (dvalue) match the specified comparison? if ( ( line . value is None ) or ( line . regex and line . value . match ( dvalue ) ) or ( line . condition == '=' and dvalue == line . value ) or ( line . condition == '>' and dvalue > line . value ) or ( line . condition == '<' and dvalue < line . value ) or ( line . condition == '!' and dvalue != line . value ) or ( line . condition == '~' and ( dvalue == ~ line . value ) ) or ( line . condition == '^' and ( dvalue ^ line . value ) ) or ( line . condition == '&' and ( dvalue & line . value ) ) or ( line . condition == '|' and ( dvalue | line . value ) ) ) : # Up until this point, date fields are treated as integer values, # but we want to display them as nicely formatted strings. if line . type == 'date' : ts = datetime . datetime . utcfromtimestamp ( dvalue ) dvalue = ts . strftime ( "%Y-%m-%d %H:%M:%S" ) # Generate the tuple for the format string dvalue_tuple = ( ) for x in self . fmtstr . finditer ( line . format ) : dvalue_tuple += ( dvalue , ) # Format the description string desc = line . format % dvalue_tuple # If there was any description string, append it to the list of description string parts if desc : description . append ( desc ) # Process tag keywords specified in the signature line. These have already been parsed out of the # original format string so that they can be processed separately from the printed description string. for ( tag_name , tag_value ) in binwalk . core . compat . iterator ( line . tags ) : # If the tag value is a string, try to format it if isinstance ( tag_value , str ) : # Generate the tuple for the format string dvalue_tuple = ( ) for x in self . fmtstr . finditer ( tag_value ) : dvalue_tuple += ( dvalue , ) # Format the tag string tags [ tag_name ] = tag_value % dvalue_tuple # Else, just use the raw tag value else : tags [ tag_name ] = tag_value # Some tag values are intended to be integer values, so try to convert them as such try : tags [ tag_name ] = int ( tags [ tag_name ] , 0 ) except KeyboardInterrupt as e : raise e except Exception as e : pass # Abort processing soon as this signature is marked invalid, unless invalid results # were explicitly requested. This means that the sooner invalid checks are made in a # given signature, the faster the scan can filter out false positives. if not self . show_invalid and tags [ 'invalid' ] : break # Look ahead to the next line in the signature; if its indent level is greater than # that of the current line, then track the end of data for the current line. This is # so that subsequent lines can use the '>>&0' offset syntax to specify relative offsets # from previous lines. try : next_line = signature . lines [ n + 1 ] if next_line . level > line . level : if line . type == 'string' : previous_line_end = line_offset + len ( dvalue ) else : previous_line_end = line_offset + line . size except IndexError as e : pass # If this line satisfied its comparison, +1 the max indentation level max_line_level = line . level + 1 else : # No match on the first line, abort if line . level == 0 : break else : # If this line did not satisfy its comparison, then higher # indentation levels will not be accepted. max_line_level = line . level # Join the formatted description strings and remove backspace characters (plus the preceeding character as well) tags [ 'description' ] = self . bspace . sub ( '' , " " . join ( description ) ) # This should never happen if not tags [ 'description' ] : tags [ 'display' ] = False tags [ 'invalid' ] = True # If the formatted string contains non-printable characters, consider it invalid if self . printable . match ( tags [ 'description' ] ) . group ( ) != tags [ 'description' ] : tags [ 'invalid' ] = True return tags