'Generator that produces <dir_list>, <object_list> pairs of groups of content of a specified bucket.'

def bucket_list_streaming(self, bucket, prefix=None, recursive=None, uri_params=None, limit=(-1)):

    def _list_truncated(data):
        is_truncated = (getTextFromXml(data, './/IsTruncated') or 'false')
        return (is_truncated.lower() != 'false')
    def _get_contents(data):
        return getListFromXml(data, 'Contents')
    def _get_common_prefixes(data):
        return getListFromXml(data, 'CommonPrefixes')
    uri_params = ((uri_params and uri_params.copy()) or {})
    truncated = True
    prefixes = []
    num_objects = 0
    num_prefixes = 0
    max_keys = limit
    while truncated:
        response = self.bucket_list_noparse(bucket, prefix, recursive, uri_params, max_keys)
        current_list = _get_contents(response['data'])
        current_prefixes = _get_common_prefixes(response['data'])
        num_objects += len(current_list)
        num_prefixes += len(current_prefixes)
        if (limit > (num_objects + num_prefixes)):
            max_keys = (limit - (num_objects + num_prefixes))
        truncated = _list_truncated(response['data'])
        if truncated:
            if ((limit == (-1)) or ((num_objects + num_prefixes) < limit)):
                if current_list:
                    uri_params['marker'] = current_list[(-1)]['Key']
                else:
                    uri_params['marker'] = current_prefixes[(-1)]['Prefix']
                debug(("Listing    continues    after    '%s'" % uri_params['marker']))
            else:
                (yield (truncated, current_prefixes, current_list))
                break
        (yield (truncated, current_prefixes, current_list))
