/*
*******************************************************************************
\file file.h
\brief File management
\project bee2 [cryptographic library]
\created 2025.04.11
\version 2025.05.27
\copyright The Bee2 authors
\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
*******************************************************************************
*/

/*!
*******************************************************************************
\file file.h
\brief Управление файлами
*******************************************************************************
*/

#ifndef __BEE2_FILE_H
#define __BEE2_FILE_H

#include <stdio.h>
#include "bee2/defs.h"

#ifdef __cplusplus
extern "C" {
#endif

/*!
*******************************************************************************
\file file.h

Переопределены стандартные функции работы с файлами как потоками: fopen(),
fclose(), fread(), fwrite() и т.д.

Cохраняются соглашения стандартных функций:
- параметр mode функции fileOpen() имеет формат "{r|w|a}[+][b]";
- параметр origin функции fileSeek() принимает одно из трех значений:
  FILE_SET (начало файла), FILE_CUR (текущая позиция файла), FILE_END (конец 
  файла). 

Запись в файл происходит в два этапа: сначала из внешнего буфера в кэш-память,
затем из кэша непосредственно на физический носитель. Очистка кэша 
(второй этап) реализована в функциях fileFlush() и fileSeek(). 

\expect Если файл открыт в режиме чтения / записи, т.е. параметр mode 
функции fileOpen() содержит '+', то между вызовами функций записи 
fileWrite() / fileWrite2() / filePuts() и вызовами функций чтения 
fileRead() / fileRead2() / fileGets() вызываются функции fileSeek() и (или) 
fileFlush().

\pre В функции передаются корректные строки, дескрипторы файлов и буферы 
памяти.

\typedef file_t
\brief Дескриптор файла
*******************************************************************************
*/

typedef FILE* file_t;

/*!	\brief Открытие файла

	Открывается файл с именем name в режиме mode. 
	\return Дескриптор открытого файла в случае успеха и нулевой дескриптор 
	в противном случае.
	\remark Действуют правила fopen(). По этим правилам определяется режим
	доступа (в зависимости от mode) и устанавливается файловый указатель.
*/
file_t fileOpen( 
	const char* name,		/*< [in] имя файла */
	const char* mode		/*< [in] режим */
);

/*!	\brief Создание временного файла

	Создается временный файл. 
	\return Дескриптор файла в случае успеха и нулевой дескриптор в противном 
	случае. 
	\remark Действуют правила tmpfile(). В частности, файл открывается в режиме 
	"w+b" и автоматически удаляется при штатном завершении программы.
*/
file_t fileTmp();

/*!	\brief Закрытие файла

	Закрывается файл file.
*/
void fileClose( 
	file_t file				/*< [in,out] файл */
);

/*!	\brief Закрытие файла с контролем

	Закрывается файл file. При закрытии контролируется завершение всех
	операций записи.
	\return Признак успеха.
*/
bool_t fileClose2(
	file_t file				/*< [in,out] файл */
);

/*!	\brief Проверка корректности файла

	Проверяется корректность файла file.
	\return Признак успеха.
	\remark Действуют правила fclose(). В частности, очищается кэш файла
	и при этом могут происходить ошибки. 
*/
bool_t fileIsValid( 
	const file_t file		/*< [in] файл */
);

/*!	\brief Перемещение файлового указателя

	Указатель файла file смещается на offset позиций относительно точки отсчета
	origin. Перед перемещением указателя очищается кэш файла. 
	\return Признак успеха.
	\remark Действуют правила fseek(). В частности, файловый указатель может быть 
	перемещен за конец файла. Если после перемещения указателя вызывается операция 
	записи в файл, то промежуток между концом файла и позицией	указателя 
	заполняется нулями.
	\warning В отличие от fseek(), смещение offset не может быть отрицательным.
*/
bool_t fileSeek(
	file_t file,		/*< [in,out] файл */ 
	size_t offset, 		/*< [in] смещение */
	int origin			/*< [out] точка отсчета */
);

/*!	\brief Позиция файлового указателя

	Определяется текущая позиция указателя файла file.
	\return Текущая позиция или SIZE_MAX в случае ошибки.
*/
size_t fileTell(
	file_t file			/*< [in,out] файл */ 
);

/*!	\brief Запись в файл

	Буфер [count]buf записывается в файл file, начиная с текущей позиции его
	указателя. Запись прерывается при ошибках. Число записанных октетов
	сохраняется по адресу written. Если ошибок нет, то файловый указатель
	смещается вправо на count октетов.
	\return ERR_OK, если записаны все count октетов, и код ошибки в противном
	случае.
	\remark Реализация интерфейса write_i.
*/
err_t fileWrite(
	size_t* written,	/*< [out] записано октетов */
	const void* buf,	/*< [in] буфер */
	size_t count,		/*< [in] записать октетов */
	file_t file			/*< [in,out] файл */
);

/*!	\brief Запись в файл 2

	Буфер [count]buf записывается в файл file, начиная с текущей позиции
	его указателя. Запись прерывается при ошибках. Если ошибок нет, то файловый
	указатель смещается вправо на count октетов.
	\return Число сount, если все октеты записаны успешно, или SIZE_MAX
	в случае ошибки.
*/
size_t fileWrite2(
	file_t file,		/*< [in,out] файл */
	const void* buf,	/*< [out] буфер */
	size_t count		/*< [in] записать октетов */
);

/*!	\brief Очистка кэша файла

	Кэш файла file записывается в файл физически и очищается.
	\return Признак успеха.
	\remark Действуют правила fflush().
*/
bool_t fileFlush(
	file_t file			/*< [in,out] file */
);


/*!	\brief Чтение из файла

	Из файла file, начиная с текущей позиции его указателя, читается count 
	октетов. Чтение прерывается при достижении конца файла и при ошибках. 
	Прочитанные октеты сохраняются в буфере buf, а их число -- по адресу read.
	Если ошибок нет, то файловый указатель смещается вправо на read октетов.
	\return 
	- ERR_OK, если прочитаны все count октетов;
	- ERR_MAX, если прочитано меньше count октетов и достигнут конец файла;
    - ERR_FILE_READ в случае ошибок чтения.
	\remark Реализация интерфейса read_i.
*/
err_t fileRead( 
	size_t* read,		/*< [out] прочитано октетов */
	void* buf,			/*< [out] буфер */
	size_t count,		/*< [in] прочитать октетов */
	file_t file			/*< [in,out] файл */
);

/*!	\brief Чтение из файла 2

	Из файла file, начиная с текущей позиции его указателя, читается count 
	октетов. Чтение прерывается при достижении конца файла и при ошибках. 
	Прочитанные октеты сохраняются в буфере buf. Если ошибок нет, то 
	файловый указатель смещается вправо на число прочитанных октетов. 
	\return Число прочитанных октетов в случае успеха или SIZE_MAX в случае 
	ошибки.
*/
size_t fileRead2(
	void* buf,			/*< [out] буфер */ 
	size_t count,		/*< [in] прочитать октетов */ 
	file_t file			/*< [in,out] файл */ 
);

/*!	\brief Запись строки в файл

	Строка str записывается в файл file, начиная с текущей позиции его 
	указателя. Запись прерывается при ошибках. Если ошибок нет, то файловый
	указатель смещается вправо на strLen(str) октетов.
	\return Признак успеха. 
	\remark Действуют правила fputs().
*/
bool_t filePuts(
	file_t file,		/*< [out] файл */
	const char* str		/*< [in] str */ 
);

/*!	\brief Чтение строки из файла

	Из файла file, начиная с текущей позиции его указателя, читается строка 
	str. Чтение прерывается в следующих ситуациях:
	- прочитано count - 1 символов,
	- при чтении встретился символ новой строки (он переносится в str),
	- достигнут конец файла,
	- при ошибках. 
	После прочитанных символов в str добавляется символ '\0'. Если ошибок нет, 
	то файловый указатель смещается вправо на число прочитанных символов.
	\return Указатель на str, если строка прочитана, и нулевой указатель 
	в противном случае.
	\remark При сount <= 1 возвращается нулевой указатель.
	\remark Действуют правила fgets().
*/
char* fileGets(
	char* str,			/*< [out] str */ 
	size_t count,		/*< [in] размер буфера строки */
	file_t file			/*< [in,out] файл */
);

/*!	\brief Размер файла

	Определяется размер файла file.
	\return Размер или SIZE_MAX в случае ошибки.
	\remark Положение файлового указателя не изменяется.
*/
size_t fileSize(
	file_t file			/*< [in,out] файл */ 
);

/*!	\brief Обрезка файла

	Длина файла file сокращается до size октетов.
	\return Признак успеха.
*/
bool_t fileTrunc(
	file_t file,		/*< [in,out] файл */ 
	size_t size			/*< [in] длина */ 
);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __BEE2_FILE_H */
