Реализация Base64 шифрования/расшифрования.

Зачем это? Когда нужно чтобы работало под всеми Windows, а не только в WinXP (т.е. нельзя пользоваться CryptAPI аналогичными ф-циями CryptStringToBinary и CryptBinaryToString). Или когда пишется код в 6ой студии (т.е. нет библиотеки ATL из 7ой студии — ATL::Base64Encode / ATL::Base64Decode).

Достоинства:
1. Быстро. Нет операций умножения/деления. Они заменены на битовый сдвиг.
(не относится к подсчёту нужного обьёма выходного буфера)
2. Работа с большими обьёмами данных.
3. Обработка ошибок:
— защита 'от дурака' (проверка вх. параметров)
— обьяснение ошибки с помощью SetLastError
— валидация символов вх.буфера на принадлежность Base64 алфавиту при декриптовании.
4. Ф-ция криптования быстрее аналогичной CryptoAPI ф-ции CryptBinaryToString.
5. Поддержка UNICODE
6. Поддержка 'чистого' API. Т.е. будет работать как в Win32 API, так и в классовых пакетах (WTL/ATL, MFC).
7. Для удобства кодирования/раскодирования строк предусмотрены функции-обёртки возвращающие класс строк.

Недостатки:
1. Ф-ция декриптования чуть медленнее аналогичной CryptoAPI ф-ции CryptStringToBinary

Пример.
Вместе с ф-циями Base64 (де)криптования, в WinMain части приведён ещё и код тестирующий их и сравнивающий работу с аналогичными ф-циями из CryptAPI — CryptStringToBinary/CryptBinaryToString.
В качестве класса срок — пользуюсь CString из библиотеки WTL 7.0.

#define _ATL_USE_CSTRING_FLOAT

#include 

#include 
#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "ShlwApi.lib")

// include для CString'а
//#include  // ATL из 7ой студии

// библиотека WTL 7.0
#include 
#include 
//extern
 CComModule _Module;
#include  // 

////////////////////////////////////////////////////////////////////////////////
//                            BASE 64
////////////////////////////////////////////////////////////////////////////////

BOOL Base64_Code(
   IN BYTE const *pData,  // на вход  - данные, которые надо зашифровать
   IN DWORD dwSize,
   OUT LPTSTR szCodeData, // на выход - зашифрованная строка
   IN OUT DWORD &dwLenInChar // length in TCHAR (if szCodeData == NULL then return length include EOL)
) {
   if (!dwSize) {
      ::SetLastError(ERROR_INVALID_DATA); // ERROR_INVALID_PARAMETER
      return FALSE;
   }
   DWORD dwNeedLen = ((((dwSize-1)/3)+1)<<2) + 1;
   if (szCodeData == NULL) {
      dwLenInChar = dwNeedLen;
      ::SetLastError(DISP_E_BUFFERTOOSMALL); // ERROR_INSUFFICIENT_BUFFER
      return TRUE;
   }
   if (!pData) {
      ::SetLastError(ERROR_INVALID_DATA); // ERROR_INVALID_PARAMETER
      return FALSE;
   }
   if (!szCodeData || (dwLenInChar < dwNeedLen)) {
      dwLenInChar = dwNeedLen;
      ::SetLastError(DISP_E_BUFFERTOOSMALL); // ERROR_INSUFFICIENT_BUFFER
      return FALSE;
   }

   szCodeData[dwNeedLen-1] = 0; // EOL

   const static TCHAR base64ABC[] = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
   DWORD j = 0;
   DWORD i = 0;
   /** /
   // Нижеприведённый цикл разбиваю на 2 части.
   // Таким образом оптимизирую по скорости работы (для больших массивов данных) -
   // удаляю в каждой части лишние проверки.
   for (; i>18) & 0x3F];
                        szCodeData[j++] = base64ABC[(l>>12) & 0x3F];
      if (i+1 < dwSize) szCodeData[j++] = base64ABC[(l>> 6) & 0x3F];
      if (i+2 < dwSize) szCodeData[j++] = base64ABC[(l    ) & 0x3F];
   }
   /**/
   for (; dwSize>2 && i>18) & 0x3F];
      szCodeData[j++] = base64ABC[(l>>12) & 0x3F];
      szCodeData[j++] = base64ABC[(l>> 6) & 0x3F];
      szCodeData[j++] = base64ABC[(l    ) & 0x3F];
   }
   if (i>18) & 0x3F];
                        szCodeData[j++] = base64ABC[(l>>12) & 0x3F];
      if (i+1 < dwSize) szCodeData[j++] = base64ABC[(l>> 6) & 0x3F];
   }
   /**/
   switch (dwSize%3) {
   case 1: szCodeData[j++] = _T('=');
   case 2: szCodeData[j++] = _T('=');
   }
   dwLenInChar = j;

   ::SetLastError(NO_ERROR);
   return TRUE;
}

__forceinline int IndexB64(TCHAR c) {
   if ((c >= _T('A')) && (c <= _T('Z'))) return c-_T('A');
   if ((c >= _T('a')) && (c <= _T('z'))) return c-_T('a')+26;
   if ((c >= _T('0')) && (c <= _T('9'))) return c-_T('0')+52;
   if (c == _T('+')) return 62;
   if (c == _T('/')) return 63;
   return -1;
}

BOOL Base64_Decode(
   IN LPCTSTR szIn,  // На вход  - зашифрованная строка
   IN int iLenIn,    // Длина входной строки. Если == -1, то считаю длину сам...
   OUT BYTE *pData,  // На выход - расшифрованные данные
   IN OUT DWORD &dwSize // IN - размер буфера; OUT - сколько данных записано
) {                     // Если dwSize==0 - возвращаю нужную длину буфера
   if (!szIn || !szIn[0]) {
      ::SetLastError(ERROR_INVALID_DATA); // ERROR_INVALID_PARAMETER
      return FALSE;
   }

   if (iLenIn == -1) {
      iLenIn = lstrlen(szIn);
   }
   DWORD dwNeedSize = (iLenIn>>2)*3 -
                      (szIn[iLenIn-1]==_T('=') ? 1 : 0) -
                      (szIn[iLenIn-2]==_T('=') ? 1 : 0);

   if (pData == NULL) {
      dwSize = dwNeedSize;
      ::SetLastError(DISP_E_BUFFERTOOSMALL); // ERROR_INSUFFICIENT_BUFFER
      return TRUE;
   }
   if (dwSize < dwNeedSize) {
      dwSize = dwNeedSize;
      ::SetLastError(DISP_E_BUFFERTOOSMALL); // ERROR_INSUFFICIENT_BUFFER
      return FALSE;
   }
   if (iLenIn < 4) {
      // минимальный размер строки - 4 символа
      ::SetLastError(ERROR_INVALID_DATA); // ERROR_INVALID_PARAMETER
      return FALSE;
   }

   const static TCHAR base64ABC[] = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");

   dwSize = 0;
   int i=0;
   /** /
   // Нижеприведённый цикл разбиваю на 2 части.
   // Таким образом оптимизирую по скорости работы (для больших массивов данных) -
   // удаляю в каждой части лишние проверки.
   for (; i>16) & 0xFF);
      if (in1 && bE1 && bE2) pData[dwSize++] = ((l>>8 ) & 0xFF);
      if (in2 && bE2 && bE3) pData[dwSize++] = ((l>>0 ) & 0xFF);
   }
   /**/
   for (; i>16) & 0xFF);
      pData[dwSize++] = ((l>>8 ) & 0xFF);
      pData[dwSize++] = ((l>>0 ) & 0xFF);
   }
   {
      bool bE0=false, bE1=false, bE2=false, bE3=false; // не символ ли "="
      int  iF0=0    , iF1=0    , iF2=0    , iF3=0    ; // индекс в строке алфавита (признак, входит ли символ в Base64 алфавит)

      LONG l = ((bE0 = (szIn[i+0] != _T('='))) ? LONG(iF0 = IndexB64(szIn[i  ])) << 18 : 0) |
               ((bE1 = (szIn[i+1] != _T('='))) ? LONG(iF1 = IndexB64(szIn[i+1])) << 12 : 0) |
               ((bE2 = (szIn[i+2] != _T('='))) ? LONG(iF2 = IndexB64(szIn[i+2])) << 6  : 0) |
               ((bE3 = (szIn[i+3] != _T('='))) ? LONG(iF3 = IndexB64(szIn[i+3])) << 0  : 0);
      if ((iF0 == -1) || (iF1 == -1) || (iF2 == -1) || (iF3 == -1)) { // во входную строку "затесался" символ не из Base64 алфавита...
         ::SetLastError(ERROR_INVALID_DATA); // ERROR_INVALID_PARAMETER
         return TRUE; // По аналогии с CryptStringToBinary..
      }

      if (bE0 && bE1) pData[dwSize++] = ((l>>16) & 0xFF);
      if (bE1 && bE2) pData[dwSize++] = ((l>>8 ) & 0xFF);
      if (bE2 && bE3) pData[dwSize++] = ((l>>0 ) & 0xFF);
   }
   /**/
   ::SetLastError(NO_ERROR);
   return TRUE;
}

CString Base64_Code(
   IN LPCTSTR szIn // на вход  - сторка, которую надо зашифровать
) {
   CString strOut; // на выход - зашифрованная строка

   if (!szIn || !szIn[0]) {
      ::SetLastError(ERROR_INVALID_DATA); // ERROR_INVALID_PARAMETER
      return strOut;
   }

   DWORD dwSizeInBytes = lstrlen(szIn) << (sizeof(TCHAR)-1);
   DWORD dwNeed = 0;
   BOOL bRes = Base64_Code(NULL, dwSizeInBytes, NULL, dwNeed); // Узнаю сколько нужно символов (c EOL)
   if (bRes) {
      TCHAR *szCodeData = new TCHAR[dwNeed];
      if (szCodeData == NULL) {
         ::SetLastError(ERROR_OUTOFMEMORY);
      } else {
         bRes = Base64_Code((BYTE*)szIn, dwSizeInBytes, szCodeData, dwNeed);
         if (bRes) {
            strOut = szCodeData;
         }
         delete [] szCodeData; szCodeData = NULL;
      }
   }
   return strOut;
}

CString Base64_Decode(
   IN LPCTSTR szIn // на вход  - зашифрованная строка
) {
   CString strOut;  // на выход - расшифрованная строка
   if (!szIn || !szIn[0]) {
      ::SetLastError(ERROR_INVALID_DATA); // ERROR_INVALID_PARAMETER
      return strOut;
   }

   DWORD dwSizeInChar = lstrlen(szIn);
   DWORD dwNeed = 0;
   BOOL bRes = Base64_Decode(szIn, dwSizeInChar, NULL, dwNeed);
   if (bRes) {
      BYTE *pDecodeBuff = new BYTE[dwNeed];
      if (pDecodeBuff == NULL) {
         ::SetLastError(ERROR_OUTOFMEMORY);
      } else {
         ((TCHAR*)pDecodeBuff)[dwNeed-1] = 0;
         bRes = Base64_Decode(szIn, dwSizeInChar, pDecodeBuff, dwNeed);
         if (bRes) {
            strOut = CString((TCHAR*)pDecodeBuff, dwNeed>>(sizeof(TCHAR)-1));
         }
         delete [] pDecodeBuff; pDecodeBuff = NULL;
      }
   }
   return strOut;
}
////////////////////////////////////////////////////////////////////////////////
CString SelectFile(BOOL bOpenDialog, HWND hWndOwner, LPCTSTR szDefSelectedFile, LPCTSTR szDefExt, LPCTSTR szFilter, LPCTSTR szTitle, LPCTSTR szInitialDir, DWORD dwFlags) {
   CString strFileName;
   DWORD nMaxFile = max(MAX_PATH, (szDefSelectedFile ? lstrlen(szDefSelectedFile)+1 : 0));
anew1:
   TCHAR *szFile = new TCHAR [nMaxFile];
anew2:
   if (szFile == NULL) {
      ::SetLastError(ERROR_OUTOFMEMORY);
   } else {
      szFile[0] = 0;
      if (szDefSelectedFile) {
         lstrcpyn(szFile, szDefSelectedFile, min(nMaxFile, (DWORD)lstrlen(szDefSelectedFile)+1));
      }
      OPENFILENAME OpenFileName = {
         sizeof(OPENFILENAME), // DWORD         lStructSize;
         hWndOwner           , // HWND          hwndOwner;
         NULL                , // HINSTANCE     hInstance;
         szFilter            , // LPCTSTR       lpstrFilter;
         NULL                , // LPTSTR        lpstrCustomFilter;
         0                   , // DWORD         nMaxCustFilter;
         0                   , // DWORD         nFilterIndex;
         szFile              , // LPTSTR        lpstrFile;
         nMaxFile            , // DWORD         nMaxFile;
         NULL                , // LPTSTR        lpstrFileTitle;
         0                   , // DWORD         nMaxFileTitle;
         szInitialDir        , // LPCTSTR       lpstrInitialDir;
         szTitle             , // LPCTSTR       lpstrTitle;
         dwFlags             , // DWORD         Flags;
         0                   , // WORD          nFileOffset;
         0                   , // WORD          nFileExtension;
         szDefExt            , // LPCTSTR       lpstrDefExt;
         0                   , // LPARAM        lCustData;
         NULL                , // LPOFNHOOKPROC lpfnHook;
         NULL                  // LPCTSTR       lpTemplateName;
      };
      if (bOpenDialog ? ::GetOpenFileName(&OpenFileName) : ::GetSaveFileName(&OpenFileName)) {
         strFileName = szFile;
      } else {
         DWORD dwError = ::CommDlgExtendedError();
         switch (dwError) {
         case FNERR_BUFFERTOOSMALL:
            {
               delete [] szFile; szFile = NULL;
               nMaxFile = nMaxFile << 1;
               goto anew1;
            } break;
         case FNERR_INVALIDFILENAME:
            {
               szDefSelectedFile = NULL;
               goto anew2;
            } break;
         }
      }
      delete [] szFile; szFile = NULL;
   }
   return strFileName;
}
////////////////////////////////////////////////////////////////////////////////

int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR     lpCmdLine,
                       int       nCmdShow)
{
   TCHAR szDir[MAX_PATH] = {0};
   ::GetCurrentDirectory(MAX_PATH, szDir);
   TCHAR szFilter[] = _T("Any file (*.*)\0\0");
   CString strFileName = ::SelectFile(TRUE, ::GetDesktopWindow(), NULL, NULL,
      szFilter,
      _T("Please select file to encrypted"), szDir, OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_PATHMUSTEXIST);

   if (strFileName.IsEmpty()) return -1;

   CString strReportCode_API(_T(">  Crypt data (API) - ERROR!\r\n"));
   CString strReportCode_My (_T(">  Crypt data (My) - ERROR!\r\n"));
   CString strReportDecode_API(_T(">  Decode data (API) - ERROR!\r\n"));
   CString strReportDecode_My (_T(">  Decode data (My) - ERROR!\r\n"));

   /**/
   // CODE part
   {
      HANDLE hFileIn     = ::CreateFile(strFileName               , GENERIC_READ , FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
      HANDLE hFileOutAPI = ::CreateFile(strFileName+_T(".API.b64"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
      HANDLE hFileOutMy  = ::CreateFile(strFileName+_T( ".My.b64"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

      DWORD dwFileSize = (hFileIn == INVALID_HANDLE_VALUE) ? 0 : ::GetFileSize(hFileIn, NULL);
      if ((hFileIn     != INVALID_HANDLE_VALUE) &&
          (hFileOutAPI != INVALID_HANDLE_VALUE) &&
          (hFileOutMy  != INVALID_HANDLE_VALUE) && (dwFileSize != INVALID_FILE_SIZE))
      {
         BYTE *pFileData = new BYTE[dwFileSize];
         if (pFileData) {
            DWORD dwNBR = 0;
            BOOL bRes = ::ReadFile(hFileIn, pFileData, dwFileSize, &dwNBR, NULL) && (dwNBR==dwFileSize);
            if (bRes) {
               { // Кодирую с помощью CryptoAPI
                  DWORD dwLenInChar = 0;
                  bRes = ::CryptBinaryToString(pFileData, dwFileSize, CRYPT_STRING_BASE64, NULL, &dwLenInChar); // Узнаю сколько нужно символов (c EOL)
                  if (bRes) {
                     TCHAR *szCodeData = new TCHAR[dwLenInChar];
                     if (szCodeData) {
                        FILETIME ftFirst = {0,0}, ftSecond = {0,0};
                        ::GetSystemTimeAsFileTime(&ftFirst); // засекаю время работы
                        bRes = ::CryptBinaryToString(pFileData, dwFileSize, CRYPT_STRING_BASE64, szCodeData, &dwLenInChar); // криптую
                        ::GetSystemTimeAsFileTime(&ftSecond);
                        if (bRes) {
                           DWORD dwNBW = 0;
                           //if (false) {
                           //   DWORD dwLenInBytes = dwLenInChar<<(sizeof(TCHAR)-1);
                           //   bRes = ::WriteFile(hFileOutAPI, szCodeData, dwLenInBytes, &dwNBW, NULL) && (dwNBW==dwLenInBytes);
                           //} else
                           {
                              // CryptoAPI через каждые 50 символов делает перенос строки... Удаляю эти левые символы.
                              CString strCodeData(szCodeData); strCodeData.Remove(_T('\r')); strCodeData.Remove(_T('\n'));
                              DWORD dwLenInBytes = strCodeData.GetLength()<<(sizeof(TCHAR)-1);
                              bRes = ::WriteFile(hFileOutAPI, (LPCTSTR)strCodeData, dwLenInBytes, &dwNBW, NULL) && (dwNBW==dwLenInBytes);
                           }

                           ULARGE_INTEGER iFirst ; iFirst .LowPart = ftFirst .dwLowDateTime; iFirst .HighPart = ftFirst .dwHighDateTime;
                           ULARGE_INTEGER iSecond; iSecond.LowPart = ftSecond.dwLowDateTime; iSecond.HighPart = ftSecond.dwHighDateTime;
                           ULONGLONG lDiff = iSecond.QuadPart - iFirst.QuadPart; // в десятках наносекунд
                           float fDiff = float(int(lDiff))/10000.f;
                           strReportCode_API.Format(_T(">   Writed code data (API) -> %s; time - %.3f millisecond\r\n"), bRes ? _T("Ok") : _T("Err"), fDiff);
                        }
                        delete [] szCodeData; szCodeData = NULL;
                     }
                  }
               }

               { // Криптую своей ф-цией
                  DWORD dwLenInChar = 0;
                  bRes = Base64_Code(NULL, dwFileSize, NULL, dwLenInChar); // Узнаю сколько нужно символов (c EOL)
                  if (bRes) {
                     TCHAR *szCodeData = new TCHAR[dwLenInChar];
                     if (szCodeData) {
                        FILETIME ftFirst = {0,0}, ftSecond = {0,0};
                        ::GetSystemTimeAsFileTime(&ftFirst); // засекаю время работы
                        bRes = Base64_Code(pFileData, dwFileSize, szCodeData, dwLenInChar);
                        ::GetSystemTimeAsFileTime(&ftSecond);
                        if (bRes) {
                           DWORD dwNBW = 0;
                           DWORD dwLenInBytes = dwLenInChar<<(sizeof(TCHAR)-1);
                           bRes = ::WriteFile(hFileOutMy, szCodeData, dwLenInBytes, &dwNBW, NULL) && (dwNBW==dwLenInBytes);

                           ULARGE_INTEGER iFirst ; iFirst .LowPart = ftFirst .dwLowDateTime; iFirst .HighPart = ftFirst .dwHighDateTime;
                           ULARGE_INTEGER iSecond; iSecond.LowPart = ftSecond.dwLowDateTime; iSecond.HighPart = ftSecond.dwHighDateTime;
                           ULONGLONG lDiff = iSecond.QuadPart - iFirst.QuadPart; // в десятках наносекунд
                           float fDiff = float(int(lDiff))/10000.f;
                           strReportCode_My.Format(_T(">   Writed code data (My)  -> %s; time - %.3f millisecond\r\n"), bRes ? _T("Ok") : _T("Err"), fDiff);
                        }
                        delete [] szCodeData; szCodeData = NULL;
                     }
                  }
               }
            }
            delete [] pFileData; pFileData = NULL;
         }
      }

      ::CloseHandle(hFileOutAPI); hFileOutAPI = NULL;
      ::CloseHandle(hFileOutMy ); hFileOutMy  = NULL;
      ::CloseHandle(hFileIn    ); hFileIn     = NULL;
   }/**/
   ::OutputDebugString(strReportCode_API);
   ::OutputDebugString(strReportCode_My);

   /**/
   // DECODE part
   {
      HANDLE hFileIn     = ::CreateFile(strFileName+_T(".My.b64"    ), GENERIC_READ , FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
      HANDLE hFileOutAPI = ::CreateFile(strFileName+_T(".API.decode"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
      HANDLE hFileOutMy  = ::CreateFile(strFileName+_T( ".My.decode"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

      DWORD dwFileSize = (hFileIn == INVALID_HANDLE_VALUE) ? 0 : ::GetFileSize(hFileIn, NULL);
      if ((hFileIn     != INVALID_HANDLE_VALUE) &&
          (hFileOutAPI != INVALID_HANDLE_VALUE) &&
          (hFileOutMy  != INVALID_HANDLE_VALUE) && (dwFileSize != INVALID_FILE_SIZE))
      {
         DWORD dwFileSizeInChar = dwFileSize>>(sizeof(TCHAR)-1);
         TCHAR *szFileData = new TCHAR[dwFileSizeInChar+1];
         if (szFileData) {
            szFileData[dwFileSizeInChar] = 0; // EOL
            DWORD dwNBR = 0;
            BOOL bRes = ::ReadFile(hFileIn, szFileData, dwFileSize, &dwNBR, NULL) && (dwNBR==dwFileSize);
            if (bRes) {
               { // Расшифровываю с помощью CryptoAPI
                  DWORD dwNeed = 0;
                  DWORD dwSkip = 0;
                  DWORD dwFlags = 0;
                  bRes = ::CryptStringToBinary(szFileData, dwFileSizeInChar, CRYPT_STRING_BASE64, NULL, &dwNeed, &dwSkip, &dwFlags);
                  if (bRes) {
                     BYTE *pDecodeBuff = new BYTE[dwNeed];
                     if (pDecodeBuff) {
                        FILETIME ftFirst = {0,0}, ftSecond = {0,0};
                        ::GetSystemTimeAsFileTime(&ftFirst); // засекаю время работы
                        bRes = ::CryptStringToBinary(szFileData, dwFileSizeInChar, CRYPT_STRING_BASE64, pDecodeBuff, &dwNeed, &dwSkip, &dwFlags);
                        ::GetSystemTimeAsFileTime(&ftSecond);
                        if (bRes) {
                           DWORD dwNBW = 0;
                           bRes = ::WriteFile(hFileOutAPI, pDecodeBuff, dwNeed, &dwNBW, NULL) && (dwNBW==dwNeed);

                           ULARGE_INTEGER iFirst ; iFirst .LowPart = ftFirst .dwLowDateTime; iFirst .HighPart = ftFirst .dwHighDateTime;
                           ULARGE_INTEGER iSecond; iSecond.LowPart = ftSecond.dwLowDateTime; iSecond.HighPart = ftSecond.dwHighDateTime;
                           ULONGLONG lDiff = iSecond.QuadPart - iFirst.QuadPart; // в десятках наносекунд
                           float fDiff = float(int(lDiff))/10000.f;
                           strReportDecode_API.Format(_T(">   Writed decode data (API) -> %s; time - %.3f millisecond\r\n"), bRes ? _T("Ok") : _T("Err"), fDiff);
                        }
                        delete [] pDecodeBuff; pDecodeBuff = NULL;
                     }
                  }
               }
               { // Расшифровываю своей ф-цией
                  DWORD dwNeed = 0;
                  bRes = Base64_Decode(szFileData, dwFileSizeInChar, NULL, dwNeed);
                  if (bRes) {
                     BYTE *pDecodeBuff = new BYTE[dwNeed];
                     if (pDecodeBuff) {
                        FILETIME ftFirst = {0,0}, ftSecond = {0,0};
                        ::GetSystemTimeAsFileTime(&ftFirst); // засекаю время работы
                        bRes = Base64_Decode(szFileData, dwFileSizeInChar, pDecodeBuff, dwNeed);
                        ::GetSystemTimeAsFileTime(&ftSecond);
                        if (bRes) {
                           DWORD dwNBW = 0;
                           bRes = ::WriteFile(hFileOutMy, pDecodeBuff, dwNeed, &dwNBW, NULL) && (dwNBW==dwNeed);

                           ULARGE_INTEGER iFirst ; iFirst .LowPart = ftFirst .dwLowDateTime; iFirst .HighPart = ftFirst .dwHighDateTime;
                           ULARGE_INTEGER iSecond; iSecond.LowPart = ftSecond.dwLowDateTime; iSecond.HighPart = ftSecond.dwHighDateTime;
                           ULONGLONG lDiff = iSecond.QuadPart - iFirst.QuadPart; // в десятках наносекунд
                           float fDiff = float(int(lDiff))/10000.f;
                           strReportDecode_My.Format(_T(">   Writed decode data (My)  -> %s; time - %.3f millisecond\r\n"), bRes ? _T("Ok") : _T("Err"), fDiff);
                        }
                        delete [] pDecodeBuff; pDecodeBuff = NULL;
                     }
                  }
               }
            }
            delete [] szFileData; szFileData = NULL;
         }
      }
      ::CloseHandle(hFileOutAPI); hFileOutAPI = NULL;
      ::CloseHandle(hFileOutMy ); hFileOutMy  = NULL;
      ::CloseHandle(hFileIn    ); hFileIn     = NULL;
   }
   /**/
   ::OutputDebugString(strReportDecode_API);
   ::OutputDebugString(strReportDecode_My);

   ::MessageBox(::GetDesktopWindow(), strReportCode_API+strReportCode_My+strReportDecode_API+strReportDecode_My, _T("Report"), MB_OK+MB_ICONINFORMATION);

   return 0;
}
   


Hosted by uCoz