// ----------------------------------------
// Перекодировка текстового файла
// из OEM в ANSI с использованием
// дополнительной таблицы перекодировки
// ----------------------------------------

#define STRICT
#include <windows.h>
#include <commdlg.h>
#include <mem.h>

// Прототипы функций
HFILE GetSrcFile(void);
HFILE GetDstFile(void);
int  Oem3Ansi(HFILE, HFILE);

// Указатель на таблицу перекодировки,
// которая будет загружена из ресурсов
char far * lpXlatTable;

// Идентификатор копии приложения
HINSTANCE hInst;

// -------------------------------
// Функция WinMain
// -------------------------------

#pragma argsused
int PASCAL
WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR     lpszCmdLine,
	int       nCmdShow)
{
  // Иднетификаторы файлов
  HFILE hfSrc, hfDst;

  // Положение ресурса в файле
  HRSRC   hResource;

  // Идентификатор таблицы перекодировки
  HGLOBAL hXlatTable;

  // Сохраняем идентификатор копии приложения
  // в глобальной переменной
  hInst = hInstance;

  // Определяем расположение ресурса
  hResource   = FindResource(hInstance, "XlatTable", "XLAT");

  // получаем идентификатор ресурса
  hXlatTable  = LoadResource(hInstance, hResource);

  // Фиксируем ресурс в памяти, получая его адрес
  lpXlatTable = (char far *)LockResource(hXlatTable);

  // Если адрес равен NULL, при загружке или
  // фиксации ресурса произошла ошибка
  if(lpXlatTable == NULL)
  {
    MessageBox(NULL, "Resource loading error", NULL, MB_OK);
    return(-1);
  }

  // Открываем входной файл.
  hfSrc = GetSrcFile();
  if(!hfSrc) return 0;

  // Открываем выходной файл
  hfDst = GetDstFile();
  if(!hfDst) return 0;

  // Выполняем перекодировку файла
  if(Oem3Ansi(hfSrc, hfDst))
  {
    MessageBox(NULL, "Low Memory", NULL, MB_OK);
  }

  // Закрываем входной и выходной файлы
  _lclose(hfSrc);
  _lclose(hfDst);

  // Разблокируем и освобождаем ресурс
  UnlockResource(hXlatTable);
  FreeResource(hXlatTable);

  return 0;
}

// -------------------------------
// Функция GetSrcFile
// Выбор файла для перекодировки
// -------------------------------

HFILE GetSrcFile(void)
{
  OPENFILENAME ofn;

  char szFile[256];
  char szFileTitle[256];
  char szFilter[256] =
	 "Text Files\0*.txt;*.doc\0Any Files\0*.*\0";
  HFILE hf;

  szFile[0] = '\0';
  memset(&ofn, 0, sizeof(OPENFILENAME));

  // Инициализируем нужные нам поля

  // Добавляем флаг OFN_ENABLETEMPLATE, который
  // разрешает использование шаблона
  ofn.Flags =   OFN_PATHMUSTEXIST  | OFN_FILEMUSTEXIST
		| OFN_HIDEREADONLY | OFN_ENABLETEMPLATE;

  // Идентификатор модуля, содержащего шаблон
  // диалоговой панели. В нашем случае это
  // идентификатор копии приложения
  ofn.hInstance = hInst;

  // Имя ресурса, содержащего шаблон
  ofn.lpTemplateName = (LPSTR)"Open";

  // Заполняем остальные поля
  ofn.lStructSize       = sizeof(OPENFILENAME);
  ofn.hwndOwner         = NULL;
  ofn.lpstrFilter       = szFilter;
  ofn.nFilterIndex      = 1;
  ofn.lpstrFile         = szFile;
  ofn.nMaxFile          = sizeof(szFile);
  ofn.lpstrFileTitle    = szFileTitle;
  ofn.nMaxFileTitle     = sizeof(szFileTitle);
  ofn.lpstrInitialDir   = NULL;

  // Выбираем входной файл
  if (GetOpenFileName(&ofn)) {
    // Открываем на чтение
    hf = _lopen(ofn.lpstrFile, OF_READ);
    return hf;
  }
  else return 0;
}

// -------------------------------
// Функция GetDstFile
// Выбор файла для записи
// результата перекодировки
// -------------------------------

HFILE GetDstFile(void)
{
  OPENFILENAME ofn;

  char szFile[256];
  char szFileTitle[256];
  char szFilter[256] =
	 "Text Files\0*.txt;*.doc\0Any Files\0*.*\0";

  HFILE hf;

  szFile[0] = '\0';

  memset(&ofn, 0, sizeof(OPENFILENAME));

  // Добавляем флаг OFN_ENABLETEMPLATE, который
  // разрешает использование шаблона
  ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLETEMPLATE;

  // Идентификатор модуля, содержащего шаблон
  ofn.hInstance = hInst;

  // Имя ресурса, содержащего шаблон
  ofn.lpTemplateName = (LPSTR)"Open";

  // Изменяем заголовок диалоговой панели
  ofn.lpstrTitle = (LPSTR)"Выберите выходной файл";

  // Заполняем остальные поля
  ofn.lStructSize       = sizeof(OPENFILENAME);
  ofn.hwndOwner         = NULL;
  ofn.lpstrFilter       = szFilter;
  ofn.nFilterIndex      = 1;
  ofn.lpstrFile         = szFile;
  ofn.nMaxFile          = sizeof(szFile);
  ofn.lpstrFileTitle    = szFileTitle;
  ofn.nMaxFileTitle     = sizeof(szFileTitle);
  ofn.lpstrInitialDir   = NULL;

  // Выбираем выходной файл
  if (GetSaveFileName(&ofn)) {

    // Открываем на запись.
    // При необходимости создаем файл
    hf = _lcreat(ofn.lpstrFile, 0);
    return hf;
  }
  else return 0;
}

// -------------------------------
// Функция Oem3Ansi
// Перекодировка файла
// -------------------------------

int Oem3Ansi(HFILE hfSrcFile, HFILE hfDstFile)
{
  // Счетчик прочитанных байт
  DWORD cbRead;

  // Рзамер файла
  DWORD dwFileSize;

  // Идентификатор глобального блока
  // памяти, который будет использован для
  // чтения файла
  HGLOBAL hglbBuf;

  // Указатель на глобальный блок памяти
  unsigned char huge * hBuf;

  // Определяем размер файла. Для этого
  // устанавливаем текущую позицию на
  // конец файла
  dwFileSize = _llseek(hfSrcFile, 0l, 2);

  // Устанавливаем текущую позицию
  // на начало файла
  _llseek(hfSrcFile, 0l, 0);

  // Заказываем глобальный блок памяти,
  // размер которого равен длине файла
  hglbBuf = GlobalAlloc(GMEM_FIXED, dwFileSize);
  hBuf = (unsigned char huge *)GlobalLock(hglbBuf);

  // Если мало свободной памяти,
  // возвращаем код ошибки
  if(hBuf == NULL) return(-1);

  // Читаем файл в полученный блок памяти
  cbRead = _hread(hfSrcFile, hBuf, dwFileSize);

  // Выполняем перекодировку
  for(long i=0; i < cbRead; i++)
  {
    // Перекодировка по таблице,
    // загруженной из ресурсов
    hBuf[i] = lpXlatTable[hBuf[i]];

    // Перекодировка из OEM в ANSI
    OemToAnsiBuff((const char far*)&hBuf[i],
       (char far*)&hBuf[i], 1);
  }

  // Сохраняем содержимое блока памяти в
  // выходном файле
  _hwrite(hfDstFile, hBuf, dwFileSize);

  // Расфиксируем и освобождаем
  // блок памяти
  GlobalUnlock(hglbBuf);
  GlobalFree(hglbBuf);
  return 0;
}

