/*
 * Copyright(C) 2000 Проект ИОК
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто Про.
 */

/*!
 * \file $RCSfile$
 * \version $Revision: 220301 $
 * \date $Date:: 2020-10-23 11:48:43 +0300#$
 * \author $Author: markova $
 * \brief Функция поиска следующей папки.
 */

#include "fat12prj.h"
#include "WinCryptEx.h"

#define FMT_3X _TEXT("%03x")
static int is_valid_name(BOOL long_names, const TCHAR *folder, TSupFileType type);
static BOOL can_open_container(TFat12Context * ctx, const TCHAR* folder, TSupFileType type);

static DWORD fat12_enum_next_long_names(TFat12Context* ctx, TReaderInfoFolderEnum *inf) {
    TSupFileType type;
    TCHAR name[MAX_CONTAINER_NAME_LEN + 1];
    if (!inf->add_info.info)
	return (DWORD)ERROR_INVALID_PARAMETER;

    //перечисляем только папки, в которых можно открыть header.key
    DWORD code = support_nextent((TSupFileEnum*)inf->add_info.info, name, &type);
    while (!code && !can_open_container(ctx, name, type))
    	code = support_nextent((TSupFileEnum*)inf->add_info.info, name, &type);

    if (code)
	return (DWORD)ERROR_FILE_NOT_FOUND;
    _tcscpy(inf->name.text, name);
    inf->name.length = _tcslen(inf->name.text);
    return ERROR_SUCCESS;
}

//В зависимости от флага перечисляет либо существующие папки fat12
//либо имя папки, которой еще не существует - если сверху передали флаг RDR_FOLDER_ENUM_FLAG_NEW. 
static DWORD fat12_enum_next_short_names(TFat12Context* ctx, TReaderInfoFolderEnum* inf){
    TFat12FolderEnumNew *folder_enum = (TFat12FolderEnumNew*)(inf->add_info.info);
    if( inf->flags & RDR_FOLDER_ENUM_FLAG_NEW )
    {
	TCHAR *ptr;
	ptr = folder_enum->full_prefix + _tcslen( folder_enum->full_prefix );
	for( ; folder_enum->num <= 0xfff; folder_enum->num++ )
	{
	    int exist;
	    _sntprintf( ptr, 4, FMT_3X , (unsigned)folder_enum->num );
	    exist = fat12_is_dir_exist( folder_enum->full_prefix );
	    *ptr = 0;
	    if( exist == DIR_NOTEXIST )
		break;
	}
	if( folder_enum->num >= 0xfff )
	    return (DWORD)ERROR_FILE_NOT_FOUND;
	_tcscpy( inf->name.text, folder_enum->prefix ); 
	_sntprintf( inf->name.text + _tcslen( inf->name.text ), 4, FMT_3X,
	    (unsigned)folder_enum->num++ );
	inf->name.length = _tcslen( inf->name.text );
	inf->flags = RDR_FOLDER_ENUM_FLAG_END;
	return ERROR_SUCCESS;
    }
    else if (inf->flags & RDR_FOLDER_ENUM_FLAG_END) {
	return (DWORD)ERROR_FILE_NOT_FOUND;
    }

    //В этом блоке перечисляем следующую папку с контейнером. 
    TSupFileEnum *f = (TSupFileEnum*)inf->add_info.info;
    TSupFileType type;
    DWORD code = support_nextent( f, inf->name.text, &type );

    //Если у папки кривое имя или не можем ее открыть, пропускаем
    while (!code && !can_open_container(ctx, inf->name.text, type))
	code = support_nextent( f, inf->name.text, &type );
    if( code )
	return (DWORD)ERROR_FILE_NOT_FOUND;
    inf->name.length = _tcslen( inf->name.text );
    return ERROR_SUCCESS;
}

/*! 
 * \ingroup fat12_fun_reader
 * \brief Функция поиска следующей папки.
 *
 * Функция поиска следующей директории.
 * \param context [in] контекст считывателя. Не используется.
 * \param info [in/out] структура #TReaderInfoFolderEnum
 * \sa #TReaderInfoFolderEnum, #READER_FUN_FOLDER_ENUM_NEXT,
 *  #TSupSysFunction, #fat12_info_folder_enum_open, 
 *  #fat12_info_folder_enum_close,
 * \return Код ошибки
 */

DWORD fat12_info_folder_enum_next(
    TSupSysContext *context, 
    TSupSysInfo *info )
{
    TReaderInfoFolderEnum *inf = (TReaderInfoFolderEnum*)info;
    TFat12Context * ctx = (TFat12Context *)context;
    
    SUPSYS_PRE_INFO( info, TReaderInfoFolderEnum );
    SUPSYS_PRE_STRING_PTRS( inf->name.text, inf->name.length );

    if (ctx->long_names) {
	return fat12_enum_next_long_names(ctx, inf);
    } else {
	return fat12_enum_next_short_names(ctx, inf);
    }
}


static BOOL is_valid_name(BOOL long_names, const TCHAR *folder, TSupFileType type )
{
    size_t i;
    size_t j;

    if (!long_names && _tcslen(folder) > 12)
	return FALSE;
    if( type != SUP_FTYPE_DIR )
	return FALSE;
    if (!long_names) {
	for (i = 0, j = 0; i < 12 && folder[i]; i++)
	{
	    if (folder[i] == '.')
	    {
		if (j)
		    return FALSE;
		j++;
		continue;
	    }
	    if (j)
		j++;
	    if (fat12_convert(folder[i]) != folder[i])
		return FALSE;
	}
	if (j > 4)
	    return FALSE;
    }
    return TRUE;
}

static BOOL has_container_access(TFat12Context * ctx, const TCHAR* folder)
{
    return (ERROR_SUCCESS == check_container_access_by_file(ctx, folder, HEADER_KEY_NAME))
	|| (ERROR_SUCCESS == check_container_access_by_file(ctx, folder, NAME_KEY_NAME));
}

BOOL can_open_container(TFat12Context * ctx, const TCHAR* folder, TSupFileType type)
{
    return is_valid_name(ctx->long_names, folder, type) && has_container_access(ctx, folder);
}

/* end of file: $Id: f12dcnxt.c 220301 2020-10-23 08:48:43Z markova $ */
