#define  STRICT
#include <windows.h>
#include <stdio.h>
// Все коды написаны для компилятора BC4.5
// Если у Вас его нет - воспользуйтесь прилагаемой готовой DLL.
//
// Обязательно прочтите ReadMe.1st
//
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <mem.h>

#pragma hdrstop

#define _EXPORT _export
/*
	Программист! Помни!
	1) В опциях компилятора должно быть включено:
		1.1) выравнивание данных по границе двойного слова (4 байта)
		1.2) Calling conventions: Pascal
	2) В TargetExpert:
		2.1) Target type:Dinamic library
		2.2) Platform: WIN32
		2.3) Target model: GUI
	3) В вызове VBA параметры функций указываются в обратном порядке
*/

// Вспомогательная функция для преобразования пароля.
// Выполняет побитовый циклический сдвиг пароля влево (в сторону
// старших разрядов) на один разряд.
int FAR _export ShiftPassword(unsigned char *password, int password_len)
{
	int k,i,j;

	// j всегда == 1 если при сдвиге возникает перенос за
	//границу байта, иначе j==0
	j=0;
	for (i=0; i<password_len; i++)
	{
		k=password[i];
		k=k<<1;

		password[i]=char((k & 0xFF) + j);

		// Был ли перенос за границу байта?
		if (k>0xFF)
			j=1;
		else
			j=0;
	};
	password[0]=char(password[0] + j);
	return 0;
};

// Функция RemoveFile удаляет файл таким образом, что его нельзя
// восстановить из корзины. Она работает очень просто - сначала
// заполняет файл символом '?', а после удаляет его. 
int FAR _export RemoveFile(const char *file_name)
// Удаление файла без возможности восстановления
// Коды возврата
// 0 - полный порядок
// -1 - Не могу удалить
{
	FILE *f;
	long file_len;
	int buf_len;
	unsigned char buf[1024];

	// Открываю файл, чтобы узнать его длинну
	f=fopen(file_name,"rb");
	if (f==NULL) return -1;
	file_len=filelength(fileno(f));
	fclose(f);

	// Теперь я открываю файл для перезаписи
	f=fopen(file_name,"wb");
	if (f==NULL) return -1;

	buf_len=1024;
	memset(buf,int('?'),buf_len);
	while (file_len>0)
	{
		if (file_len<buf_len) buf_len=file_len;

		// Записываю
		if (fwrite(buf,buf_len,1,f)!=1) return -1;

		// Уменьшаю величину оставшейся части файла на размер буфера
		file_len-=buf_len;
	};
	fclose(f);

	remove(file_name);
	return 0;
};

// Функция Code - суть этой библиотеки.
int FAR _export Code(  const char *passwordChrs,  const char *file_name)
// Кодирование/декодирование файла.
// Коды возврата
// 0 - полный порядок
// 1 - Не могу открыть для чтения исходный файл
// 2 - Не могу открыть для записи вспомогательный файл.
// 3 - Ошибка чтения исходного файла
// 4 - Ошибка: не могу удалить исходный файл.
// 5 - Ошибка: не могу переименовать промежуточный файл в исходный.
// 6 - Ошибка записи вспомогательного файла
{
	FILE *in,*out;
	long file_len,i;
	int j,buf_len,password_len;
	unsigned char buf[1024],password[222],c;

	in=fopen(file_name,"rb");
	if (in==NULL) return 1;

	out=fopen("code.tmp","wb");
	if (out==NULL) return 2;

	file_len=filelength(fileno(in));

	// Копирую пароль, но не более 221 символов
	password_len=strlen(passwordChrs);
	if (password_len>221) password_len=221;
	c=0; // В этой переменной буду накапливать контрольную сумму
	for (i=0; i<password_len; i++)
	{  // Подсчитать контрольную сумму
		c=(unsigned char)(c+passwordChrs[i]);
		password[i+1]=passwordChrs[i];
	};
	password[0]=c;  // Сделать контрольную сумму частью пароля (первым
						 // его символом).
	password_len++; // Длина пароля увеличивается на один контрольный символ

	// Инициирую пароль, сдвигая циклически влево все разряды на число,
	// равное контрольной сумме. На самом деле достаточно сдвига на
	// (c mod 8) разрядов.
	for (i=1; i<c; i++) ShiftPassword(password,password_len);


	buf_len=1024;
	j=0;
	while (file_len>0)
	{
		if (file_len<buf_len) buf_len=file_len;

		// Читаю
		if (fread(buf,buf_len,1,in)!=1)
		{
			fclose(in); fclose(out);
			return 3;
		};

		// Перекодирую
		for (i=0; i<buf_len; i++)
		{
			buf[i]=buf[i] ^ password[j];
			j++;
			if (j==password_len)
			{
				j=0;
				// Использованы все символы - изменяю пароль
				ShiftPassword(password,password_len);
			};
		};

		// Записываю
		if (fwrite(buf,buf_len,1,out)!=1)
		{
			//printf("\nОшибка записи вспомогательного файла.");
			//printf("\nПрограмма завершена аварийно.");
			return 6;
		};

		// Уменьшаю величину оставшейся части файла на размер буфера
		file_len-=buf_len;
	};
	fclose(in);
	fclose(out);

	// Сохранить файл под тем же именем
	if (RemoveFile(file_name)!=0)
	{
		if (remove(file_name)) return 4;
	};
	if (rename("code.tmp",file_name)) return 5;

	if (RemoveFile("code.tmp")!=0) remove("code.tmp");
	return 0;
};

