Load a database from passed-in buffer (bytes).

        :param buf: A string (bytes) of the database contents.
        :type buf: str
        :param password: The password for the database.
        :type password: str
        :param keyfile: Path to a keyfile (or a stream) that can be used instead of or in conjunction with password for database.
        :type keyfile: str or file-like object
        :param readonly: Whether to open the database read-only.
        :type readonly: bool

def load_from_buffer(self, buf, password=None, keyfile=None, readonly=False):
        """
        Load a database from passed-in buffer (bytes).

        :param buf: A string (bytes) of the database contents.
        :type buf: str
        :param password: The password for the database.
        :type password: str
        :param keyfile: Path to a keyfile (or a stream) that can be used instead of or in conjunction with password for database.
        :type keyfile: str or file-like object
        :param readonly: Whether to open the database read-only.
        :type readonly: bool
        """
        if password is None and keyfile is None:
            raise ValueError("Password and/or keyfile is required.")
        
        # Save these to use as defaults when saving the database
        self.password = password
        self.keyfile = keyfile
        
        # The header is 124 bytes long, the rest is content
        hdr_len = HeaderStruct.length
        header_bytes = buf[:hdr_len]
        crypted_content = buf[hdr_len:]
        
        self.header = HeaderStruct(header_bytes)
        
        self.log.debug("Extracted header: {0}".format(self.header))
        # Check if the database is supported
        if self.header.version & const.DB_SUPPORTED_VERSION_MASK != const.DB_SUPPORTED_VERSION & const.DB_SUPPORTED_VERSION_MASK:
            raise exc.UnsupportedDatabaseVersion('Unsupported file version: {0}'.format(hex(self.header.version)))
            
        #Actually, only AES is supported.
        if not self.header.flags & HeaderStruct.AES:
            raise exc.UnsupportedDatabaseEncryption('Only AES encryption is supported.')
        
        final_key = util.derive_key(seed_key=self.header.seed_key,
                                    seed_rand=self.header.seed_rand,
                                    rounds=self.header.key_enc_rounds,
                                    password=password, keyfile=keyfile)
        
        # FIXME: Remove this once we've tracked down issues.
        self.log.debug("(load) Final key: {0!r}, pass={1}".format(final_key, password))
        
        decrypted_content = util.decrypt_aes_cbc(crypted_content, key=final_key, iv=self.header.encryption_iv)
        
        # Check if decryption failed
        if ((len(decrypted_content) > const.DB_MAX_CONTENT_LEN) or
            (len(decrypted_content) == 0 and self.header.ngroups > 0)):
            raise exc.IncorrectKey("Decryption failed! The key is wrong or the file is damaged.")
        
        if not self.header.contents_hash == hashlib.sha256(decrypted_content).digest():
            self.log.debug("Decrypted content: {0!r}".format(decrypted_content))
            self.log.error("Hash mismatch. Header hash = {0!r}, hash of contents = {1!r}".format(self.header.contents_hash,                                                                                                 hashlib.sha256(decrypted_content).digest()))
            raise exc.AuthenticationError("Hash test failed. The key is wrong or the file is damaged.")
            
        # First thing (after header) are the group definitions.
        for _i in range(self.header.ngroups):
            gstruct = GroupStruct(decrypted_content)
            self.groups.append(Group.from_struct(gstruct))
            length = len(gstruct)
            decrypted_content = decrypted_content[length:]
        
        # Next come the entry definitions.
        for _i in range(self.header.nentries):
            estruct = EntryStruct(decrypted_content)
            self.entries.append(Entry.from_struct(estruct))
            length = len(estruct)
            decrypted_content = decrypted_content[length:]
            
        # Sets up the hierarchy, relates the group/entry model objects.
        self._bind_model()