docs: def save(self, filepath = None, password = None, keyfile = None):
          """This method saves the database.
  
          It's possible to parse a data path to an alternative file.
  
          """
          
          if (password is None and keyfile is not None and keyfile != "" and
              type(keyfile) is str):
              self.keyfile = keyfile
          elif (keyfile is None and password is not None and password != "" and
                type(password is str)):
              self.password = password
          elif (keyfile is not None and password is not None and
                keyfile != "" and password != "" and type(keyfile) is str and
                type(password) is str):
              self.keyfile = keyfile
              self.password = password
  
          if self.read_only:
              raise KPError("The database has been opened read-only.")
          elif ((self.password is None and self.keyfile is None) or 
                (filepath is None and self.filepath is None) or 
                (keyfile == "" and password == "")):
              raise KPError("Need a password/keyfile and a filepath to save the "
                            "file.")
          elif ((type(self.filepath) is not str and self.filepath is not None) or
                (type(self.password) is not str and self.password is not None) or
                (type(self.keyfile) is not str and self.keyfile is not None)):
              raise KPError("filepath, password and keyfile  must be strings.")
          elif self._num_groups == 0:
              raise KPError("Need at least one group!")
          
          content = bytearray()
  
          # First, read out all groups
          for i in self.groups:
              # Get the packed bytes
              # j stands for a possible field type
              for j in range(1, 10):
                  ret_save = self._save_group_field(j, i)
                  # The field type and the size is always in front of the data
                  if ret_save is not False:
                      content += struct.pack('<H', j)
                      content += struct.pack('<I', ret_save[0])
                      content += ret_save[1]
              # End of field
              content += struct.pack('<H', 0xFFFF)
              content += struct.pack('<I', 0) 
  
          # Same with entries
          for i in self.entries:
              for j in range(1, 15):
                  ret_save = self._save_entry_field(j, i)
                  if ret_save is not False:
                      content += struct.pack('<H', j)
                      content += struct.pack('<I', ret_save[0])
                      content += ret_save[1]
              content += struct.pack('<H', 0xFFFF)
              content += struct.pack('<I', 0)
  
          # Generate new seed and new vector; calculate the new hash
          Random.atfork()
          self._final_randomseed = Random.get_random_bytes(16)
          self._enc_iv = Random.get_random_bytes(16)
          sha_obj = SHA256.new()
          sha_obj.update(bytes(content))
          self._contents_hash = sha_obj.digest()
          del sha_obj
  
          # Pack the header
          header = bytearray()
          header += struct.pack('<I', 0x9AA2D903)
          header += struct.pack('<I', 0xB54BFB65)
          header += struct.pack('<I', self._enc_flag)
          header += struct.pack('<I', self._version)
          header += struct.pack('<16s', self._final_randomseed)
          header += struct.pack('<16s', self._enc_iv)
          header += struct.pack('<I', self._num_groups)
          header += struct.pack('<I', self._num_entries)
          header += struct.pack('<32s', self._contents_hash)
          header += struct.pack('<32s', self._transf_randomseed)
          if self._key_transf_rounds < 150000:
              self._key_transf_rounds = 150000
          header += struct.pack('<I', self._key_transf_rounds)
  
          # Finally encrypt everything...
          if self.password is None:
              masterkey = self._get_filekey()
          elif self.password is not None and self.keyfile is not None:
              passwordkey = self._get_passwordkey()
              filekey = self._get_filekey()
              sha = SHA256.new()
              sha.update(passwordkey+filekey)
              masterkey = sha.digest()
          else:
              masterkey = self._get_passwordkey()
          final_key = self._transform_key(masterkey)
          encrypted_content = self._cbc_encrypt(content, final_key)
          del content
          del masterkey
          del final_key
          
          # ...and write it out
          if filepath is not None:
              try:
                  handler = open(filepath, "wb")
              except IOError:
                  raise KPError("Can't open {0}".format(filepath))
              if self.filepath is None:
                  self.filepath = filepath
          elif filepath is None and self.filepath is not None:
              try:
                  handler = open(self.filepath, "wb")
              except IOError:
                  raise KPError("Can't open {0}".format(self.filepath))
          else:
              raise KPError("Need a filepath.")
  
          try:
              handler.write(header+encrypted_content)
          except IOError:
              raise KPError("Can't write to file.")
          finally:
              handler.close()
          
          if not path.isfile(self.filepath+".lock"):
              try:
                  lock = open(self.filepath+".lock", "w")
                  lock.write('')
              except IOError:
                  raise KPError("Can't create lock-file {0}".format(self.filepath
                                                                    +".lock"))
              else:
                  lock.close()
          return True