docs: def extract(self, offset, description, file_name, size, name=None):
          '''
          Extract an embedded file from the target file, if it matches an extract rule.
          Called automatically by Binwalk.scan().
  
          @offset      - Offset inside the target file to begin the extraction.
          @description - Description of the embedded file to extract, as returned by libmagic.
          @file_name   - Path to the target file.
          @size        - Number of bytes to extract.
          @name        - Name to save the file as.
  
          Returns the name of the extracted file (blank string if nothing was extracted).
          '''
          fname = ''
          rule = None
          recurse = False
          command_line = ''
          original_dir = os.getcwd()
          rules = self.match(description)
          file_path = os.path.realpath(file_name)
  
          # No extraction rules for this file
          if not rules:
              binwalk.core.common.debug("No extraction rules found for '%s'" % description)
              return (None, None, False, str(None))
          else:
              binwalk.core.common.debug("Found %d matching extraction rules" % len(rules))
  
          # Generate the output directory name where extracted files will be stored
          output_directory = self.build_output_directory(file_name)
  
          # Extract to end of file if no size was specified
          if not size:
              size = file_size(file_path) - offset
  
          if os.path.isfile(file_path):
              binwalk.core.common.debug("Changing directory to: %s" % output_directory)
              os.chdir(output_directory)
  
              # Extract into subdirectories named by the offset
              if self.extract_into_subdirs:
                  # Remove trailing L that is added by hex()
                  offset_dir = "0x%X" % offset
                  os.mkdir(offset_dir)
                  os.chdir(offset_dir)
  
              # Loop through each extraction rule until one succeeds
              for i in range(0, len(rules)):
                  rule = rules[i]
  
                  binwalk.core.common.debug("Processing extraction rule #%d (%s)" % (i, str(rule['cmd'])))
  
                  # Make sure we don't recurse into any extracted directories if
                  # instructed not to
                  if rule['recurse'] in [True, False]:
                      recurse = rule['recurse']
                  else:
                      recurse = True
  
                  binwalk.core.common.debug("Extracting %s[%d:] to %s" % (file_path, offset, name))
  
                  # Copy out the data to disk, if we haven't already
                  fname = self._dd(file_path, offset, size, rule['extension'], output_file_name=name)
  
                  # If there was a command specified for this rule, try to execute it.
                  # If execution fails, the next rule will be attempted.
                  if rule['cmd']:
  
                      # Note the hash of the original file; if --rm is specified and the
                      # extraction utility modifies the original file rather than creating
                      # a new one (AFAIK none currently do, but could happen in the future),
                      # we don't want to remove this file.
                      if self.remove_after_execute:
                          fname_md5 = file_md5(fname)
  
                      binwalk.core.common.debug("Executing extraction command %s" % (str(rule['cmd'])))
  
                      # Execute the specified command against the extracted file
                      if self.run_extractors:
                          (extract_ok, command_line) = self.execute(rule['cmd'], fname, rule['codes'])
                      else:
                          extract_ok = True
                          command_line = ''
  
                      binwalk.core.common.debug("Ran extraction command: %s" % command_line)
                      binwalk.core.common.debug("Extraction successful: %s" % extract_ok)
  
                      # Only clean up files if remove_after_execute was specified.
                      # Only clean up files if the file was extracted sucessfully, or if we've run
                      # out of extractors.
                      if self.remove_after_execute and (extract_ok == True or i == (len(rules) - 1)):
  
                          # Remove the original file that we extracted,
                          # if it has not been modified by the extractor.
                          try:
                              if file_md5(fname) == fname_md5:
                                  os.unlink(fname)
                          except KeyboardInterrupt as e:
                              raise e
                          except Exception as e:
                              pass
  
                      # If the command executed OK, don't try any more rules
                      if extract_ok == True:
                          break
                      # Else, remove the extracted file if this isn't the last rule in the list.
                      # If it is the last rule, leave the file on disk for the
                      # user to examine.
                      elif i != (len(rules) - 1):
                          try:
                              os.unlink(fname)
                          except KeyboardInterrupt as e:
                              raise e
                          except Exception as e:
                              pass
  
                  # If there was no command to execute, just use the first rule
                  else:
                      break
  
              binwalk.core.common.debug("Changing directory back to: %s" % original_dir)
              os.chdir(original_dir)
  
          return (output_directory, fname, recurse, command_line)