/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include #include #include "errno.h" #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) #include #include #endif #ifdef _LINUX #include #include #include #include #include #endif #ifdef _MAC #include #endif #if defined(__APPLE__) || defined(__NetBSD__) #define st_atim st_atimespec #define st_ctim st_ctimespec #define st_mtim st_mtimespec #endif #ifndef MAX_PATH #define MAX_PATH 1024 #endif #define READ_WRITE_FULL_BUFFER_SIZE 10000000 // 10mb #ifdef __ANDROID__ #define READ_WRITE_FULL #define USE_LINUX_SENDFILE_INSTEAD_STREAMS // Available since API level 21. // iostream operation throwing exception when exceptions not enabled #endif #ifdef USE_LINUX_SENDFILE_INSTEAD_STREAMS #include #include #include #endif // реализация возможности подмены определения GetTempPath std::wstring g_overrideTmpPath = L""; #include "File.h" #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) #include #include std::wstring CorrectPathW(const std::wstring& path) { int len = (int)path.length(); if (2 > len) return path; const wchar_t* path_str = path.c_str(); if (path_str[0] == '\\' || path_str[1] == '/') return path; // local files: '\\?\' prefix // server files: '\\?\UNC\' prefix <== TODO! int nLen = GetFullPathNameW(path_str, 0, 0, 0); wchar_t* pBuf = new wchar_t[(4 + nLen) * sizeof(wchar_t)]; pBuf[0] = L'\\', pBuf[1] = L'\\', pBuf[2] = L'?', pBuf[3] = L'\\'; GetFullPathNameW(path_str, nLen, pBuf + 4, NULL); std::wstring retPath(pBuf); delete [] pBuf; return retPath; } #else std::wstring CorrectPathW(const std::wstring& path) { return path; } #endif namespace NSFile { std::wstring CUtf8Converter::GetUnicodeFromCharPtr(const char* pData, LONG lCount, INT bIsUtf8) { if (bIsUtf8) return GetUnicodeStringFromUTF8((BYTE*)pData, lCount); wchar_t* pUnicode = new wchar_t[lCount + 1]; for (LONG i = 0; i < lCount; ++i) pUnicode[i] = (wchar_t)(BYTE)pData[i]; pUnicode[lCount] = 0; std::wstring s(pUnicode, lCount); RELEASEARRAYOBJECTS(pUnicode); return s; } std::wstring CUtf8Converter::GetUnicodeFromCharPtr(const std::string& sParam, INT bIsUtf8) { return GetUnicodeFromCharPtr(sParam.c_str(), (LONG)sParam.length(), bIsUtf8); } LONG CUtf8Converter::GetUnicodeStringFromUTF8BufferSize(LONG lCount) { return lCount + 1; } std::wstring CUtf8Converter::GetUnicodeStringFromUTF8_4bytes( BYTE* pBuffer, LONG lCount ) { std::wstring strRes; GetUnicodeStringFromUTF8_4bytes(pBuffer, lCount, strRes); return strRes; } std::wstring CUtf8Converter::GetUnicodeStringFromUTF8_2bytes( BYTE* pBuffer, LONG lCount ) { std::wstring strRes; GetUnicodeStringFromUTF8_2bytes(pBuffer, lCount, strRes); return strRes; } std::wstring CUtf8Converter::GetUnicodeStringFromUTF8( BYTE* pBuffer, LONG lCount ) { std::wstring strRes; GetUnicodeStringFromUTF8(pBuffer, lCount, strRes); return strRes; } void CUtf8Converter::GetUnicodeStringFromUTF8_4bytes( BYTE* pBuffer, LONG lCount, std::wstring& sOutput ) { WCHAR* pUnicodeString = new WCHAR[lCount + 1]; LONG lIndexUnicode = 0; LONG lIndex = 0; while (lIndex < lCount) { BYTE byteMain = pBuffer[lIndex]; if (0x00 == (byteMain & 0x80)) { // 1 byte pUnicodeString[lIndexUnicode++] = (WCHAR)byteMain; ++lIndex; } else if (0x00 == (byteMain & 0x20)) { // 2 byte int val = 0; if ((lIndex + 1) < lCount) { val = (int)(((byteMain & 0x1F) << 6) | (pBuffer[lIndex + 1] & 0x3F)); } pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 2; } else if (0x00 == (byteMain & 0x10)) { // 3 byte int val = 0; if ((lIndex + 2) < lCount) { val = (int)(((byteMain & 0x0F) << 12) | ((pBuffer[lIndex + 1] & 0x3F) << 6) | (pBuffer[lIndex + 2] & 0x3F)); } pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 3; } else if (0x00 == (byteMain & 0x0F)) { // 4 byte int val = 0; if ((lIndex + 3) < lCount) { val = (int)(((byteMain & 0x07) << 18) | ((pBuffer[lIndex + 1] & 0x3F) << 12) | ((pBuffer[lIndex + 2] & 0x3F) << 6) | (pBuffer[lIndex + 3] & 0x3F)); } pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 4; } else if (0x00 == (byteMain & 0x08)) { // 4 byte int val = 0; if ((lIndex + 3) < lCount) { val = (int)(((byteMain & 0x07) << 18) | ((pBuffer[lIndex + 1] & 0x3F) << 12) | ((pBuffer[lIndex + 2] & 0x3F) << 6) | (pBuffer[lIndex + 3] & 0x3F)); } pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 4; } else if (0x00 == (byteMain & 0x04)) { // 5 byte int val = 0; if ((lIndex + 4) < lCount) { val = (int)(((byteMain & 0x03) << 24) | ((pBuffer[lIndex + 1] & 0x3F) << 18) | ((pBuffer[lIndex + 2] & 0x3F) << 12) | ((pBuffer[lIndex + 3] & 0x3F) << 6) | (pBuffer[lIndex + 4] & 0x3F)); } pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 5; } else { // 6 byte int val = 0; if ((lIndex + 5) < lCount) { val = (int)(((byteMain & 0x01) << 30) | ((pBuffer[lIndex + 1] & 0x3F) << 24) | ((pBuffer[lIndex + 2] & 0x3F) << 18) | ((pBuffer[lIndex + 3] & 0x3F) << 12) | ((pBuffer[lIndex + 4] & 0x3F) << 6) | (pBuffer[lIndex + 5] & 0x3F)); } pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 6; } } pUnicodeString[lIndexUnicode] = 0; sOutput.append(pUnicodeString); delete [] pUnicodeString; } void CUtf8Converter::GetUnicodeStringFromUTF8_2bytes( BYTE* pBuffer, LONG lCount, std::wstring& sOutput ) { WCHAR* pUnicodeString = new WCHAR[lCount + 1]; WCHAR* pStart = pUnicodeString; LONG lIndex = 0; while (lIndex < lCount) { BYTE byteMain = pBuffer[lIndex]; if (0x00 == (byteMain & 0x80)) { // 1 byte *pUnicodeString++ = (WCHAR)byteMain; ++lIndex; } else if (0x00 == (byteMain & 0x20)) { // 2 byte int val = 0; if ((lIndex + 1) < lCount) { val = (int)(((byteMain & 0x1F) << 6) | (pBuffer[lIndex + 1] & 0x3F)); } *pUnicodeString++ = (WCHAR)(val); lIndex += 2; } else if (0x00 == (byteMain & 0x10)) { // 3 byte int val = 0; if ((lIndex + 2) < lCount) { val = (int)(((byteMain & 0x0F) << 12) | ((pBuffer[lIndex + 1] & 0x3F) << 6) | (pBuffer[lIndex + 2] & 0x3F)); } WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 3; } else if (0x00 == (byteMain & 0x0F)) { // 4 byte int val = 0; if ((lIndex + 3) < lCount) { val = (int)(((byteMain & 0x07) << 18) | ((pBuffer[lIndex + 1] & 0x3F) << 12) | ((pBuffer[lIndex + 2] & 0x3F) << 6) | (pBuffer[lIndex + 3] & 0x3F)); } WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 4; } else if (0x00 == (byteMain & 0x08)) { // 4 byte int val = 0; if ((lIndex + 3) < lCount) { val = (int)(((byteMain & 0x07) << 18) | ((pBuffer[lIndex + 1] & 0x3F) << 12) | ((pBuffer[lIndex + 2] & 0x3F) << 6) | (pBuffer[lIndex + 3] & 0x3F)); } WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 4; } else if (0x00 == (byteMain & 0x04)) { // 5 byte int val = 0; if ((lIndex + 4) < lCount) { val = (int)(((byteMain & 0x03) << 24) | ((pBuffer[lIndex + 1] & 0x3F) << 18) | ((pBuffer[lIndex + 2] & 0x3F) << 12) | ((pBuffer[lIndex + 3] & 0x3F) << 6) | (pBuffer[lIndex + 4] & 0x3F)); } WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 5; } else { // 6 byte int val = 0; if ((lIndex + 5) < lCount) { val = (int)(((byteMain & 0x01) << 30) | ((pBuffer[lIndex + 1] & 0x3F) << 24) | ((pBuffer[lIndex + 2] & 0x3F) << 18) | ((pBuffer[lIndex + 3] & 0x3F) << 12) | ((pBuffer[lIndex + 4] & 0x3F) << 6) | (pBuffer[lIndex + 5] & 0x3F)); } WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 5; } } *pUnicodeString++ = 0; sOutput.append(pStart); delete [] pStart; } void CUtf8Converter::GetUnicodeStringFromUTF8( BYTE* pBuffer, LONG lCount, std::wstring& sOutput ) { if (sizeof(WCHAR) == 2) GetUnicodeStringFromUTF8_2bytes(pBuffer, lCount, sOutput); else GetUnicodeStringFromUTF8_4bytes(pBuffer, lCount, sOutput); } #define CHECK_HHHH(pBuffer) \ wchar_t code = 0; \ if('_' == pBuffer[0] && 'x' == pBuffer[1] && 0 != pBuffer[2] && 0 != pBuffer[3] && 0 != pBuffer[4] && 0 != pBuffer[5] && '_' == pBuffer[6]) \ { \ int i = 2; \ for(; i < 6; ++i) \ { \ code *= 16; \ if('0' <= pBuffer[i] && pBuffer[i] <= '9') \ { \ code += pBuffer[i] - '0'; \ } \ else if('A' <= pBuffer[i] && pBuffer[i] <= 'F') \ { \ code += pBuffer[i] - 'A' + 10; \ } \ else if('a' <= pBuffer[i] && pBuffer[i] <= 'f') \ { \ code += pBuffer[i] - 'a' + 10; \ } \ else \ { \ break; \ } \ } \ if(i == 6) \ { \ if(0x005F == code) \ { \ code = '_'; \ } \ return code; \ } \ } \ return -1; long CUtf8Converter::CheckHHHHChar(const BYTE* pBuffer) { CHECK_HHHH(pBuffer); } long CUtf8Converter::CheckHHHHChar(const wchar_t* pBuffer) { CHECK_HHHH(pBuffer); } void CUtf8Converter::GetUnicodeStringFromUTF8WithHHHH_4bytes( const BYTE* pBuffer, LONG lCount, wchar_t*& pUnicodes, LONG& lOutputCount ) { if (NULL == pUnicodes) { pUnicodes = new wchar_t[GetUnicodeStringFromUTF8BufferSize(lCount)]; } WCHAR* pUnicodeString = pUnicodes; LONG lIndexUnicode = 0; LONG lIndex = 0; while (lIndex < lCount) { BYTE byteMain = pBuffer[lIndex]; if (0x00 == (byteMain & 0x80)) { // 1 byte long code = CheckHHHHChar(pBuffer + lIndex); if(code < 0) { pUnicodeString[lIndexUnicode++] = (WCHAR)byteMain; ++lIndex; } else { pUnicodeString[lIndexUnicode++] = (WCHAR)code; lIndex += 7; } } else if (0x00 == (byteMain & 0x20)) { // 2 byte int val = (int)(((byteMain & 0x1F) << 6) | (pBuffer[lIndex + 1] & 0x3F)); pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 2; } else if (0x00 == (byteMain & 0x10)) { // 3 byte int val = (int)(((byteMain & 0x0F) << 12) | ((pBuffer[lIndex + 1] & 0x3F) << 6) | (pBuffer[lIndex + 2] & 0x3F)); pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 3; } else if (0x00 == (byteMain & 0x0F)) { // 4 byte int val = (int)(((byteMain & 0x07) << 18) | ((pBuffer[lIndex + 1] & 0x3F) << 12) | ((pBuffer[lIndex + 2] & 0x3F) << 6) | (pBuffer[lIndex + 3] & 0x3F)); pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 4; } else if (0x00 == (byteMain & 0x08)) { // 4 byte int val = (int)(((byteMain & 0x07) << 18) | ((pBuffer[lIndex + 1] & 0x3F) << 12) | ((pBuffer[lIndex + 2] & 0x3F) << 6) | (pBuffer[lIndex + 3] & 0x3F)); pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 4; } else if (0x00 == (byteMain & 0x04)) { // 5 byte int val = (int)(((byteMain & 0x03) << 24) | ((pBuffer[lIndex + 1] & 0x3F) << 18) | ((pBuffer[lIndex + 2] & 0x3F) << 12) | ((pBuffer[lIndex + 3] & 0x3F) << 6) | (pBuffer[lIndex + 4] & 0x3F)); pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 5; } else { // 6 byte int val = (int)(((byteMain & 0x01) << 30) | ((pBuffer[lIndex + 1] & 0x3F) << 24) | ((pBuffer[lIndex + 2] & 0x3F) << 18) | ((pBuffer[lIndex + 3] & 0x3F) << 12) | ((pBuffer[lIndex + 4] & 0x3F) << 6) | (pBuffer[lIndex + 5] & 0x3F)); pUnicodeString[lIndexUnicode++] = (WCHAR)(val); lIndex += 5; } } pUnicodeString[lIndexUnicode] = 0; lOutputCount = lIndexUnicode; } void CUtf8Converter::GetUnicodeStringFromUTF8WithHHHH_2bytes( const BYTE* pBuffer, LONG lCount, wchar_t*& pUnicodes, LONG& lOutputCount ) { if (NULL == pUnicodes) { pUnicodes = new wchar_t[GetUnicodeStringFromUTF8BufferSize(lCount)]; } WCHAR* pUnicodeString = pUnicodes; WCHAR* pStart = pUnicodeString; LONG lIndex = 0; while (lIndex < lCount) { BYTE byteMain = pBuffer[lIndex]; if (0x00 == (byteMain & 0x80)) { // 1 byte long code = CheckHHHHChar(pBuffer + lIndex); if(code < 0) { *pUnicodeString++ = (WCHAR)byteMain; ++lIndex; } else { *pUnicodeString++ = (WCHAR)code; lIndex += 7; } } else if (0x00 == (byteMain & 0x20)) { // 2 byte int val = (int)(((byteMain & 0x1F) << 6) | (pBuffer[lIndex + 1] & 0x3F)); *pUnicodeString++ = (WCHAR)(val); lIndex += 2; } else if (0x00 == (byteMain & 0x10)) { // 3 byte int val = (int)(((byteMain & 0x0F) << 12) | ((pBuffer[lIndex + 1] & 0x3F) << 6) | (pBuffer[lIndex + 2] & 0x3F)); WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 3; } else if (0x00 == (byteMain & 0x0F)) { // 4 byte int val = (int)(((byteMain & 0x07) << 18) | ((pBuffer[lIndex + 1] & 0x3F) << 12) | ((pBuffer[lIndex + 2] & 0x3F) << 6) | (pBuffer[lIndex + 3] & 0x3F)); WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 4; } else if (0x00 == (byteMain & 0x08)) { // 4 byte int val = (int)(((byteMain & 0x07) << 18) | ((pBuffer[lIndex + 1] & 0x3F) << 12) | ((pBuffer[lIndex + 2] & 0x3F) << 6) | (pBuffer[lIndex + 3] & 0x3F)); WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 4; } else if (0x00 == (byteMain & 0x04)) { // 5 byte int val = (int)(((byteMain & 0x03) << 24) | ((pBuffer[lIndex + 1] & 0x3F) << 18) | ((pBuffer[lIndex + 2] & 0x3F) << 12) | ((pBuffer[lIndex + 3] & 0x3F) << 6) | (pBuffer[lIndex + 4] & 0x3F)); WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 5; } else { // 6 byte int val = (int)(((byteMain & 0x01) << 30) | ((pBuffer[lIndex + 1] & 0x3F) << 24) | ((pBuffer[lIndex + 2] & 0x3F) << 18) | ((pBuffer[lIndex + 3] & 0x3F) << 12) | ((pBuffer[lIndex + 4] & 0x3F) << 6) | (pBuffer[lIndex + 5] & 0x3F)); WriteUtf16_WCHAR(val, pUnicodeString); lIndex += 5; } } lOutputCount = (LONG)(pUnicodeString - pStart); *pUnicodeString++ = 0; } void CUtf8Converter::GetUnicodeStringFromUTF8WithHHHH( const BYTE* pBuffer, LONG lCount, wchar_t*& pUnicodes, LONG& lOutputCount ) { if (sizeof(WCHAR) == 2) return GetUnicodeStringFromUTF8WithHHHH_2bytes(pBuffer, lCount, pUnicodes, lOutputCount); return GetUnicodeStringFromUTF8WithHHHH_4bytes(pBuffer, lCount, pUnicodes, lOutputCount); } void CUtf8Converter::GetUtf8StringFromUnicode_4bytes(const wchar_t* pUnicodes, LONG lCount, BYTE*& pData, LONG& lOutputCount, bool bIsBOM) { if (NULL == pData) { pData = new BYTE[6 * lCount + 3 + 1 ]; } BYTE* pCodesCur = pData; if (bIsBOM) { pCodesCur[0] = 0xEF; pCodesCur[1] = 0xBB; pCodesCur[2] = 0xBF; pCodesCur += 3; } const wchar_t* pEnd = pUnicodes + lCount; const wchar_t* pCur = pUnicodes; while (pCur < pEnd) { unsigned int code = (unsigned int)*pCur++; if (code < 0x80) { *pCodesCur++ = (BYTE)code; } else if (code < 0x0800) { *pCodesCur++ = 0xC0 | (code >> 6); *pCodesCur++ = 0x80 | (code & 0x3F); } else if (code < 0x10000) { *pCodesCur++ = 0xE0 | (code >> 12); *pCodesCur++ = 0x80 | (code >> 6 & 0x3F); *pCodesCur++ = 0x80 | (code & 0x3F); } else if (code < 0x1FFFFF) { *pCodesCur++ = 0xF0 | (code >> 18); *pCodesCur++ = 0x80 | (code >> 12 & 0x3F); *pCodesCur++ = 0x80 | (code >> 6 & 0x3F); *pCodesCur++ = 0x80 | (code & 0x3F); } else if (code < 0x3FFFFFF) { *pCodesCur++ = 0xF8 | (code >> 24); *pCodesCur++ = 0x80 | (code >> 18 & 0x3F); *pCodesCur++ = 0x80 | (code >> 12 & 0x3F); *pCodesCur++ = 0x80 | (code >> 6 & 0x3F); *pCodesCur++ = 0x80 | (code & 0x3F); } else if (code < 0x7FFFFFFF) { *pCodesCur++ = 0xFC | (code >> 30); *pCodesCur++ = 0x80 | (code >> 24 & 0x3F); *pCodesCur++ = 0x80 | (code >> 18 & 0x3F); *pCodesCur++ = 0x80 | (code >> 12 & 0x3F); *pCodesCur++ = 0x80 | (code >> 6 & 0x3F); *pCodesCur++ = 0x80 | (code & 0x3F); } } lOutputCount = (LONG)(pCodesCur - pData); *pCodesCur++ = 0; } void CUtf8Converter::GetUtf8StringFromUnicode_2bytes(const wchar_t* pUnicodes, LONG lCount, BYTE*& pData, LONG& lOutputCount, bool bIsBOM) { if (NULL == pData) { pData = new BYTE[6 * lCount + 3 + 1]; } BYTE* pCodesCur = pData; if (bIsBOM) { pCodesCur[0] = 0xEF; pCodesCur[1] = 0xBB; pCodesCur[2] = 0xBF; pCodesCur += 3; } const wchar_t* pEnd = pUnicodes + lCount; const wchar_t* pCur = pUnicodes; while (pCur < pEnd) { unsigned int code = (unsigned int)*pCur++; if (code >= 0xD800 && code <= 0xDFFF && pCur < pEnd) { code = 0x10000 + (((code & 0x3FF) << 10) | (0x03FF & *pCur++)); } if (code < 0x80) { *pCodesCur++ = (BYTE)code; } else if (code < 0x0800) { *pCodesCur++ = 0xC0 | (code >> 6); *pCodesCur++ = 0x80 | (code & 0x3F); } else if (code < 0x10000) { *pCodesCur++ = 0xE0 | (code >> 12); *pCodesCur++ = 0x80 | ((code >> 6) & 0x3F); *pCodesCur++ = 0x80 | (code & 0x3F); } else if (code < 0x1FFFFF) { *pCodesCur++ = 0xF0 | (code >> 18); *pCodesCur++ = 0x80 | ((code >> 12) & 0x3F); *pCodesCur++ = 0x80 | ((code >> 6) & 0x3F); *pCodesCur++ = 0x80 | (code & 0x3F); } else if (code < 0x3FFFFFF) { *pCodesCur++ = 0xF8 | (code >> 24); *pCodesCur++ = 0x80 | ((code >> 18) & 0x3F); *pCodesCur++ = 0x80 | ((code >> 12) & 0x3F); *pCodesCur++ = 0x80 | ((code >> 6) & 0x3F); *pCodesCur++ = 0x80 | (code & 0x3F); } else if (code < 0x7FFFFFFF) { *pCodesCur++ = 0xFC | (code >> 30); *pCodesCur++ = 0x80 | ((code >> 24) & 0x3F); *pCodesCur++ = 0x80 | ((code >> 18) & 0x3F); *pCodesCur++ = 0x80 | ((code >> 12) & 0x3F); *pCodesCur++ = 0x80 | ((code >> 6) & 0x3F); *pCodesCur++ = 0x80 | (code & 0x3F); } } lOutputCount = (LONG)(pCodesCur - pData); *pCodesCur++ = 0; } void CUtf8Converter::GetUtf8StringFromUnicode(const wchar_t* pUnicodes, LONG lCount, BYTE*& pData, LONG& lOutputCount, bool bIsBOM) { if (NULL == pUnicodes || 0 == lCount) { pData = NULL; lOutputCount = 0; return; } if (sizeof(WCHAR) == 2) return GetUtf8StringFromUnicode_2bytes(pUnicodes, lCount, pData, lOutputCount, bIsBOM); return GetUtf8StringFromUnicode_4bytes(pUnicodes, lCount, pData, lOutputCount, bIsBOM); } std::string CUtf8Converter::GetUtf8StringFromUnicode2(const wchar_t* pUnicodes, LONG lCount, bool bIsBOM) { if (NULL == pUnicodes || 0 == lCount) return ""; BYTE* pData = NULL; LONG lLen = 0; GetUtf8StringFromUnicode(pUnicodes, lCount, pData, lLen, bIsBOM); std::string s((char*)pData, lLen); RELEASEARRAYOBJECTS(pData); return s; } std::string CUtf8Converter::GetUtf8StringFromUnicode(const std::wstring& sData) { return GetUtf8StringFromUnicode2(sData.c_str(), (LONG)sData.length()); } // utf16 void CUtf8Converter::GetUtf16StringFromUnicode_4bytes(const wchar_t* pUnicodes, LONG lCount, BYTE*& pData, int& lOutputCount, bool bIsBOM) { if (NULL == pData) { pData = new BYTE[4 * lCount + 3 + 2]; } BYTE* pCodesCur = pData; if (bIsBOM) { pCodesCur[0] = 0xEF; pCodesCur[1] = 0xBB; pCodesCur[2] = 0xBF; pCodesCur += 3; } const wchar_t* pEnd = pUnicodes + lCount; const wchar_t* pCur = pUnicodes; while (pCur < pEnd) { unsigned int code = (unsigned int)*pCur++; if (code <= 0xFFFF) { USHORT usCode = (USHORT)(code & 0xFFFF); memcpy(pCodesCur, &usCode, 2); pCodesCur += 2; } else { code -= 0x10000; code &= 0xFFFFF; USHORT us1 = 0xD800 | ((code >> 10) & 0x03FF); USHORT us2 = 0xDC00 | (code & 0x03FF); memcpy(pCodesCur, &us1, 2); pCodesCur += 2; memcpy(pCodesCur, &us2, 2); pCodesCur += 2; } } lOutputCount = (LONG)(pCodesCur - pData); *pCodesCur++ = 0; *pCodesCur++ = 0; } void CUtf8Converter::GetUtf16StringFromUnicode_4bytes2(const wchar_t* pUnicodes, LONG lCount, CStringUtf16& data) { GetUtf16StringFromUnicode_4bytes(pUnicodes, lCount, data.Data, data.Length); } long CUtf8Converter::GetUtf16SizeFromUnicode_4bytes(const wchar_t* pUnicodes, LONG lCount, bool bIsBOM) { long sizeUtf16 = 0; if (bIsBOM) { sizeUtf16 += 3; } const wchar_t* pEnd = pUnicodes + lCount; const wchar_t* pCur = pUnicodes; while (pCur < pEnd) { unsigned int code = (unsigned int)*pCur++; if (code <= 0xFFFF) { sizeUtf16 += 2; } else { sizeUtf16 += 4; } } return sizeUtf16; } long CUtf8Converter::GetUtf16SizeFromUnicode(const wchar_t* pUnicodes, LONG lCount, bool bIsBOM) { if (sizeof(wchar_t) == 4) { return GetUtf16SizeFromUnicode_4bytes(pUnicodes, lCount, bIsBOM); } else { long sizeUtf16 = 2 * lCount; if (bIsBOM) { sizeUtf16 += 3; } return sizeUtf16; } } std::wstring CUtf8Converter::GetWStringFromUTF16(const CStringUtf16& data) { if (0 == data.Length) return L""; if (sizeof(wchar_t) == 2) return std::wstring((wchar_t*)data.Data, data.Length / 2); int nCount = data.Length / 2; USHORT* pShort = (USHORT*)data.Data; wchar_t* pWChar = new wchar_t[nCount + 1]; wchar_t* pWCurrent = pWChar; int nCurrent = 0; while (nCurrent < nCount) { if (*pShort < 0xD800 || *pShort > 0xDBFF) { *pWCurrent = (wchar_t)(*pShort); ++pShort; ++nCurrent; } else { *pWCurrent = (wchar_t)(((((pShort[0] - 0xD800) & 0x03FF) << 10) | ((pShort[1] - 0xDC00) & 0x03FF)) + 0x10000); pShort += 2; nCurrent += 2; } ++pWCurrent; } std::wstring sRet(pWChar, pWCurrent - pWChar); RELEASEARRAYOBJECTS(pWChar); return sRet; } std::wstring CUtf8Converter::GetWStringFromUTF16(const unsigned short* pUtf16, LONG lCount) { CStringUtf16 oString; oString.Data = (BYTE*)pUtf16; oString.Length = lCount * 2; std::wstring wsResult = GetWStringFromUTF16(oString); oString.Data = NULL; return wsResult; } } namespace NSFile { CFileBinary::CFileBinary() { m_pFile = NULL; m_lFilePosition = 0; m_lFileSize = 0; } CFileBinary::~CFileBinary() { CloseFile(); } void CFileBinary::CloseFile() { m_lFilePosition = 0; m_lFileSize = 0; if (m_pFile != NULL) { fclose(m_pFile); m_pFile = NULL; } } FILE* CFileBinary::GetFileNative() { return m_pFile; } long CFileBinary::GetFileSize() { return m_lFileSize; } long CFileBinary::GetFilePosition() { if (!m_pFile) return 0; m_lFilePosition = ftell(m_pFile); return m_lFilePosition; } unsigned long CFileBinary::GetPosition() { if (!m_pFile) return 0; m_lFilePosition = ftell(m_pFile); return (unsigned long)m_lFilePosition; } bool CFileBinary::OpenFile(const std::wstring& sFileName, bool bRewrite) { #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) if ( NULL == (m_pFile = _wfsopen( sFileName.c_str(), bRewrite ? L"rb+" : L"rb", _SH_DENYNO))) return false; #else #ifdef _IOS std::string sFilePath = NSIOS::GetFileSystemRepresentation(sFileName); m_pFile = fopen((char*)sFilePath.c_str(), bRewrite ? "rb+" : "rb"); #else BYTE* pUtf8 = NULL; LONG lLen = 0; CUtf8Converter::GetUtf8StringFromUnicode(sFileName.c_str(), sFileName.length(), pUtf8, lLen, false); struct stat st; if ((0 == stat((char*)pUtf8, &st)) && S_ISDIR(st.st_mode)) return false; m_pFile = fopen((char*)pUtf8, bRewrite ? "rb+" : "rb"); delete [] pUtf8; #endif #endif if (NULL == m_pFile) return false; fseek(m_pFile, 0, SEEK_END); m_lFileSize = ftell(m_pFile); fseek(m_pFile, 0, SEEK_SET); m_lFilePosition = 0; if (0 < sFileName.length()) { if (((wchar_t)'/') == sFileName.c_str()[sFileName.length() - 1]) m_lFileSize = 0x7FFFFFFF; } unsigned int err = 0x7FFFFFFF; unsigned int cur = (unsigned int)m_lFileSize; if (err == cur) { CloseFile(); return false; } return true; } bool CFileBinary::CreateFileW(const std::wstring& sFileName) { #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) if ( 0 != _wfopen_s(&m_pFile, sFileName.c_str(), L"wb")) return false; #else #ifdef _IOS std::string sFilePath = NSIOS::GetFileSystemRepresentation(sFileName); m_pFile = fopen((char*)sFilePath.c_str(), "wb"); #else BYTE* pUtf8 = NULL; LONG lLen = 0; CUtf8Converter::GetUtf8StringFromUnicode(sFileName.c_str(), sFileName.length(), pUtf8, lLen, false); m_pFile = fopen((char*)pUtf8, "wb"); delete [] pUtf8; #endif #endif if (NULL == m_pFile) return false; m_lFilePosition = 0; return true; } bool CFileBinary::CreateFile(const std::wstring& sFileName) { return CreateFileW(sFileName); } bool CFileBinary::CreateTempFile() { #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) if (0 != tmpfile_s(&m_pFile)) return false; #else m_pFile = tmpfile(); if (NULL == m_pFile) return false; #endif m_lFilePosition = 0; return true; } bool CFileBinary::SeekFile(int lFilePosition, int nSeekMode) { if (!m_pFile) return false; m_lFilePosition = fseek(m_pFile, lFilePosition, nSeekMode); return true; } bool CFileBinary::SetPosition(int lFilePosition) { return SeekFile(lFilePosition, SEEK_SET); } bool CFileBinary::ReadFile(BYTE* pData, DWORD nBytesToRead) { if (!m_pFile) return false; DWORD dwSizeRead = (DWORD)fread((void*)pData, 1, nBytesToRead, m_pFile); return (dwSizeRead == nBytesToRead) ? true : false; } bool CFileBinary::ReadFile(BYTE* pData, DWORD nBytesToRead, DWORD& dwSizeRead) { if (!m_pFile) return false; dwSizeRead = (DWORD)fread((void*)pData, 1, nBytesToRead, m_pFile); return true; } bool CFileBinary::WriteFile(const void* pData, DWORD nBytesCount) { if (!m_pFile) return false; size_t nCountWrite = fwrite(pData, 1, nBytesCount, m_pFile); return true; } bool CFileBinary::WriteFile(const BYTE* pData, DWORD nBytesCount) { return WriteFile((const void*)pData, nBytesCount); } bool CFileBinary::WriteFile2(const BYTE* pData, DWORD nBytesToWrite) { if (!m_pFile) return false; BYTE* mem = new BYTE[nBytesToWrite]; memcpy(mem, pData, nBytesToWrite); for (size_t index = 0; index < nBytesToWrite / 2; ++index) { BYTE temp = mem[index]; mem[index] = mem[nBytesToWrite - index - 1]; mem[nBytesToWrite - index - 1] = temp; } bool bRes = WriteFile(mem, nBytesToWrite); RELEASEARRAYOBJECTS(mem); return bRes; } long CFileBinary::TellFile() { if (!m_pFile) return 0; return ftell(m_pFile); } long CFileBinary::SizeFile() { if (!m_pFile) return 0; long lPos = TellFile(); fseek(m_pFile, 0, SEEK_END); m_lFileSize = ftell(m_pFile); fseek(m_pFile, lPos, SEEK_SET); return m_lFileSize; } void CFileBinary::WriteStringUTF8(const std::wstring& strXml, bool bIsBOM) { BYTE* pData = NULL; LONG lLen = 0; CUtf8Converter::GetUtf8StringFromUnicode(strXml.c_str(), (LONG)strXml.length(), pData, lLen, bIsBOM); WriteFile(pData, lLen); RELEASEARRAYOBJECTS(pData); } bool CFileBinary::WriteReserved(DWORD dwCount) { BYTE* buf = new BYTE[dwCount]; memset(buf, 0, (size_t)dwCount); bool hr = WriteFile(buf, dwCount); RELEASEARRAYOBJECTS(buf); return hr; } bool CFileBinary::WriteReserved2(DWORD dwCount) { BYTE* buf = new BYTE[dwCount]; memset(buf, 0xFF, (size_t)dwCount); bool hr = WriteFile(buf, dwCount); RELEASEARRAYOBJECTS(buf); return hr; } bool CFileBinary::WriteReservedTo(DWORD dwPoint) { if ((DWORD)m_lFilePosition >= dwPoint) return S_OK; DWORD dwCount = dwPoint - (DWORD)m_lFilePosition; BYTE* buf = new BYTE[dwCount]; memset(buf, 0, (size_t)dwCount); bool hr = WriteFile(buf, dwCount); RELEASEARRAYOBJECTS(buf); return hr; } bool CFileBinary::SkipReservedTo(DWORD dwPoint) { if ((DWORD)m_lFilePosition >= dwPoint) return S_OK; DWORD dwCount = dwPoint - (DWORD)m_lFilePosition; return SkipBytes(dwCount); } LONG CFileBinary::GetProgress() { if (0 >= m_lFileSize) return -1; double dVal = (double)(100 * m_lFilePosition); LONG lProgress = (LONG)(dVal / m_lFileSize); return lProgress; } bool CFileBinary::SkipBytes(ULONG nCount) { return SeekFile(m_lFilePosition + nCount); } bool CFileBinary::ReadAllBytes(const std::wstring& strFileName, BYTE** ppData, DWORD& nBytesCount) { *ppData = NULL; nBytesCount = 0; bool bRes = false; CFileBinary oFileBinary; if (oFileBinary.OpenFile(strFileName)) { long nFileSize = oFileBinary.GetFileSize(); BYTE* pData = new BYTE[nFileSize]; DWORD dwSizeRead; if (oFileBinary.ReadFile(pData, nFileSize, dwSizeRead)) { oFileBinary.CloseFile(); *ppData = pData; nBytesCount = dwSizeRead; bRes = true; } else RELEASEARRAYOBJECTS(pData); } return bRes; } bool CFileBinary::ReadAllTextUtf8(const std::wstring& strFileName, std::wstring& sData) { bool bRes = false; BYTE* pData = NULL; DWORD nDataSize; if (CFileBinary::ReadAllBytes(strFileName, &pData, nDataSize)) { //remove BOM if exist BYTE* pDataStart = pData; DWORD nBOMSize = 3; if (nDataSize > nBOMSize && 0xef == pDataStart[0] && 0xbb == pDataStart[1] && 0xbf == pDataStart[2]) { pDataStart += nBOMSize; nDataSize -= nBOMSize; } sData = CUtf8Converter::GetUnicodeStringFromUTF8(pDataStart, nDataSize); RELEASEARRAYOBJECTS(pData); bRes = true; } return bRes; } bool CFileBinary::ReadAllTextUtf8A(const std::wstring& strFileName, std::string& sData) { bool bRes = false; BYTE* pData = NULL; DWORD nDataSize; if (CFileBinary::ReadAllBytes(strFileName, &pData, nDataSize)) { //remove BOM if exist BYTE* pDataStart = pData; DWORD nBOMSize = 3; if (nDataSize > nBOMSize && 0xef == pDataStart[0] && 0xbb == pDataStart[1] && 0xbf == pDataStart[2]) { pDataStart += nBOMSize; nDataSize -= nBOMSize; } sData = std::string((char*)pDataStart, nDataSize); RELEASEARRAYOBJECTS(pData); bRes = true; } return bRes; } bool CFileBinary::SaveToFile(const std::wstring& strFileName, const std::wstring& strXml, bool bIsBOM) { CFileBinary oFile; oFile.CreateFileW(strFileName); oFile.WriteStringUTF8(strXml, bIsBOM); oFile.CloseFile(); return true; } bool CFileBinary::Exists(const std::wstring& strFileName) { #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) FILE* pFile = NULL; if ( NULL == (pFile = _wfsopen( strFileName.c_str(), L"rb", _SH_DENYNO))) return false; #else BYTE* pUtf8 = NULL; LONG lLen = 0; CUtf8Converter::GetUtf8StringFromUnicode(strFileName.c_str(), strFileName.length(), pUtf8, lLen, false); FILE* pFile = fopen((char*)pUtf8, "rb"); delete [] pUtf8; #endif if (NULL != pFile) { fclose(pFile); return true; } else return false; } bool CFileBinary::Copy(const std::wstring& strSrc, const std::wstring& strDst) { if (strSrc == strDst) return true; #ifdef READ_WRITE_FULL BYTE* pFileData = NULL; DWORD dwChunkSize = READ_WRITE_FULL_BUFFER_SIZE; CFileBinary oFileSrc; CFileBinary oFileDst; if (oFileSrc.OpenFile(strSrc) && oFileDst.CreateFileW(strDst)) { DWORD dwFileSrcSize = (DWORD)oFileSrc.GetFileSize(); if (dwChunkSize > dwFileSrcSize) dwChunkSize = dwFileSrcSize; BYTE* pTempBuffer = new BYTE[dwChunkSize]; DWORD dwProcessedBytes = 0; while (dwFileSrcSize != 0) { oFileSrc.ReadFile(pTempBuffer, dwChunkSize, dwProcessedBytes); if (dwProcessedBytes != dwChunkSize) break; if (!oFileDst.WriteFile(pTempBuffer, dwChunkSize)) break; dwFileSrcSize -= dwChunkSize; if (dwChunkSize > dwFileSrcSize) dwChunkSize = dwFileSrcSize; } oFileSrc.CloseFile(); oFileDst.CloseFile(); RELEASEARRAYOBJECTS(pTempBuffer); if (0 != dwFileSrcSize) Remove(strDst); else return true; } #endif #if !defined(_WIN32) && !defined(_WIN32_WCE) && !defined(_WIN64) std::string strSrcA = U_TO_UTF8(strSrc); std::string strDstA = U_TO_UTF8(strDst); #endif #ifdef USE_LINUX_SENDFILE_INSTEAD_STREAMS int src = open(strSrcA.c_str(), O_RDONLY); int dst = open(strDstA.c_str(), O_WRONLY | O_CREAT); // struct required, rationale: function stat() exists also struct stat stat_source; fstat(src, &stat_source); if (stat_source.st_size > 0x7FFFFFFF) return false; off_t offset = 0; long long file_size = stat_source.st_size; long long file_size_tmp = file_size; long long read_size = 0; long long read_size_marker = (long long)sendfile(dst, src, &offset, file_size_tmp); while (-1 != read_size_marker) { if (read_size == file_size) break; file_size_tmp -= read_size_marker; read_size += read_size_marker; if (read_size != file_size) read_size_marker = (long long)sendfile(dst, src, &offset, file_size_tmp); } close(src); close(dst); return (-1 != read_size_marker) ? true : false; #else #ifdef _WIN32 if (0 != ::CopyFileW(strSrc.c_str(), strDst.c_str(), 1)) return true; #endif std::ifstream src; std::ofstream dst; int nLenBuffer = 1024 * 1024; // 10 CFileBinary oFile; if (oFile.OpenFile(strSrc)) { int nFileSize = (int)oFile.GetFileSize(); if (nFileSize < nLenBuffer) nLenBuffer = nFileSize; oFile.CloseFile(); } else { #ifdef _WIN32 return (0 != ::CopyFileW(strSrc.c_str(), strDst.c_str(), 1)); #endif } char* pBuffer_in = NULL; char* pBuffer_out = NULL; if (nLenBuffer > 0) { pBuffer_in = new char[nLenBuffer]; pBuffer_out = new char[nLenBuffer]; src.rdbuf()->pubsetbuf(pBuffer_in, nLenBuffer); dst.rdbuf()->pubsetbuf(pBuffer_out, nLenBuffer); } #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) src.open(strSrc.c_str(), std::ios::binary); if (src.is_open()) dst.open(strDst.c_str(), std::ios::binary); #else src.open(strSrcA.c_str(), std::ios::binary); if (src.is_open()) dst.open(strDstA.c_str(), std::ios::binary); #endif bool bRet = false; if (src.is_open() && dst.is_open()) { dst << src.rdbuf(); src.close(); dst.close(); bRet = true; } RELEASEARRAYOBJECTS(pBuffer_in); RELEASEARRAYOBJECTS(pBuffer_out); return bRet; #endif } bool CFileBinary::Remove(const std::wstring& strFileName) { #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) int nRes = _wremove(strFileName.c_str()); #else BYTE* pUtf8 = NULL; LONG lLen = 0; CUtf8Converter::GetUtf8StringFromUnicode(strFileName.c_str(), strFileName.length(), pUtf8, lLen, false); int nRes = std::remove((char*)pUtf8); delete [] pUtf8; #endif return 0 == nRes; } bool CFileBinary::Move(const std::wstring& strSrc, const std::wstring& strDst) { if (strSrc == strDst) return true; if (Copy(strSrc, strDst)) if (Remove(strSrc)) return true; return false; } bool CFileBinary::Truncate(const std::wstring& sPath, size_t nNewSize) { bool bIsSuccess = false; #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) HANDLE hFile = ::CreateFileW( sPath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { return bIsSuccess; } LARGE_INTEGER Size = { 0 }; if ( GetFileSizeEx( hFile, &Size ) ) { LARGE_INTEGER Distance = { 0 }; // Negative values move the pointer backward in the file Distance.QuadPart = (LONGLONG)nNewSize - Size.QuadPart; bIsSuccess = (SetFilePointerEx(hFile, Distance, NULL, FILE_END) && SetEndOfFile(hFile)); } CloseHandle( hFile ); #else std::string sFileUTF8 = U_TO_UTF8(sPath); bIsSuccess = (0 == truncate(sFileUTF8.c_str(), nNewSize)); #endif return bIsSuccess; } bool CFileBinary::IsGlobalTempPathUse() { return g_overrideTmpPath.empty() ? false : true; } std::wstring CFileBinary::GetTempPath() { if (!g_overrideTmpPath.empty()) return g_overrideTmpPath; #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) wchar_t pBuffer[MAX_PATH + 1]; memset(pBuffer, 0, sizeof(wchar_t) * (MAX_PATH + 1)); ::GetTempPathW(MAX_PATH, pBuffer); std::wstring sRet(pBuffer); size_t nSeparatorPos = sRet.find_last_of(wchar_t('/')); if (std::wstring::npos == nSeparatorPos) { nSeparatorPos = sRet.find_last_of(wchar_t('\\')); } if (std::wstring::npos == nSeparatorPos) return L""; return sRet.substr(0, nSeparatorPos); #else char *folder = getenv("TEMP"); if (NULL == folder) folder = getenv("TMP"); if (NULL == folder) folder = getenv("TMPDIR"); if (NULL == folder) folder = "/tmp"; return NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)folder, strlen(folder)); #endif } std::wstring CFileBinary::CreateTempFileWithUniqueName(const std::wstring& strFolderPathRoot, const std::wstring& Prefix) { #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) wchar_t pBuffer[MAX_PATH + 1]; ::GetTempFileNameW(strFolderPathRoot.c_str(), Prefix.c_str(), 0, pBuffer); std::wstring sRet(pBuffer); return sRet; #else char pcRes[MAX_PATH]; BYTE* pData = (BYTE*)pcRes; std::wstring sPrefix = strFolderPathRoot + L"/" + Prefix + L"_XXXXXX"; LONG lLen = 0; NSFile::CUtf8Converter::GetUtf8StringFromUnicode(sPrefix.c_str(), (LONG)sPrefix.length(), pData, lLen); pcRes[lLen] = '\0'; int res = mkstemp(pcRes); if (-1 != res) close(res); std::string sRes = pcRes; return NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)sRes.c_str(), sRes.length()); #endif } bool CFileBinary::OpenTempFile(std::wstring *pwsName, FILE **ppFile, wchar_t *wsMode, wchar_t *wsExt, wchar_t *wsFolder, wchar_t* wsName) { // TODO: Реализовать когда wsName != NULL std::wstring wsTemp, wsFileName; FILE *pTempFile = NULL; #if defined(_WIN32) || defined (_WIN64) wchar_t *wsTempDir = NULL; size_t sz = 0; if ( (0 == _wdupenv_s(&wsTempDir, &sz, L"TEMP")) && (wsFolder == NULL)) { wsTemp = std::wstring(wsTempDir, sz-1); #else char *wsTempDirA; if ((wsTempDirA = getenv("TEMP")) && (wsFolder == NULL)) { std::wstring wsTempDir = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)wsTempDirA, strlen(wsTempDirA)); wsTemp = wsTempDir.c_str(); #endif wsTemp += L"/"; } else if (wsFolder != NULL) { wsTemp = std::wstring(wsFolder); wsTemp += L"/"; } else { wsTemp = L""; } #if defined(_WIN32) || defined (_WIN64) if (wsTempDir) free(wsTempDir); #endif wsTemp += L"x"; int nTime = (int)time(NULL); for (int nIndex = 0; nIndex < 1000; ++nIndex) { wsFileName = wsTemp; wsFileName.append(std::to_wstring(nTime + nIndex)); if (wsExt) { wsFileName.append(wsExt); } #if defined (_WIN32) || defined (_WIN64) if ( 0 != _wfopen_s(&pTempFile, wsFileName.c_str(), L"r") ) { if (0 != _wfopen_s(&pTempFile, wsFileName.c_str(), wsMode)) #else std::string sFileName = U_TO_UTF8(wsFileName); if (!(pTempFile = fopen(sFileName.c_str(), "r"))) { std::wstring strMode(wsMode); std::string sMode = U_TO_UTF8(strMode); if (!(pTempFile = fopen(sFileName.c_str(), sMode.c_str()))) #endif { return FALSE; } *pwsName = wsFileName; *ppFile = pTempFile; return TRUE; } fclose(pTempFile); } return FALSE; } FILE* CFileBinary::OpenFileNative(const std::wstring& sFileName, const std::wstring& sMode) { #if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64) FILE* pFile = NULL; _wfopen_s(&pFile, sFileName.c_str(), sMode.c_str()); return pFile; #else BYTE* pUtf8 = NULL; LONG lLen = 0; CUtf8Converter::GetUtf8StringFromUnicode(sFileName.c_str(), sFileName.length(), pUtf8, lLen, false); BYTE* pMode = NULL; LONG lLenMode; CUtf8Converter::GetUtf8StringFromUnicode(sMode.c_str(), sMode.length(), pMode, lLenMode, false); struct stat st; if ((0 == stat((char*)pUtf8, &st)) && S_ISDIR(st.st_mode)) { delete [] pUtf8; delete [] pMode; return NULL; } FILE* pFile = fopen((char*)pUtf8, (char*)pMode); delete [] pUtf8; delete [] pMode; return pFile; #endif } void CFileBinary::SetTempPath(const std::wstring& strTempPath) { g_overrideTmpPath = strTempPath; } bool CFileBinary::GetTime(const std::wstring& sFilename, struct tm* ptmLastWrite, struct tm* ptmLastAccess) { bool result = true; if (ptmLastWrite) memset(ptmLastWrite, 0, sizeof(struct tm)); if (ptmLastAccess) memset(ptmLastAccess, 0, sizeof(struct tm)); #if defined(_WIN32) || defined (_WIN64) // windows HANDLE hFile; hFile = ::CreateFileW(sFilename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile) { FILETIME ftLastWrite{}, ftLastAccess{}; if (::GetFileTime(hFile, NULL, &ftLastAccess, &ftLastWrite)) { FILETIME ftLastWriteLocal{}, ftLastAccessLocal{}; result = result && ::FileTimeToLocalFileTime(&ftLastWrite, &ftLastWriteLocal); result = result && ::FileTimeToLocalFileTime(&ftLastAccess, &ftLastAccessLocal); SYSTEMTIME stLastWrite{}, stLastAccess{}; result = result && ::FileTimeToSystemTime(&ftLastWriteLocal, &stLastWrite); result = result && ::FileTimeToSystemTime(&ftLastAccessLocal, &stLastAccess); auto set_tm_by_st = [] (struct tm* time_tm, SYSTEMTIME* time_st) { time_tm->tm_sec = static_cast(time_st->wSecond); time_tm->tm_min = static_cast(time_st->wMinute); time_tm->tm_hour = static_cast(time_st->wHour); time_tm->tm_mday = static_cast(time_st->wDay); time_tm->tm_mon = static_cast(time_st->wMonth); time_tm->tm_year = static_cast(time_st->wYear); }; if (result) { if (ptmLastWrite) set_tm_by_st(ptmLastWrite, &stLastWrite); if (ptmLastAccess) set_tm_by_st(ptmLastAccess, &stLastAccess); } } else result = false; CloseHandle(hFile); } else result = false; #else // linux or macOS struct stat attr; result = (0 == stat(U_TO_UTF8(sFilename).c_str(), &attr)); if (result) { auto set_tm_by_secs = [] (struct tm* time_tm, time_t time_secs) { struct tm* ltime = localtime(&time_secs); *time_tm = *ltime; time_tm->tm_year += 1900; time_tm->tm_mon += 1; }; time_t m_secs = attr.st_mtim.tv_sec; // edit time_t a_secs = attr.st_atim.tv_sec; // access if (ptmLastWrite) set_tm_by_secs(ptmLastWrite, m_secs); if (ptmLastAccess) set_tm_by_secs(ptmLastAccess, a_secs); } #endif // defined(_WIN32) || defined (_WIN64) return result; } bool CFileBinary::SetTime(const std::wstring& sFilename, struct tm* ptmLastWrite, struct tm* ptmLastAccess) { bool result = true; #if defined(_WIN32) || defined (_WIN64) // windows auto set_st_by_tm = [] (SYSTEMTIME* time_st, struct tm* time_tm) { time_st->wSecond = static_cast(time_tm->tm_sec); time_st->wMinute = static_cast(time_tm->tm_min); time_st->wHour = static_cast(time_tm->tm_hour); time_st->wDay = static_cast(time_tm->tm_mday); time_st->wMonth = static_cast(time_tm->tm_mon); time_st->wYear = static_cast(time_tm->tm_year); }; SYSTEMTIME stLastWrite{}, stLastAccess{}; if (ptmLastWrite) set_st_by_tm(&stLastWrite, ptmLastWrite); if (ptmLastAccess) set_st_by_tm(&stLastAccess, ptmLastAccess); FILETIME ftLastWriteLocal{}, ftLastAccessLocal{}; if (ptmLastWrite) result = result && ::SystemTimeToFileTime(&stLastWrite, &ftLastWriteLocal); if (ptmLastAccess) result = result && ::SystemTimeToFileTime(&stLastAccess, &ftLastAccessLocal); FILETIME ftLastWrite{}, ftLastAccess{}; if (ptmLastWrite) result = result && ::LocalFileTimeToFileTime(&ftLastWriteLocal, &ftLastWrite); if (ptmLastAccess) result = result && ::LocalFileTimeToFileTime(&ftLastAccessLocal, &ftLastAccess); if (result) { HANDLE hFile; hFile = ::CreateFileW(sFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile) { FILETIME* pftLastWrite = NULL; FILETIME* pftLastAccess = NULL; if (ptmLastWrite) pftLastWrite = &ftLastWrite; if (ptmLastAccess) pftLastAccess = &ftLastAccess; result = SetFileTime(hFile, NULL, pftLastAccess, pftLastWrite); } else result = false; CloseHandle(hFile); } #else // linux or macOS struct stat attr; std::string sFilenameA = U_TO_UTF8(sFilename); result = (0 == stat(sFilenameA.c_str(), &attr)); if (result) { time_t m_secs = attr.st_mtim.tv_sec; // edit time_t a_secs = attr.st_atim.tv_sec; // access time_t new_m_secs = m_secs; time_t new_a_secs = a_secs; if (ptmLastWrite) { struct tm tmLastWriteUnix = *ptmLastWrite; tmLastWriteUnix.tm_year -= 1900; tmLastWriteUnix.tm_mon -= 1; new_m_secs = mktime(&tmLastWriteUnix); } if (ptmLastAccess) { struct tm tmLastAccessUnix = *ptmLastAccess; tmLastAccessUnix.tm_year -= 1900; tmLastAccessUnix.tm_mon -= 1; new_a_secs = mktime(&tmLastAccessUnix); } utimbuf new_time{}; new_time.actime = new_a_secs; new_time.modtime = new_m_secs; utime(sFilenameA.c_str(), &new_time); } #endif // defined(_WIN32) || defined (_WIN64) return result; } } namespace NSFile { bool CBase64Converter::Encode(const BYTE* pDataSrc, int nLenSrc, char*& pDataDst, int& nLenDst, DWORD dwFlags) { if (!pDataSrc || nLenSrc < 1) return false; nLenDst = NSBase64::Base64EncodeGetRequiredLength(nLenSrc, dwFlags); pDataDst = new char[nLenDst]; if (FALSE == NSBase64::Base64Encode(pDataSrc, nLenSrc, (BYTE*)pDataDst, &nLenDst, dwFlags)) { RELEASEARRAYOBJECTS(pDataDst); return false; } return true; } bool CBase64Converter::Decode(const char* pDataSrc, int nLenSrc, BYTE*& pDataDst, int& nLenDst) { if (!pDataSrc || nLenSrc < 1) return false; nLenDst = NSBase64::Base64DecodeGetRequiredLength(nLenSrc); pDataDst = new BYTE[nLenDst]; if (FALSE == NSBase64::Base64Decode(pDataSrc, nLenSrc, pDataDst, &nLenDst)) { RELEASEARRAYOBJECTS(pDataDst); return false; } return true; } } namespace NSFile { std::wstring GetProcessPath() { #if defined (_WIN64) || defined(_WIN32) wchar_t buf [NS_FILE_MAX_PATH]; GetModuleFileNameW(GetModuleHandle(NULL), buf, NS_FILE_MAX_PATH); return std::wstring(buf); #endif #if defined(__linux__) || defined(_MAC) && !defined(_IOS) char buf[NS_FILE_MAX_PATH]; memset(buf, 0, NS_FILE_MAX_PATH); if (readlink ("/proc/self/exe", buf, NS_FILE_MAX_PATH) <= 0) { #ifdef _MAC uint32_t _size = NS_FILE_MAX_PATH; _NSGetExecutablePath(buf, &_size); std::string sUTF8(buf); std::wstring sRet = CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)sUTF8.c_str(), sUTF8.length()); return sRet; #endif return L""; } std::string sUTF8(buf); std::wstring sRet = CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)sUTF8.c_str(), sUTF8.length()); return sRet; #endif return L""; } std::wstring GetProcessDirectory() { std::wstring sPath = GetProcessPath(); size_t pos1 = sPath.find_last_of(wchar_t('/')); size_t pos2 = sPath.find_last_of(wchar_t('\\')); size_t pos = std::wstring::npos; if (pos1 != std::wstring::npos) pos = pos1; if (pos2 != std::wstring::npos) { if (pos == std::wstring::npos) pos = pos2; else if (pos2 > pos) pos = pos2; } if (pos != std::wstring::npos) { sPath = sPath.substr(0, pos); } return sPath; } // CommonFunctions std::wstring GetFileExtention(const std::wstring& sPath) { std::wstring::size_type nPos = sPath.rfind('.'); if (nPos != std::wstring::npos) return sPath.substr(nPos + 1); return sPath; } std::wstring GetFileName(const std::wstring& sPath) { #ifdef _WIN32 std::wstring::size_type nPos1 = sPath.rfind('\\'); #else std::wstring::size_type nPos1 = std::wstring::npos; #endif std::wstring::size_type nPos2 = sPath.rfind('/'); std::wstring::size_type nPos = std::wstring::npos; if (nPos1 != std::wstring::npos) { nPos = nPos1; if (nPos2 != std::wstring::npos && nPos2 > nPos) nPos = nPos2; } else nPos = nPos2; if (nPos == std::wstring::npos) return sPath; return sPath.substr(nPos + 1); } std::wstring GetDirectoryName(const std::wstring& sPath) { #ifdef _WIN32 std::wstring::size_type nPos1 = sPath.rfind('\\'); #else std::wstring::size_type nPos1 = std::wstring::npos; #endif std::wstring::size_type nPos2 = sPath.rfind('/'); std::wstring::size_type nPos = std::wstring::npos; if (nPos1 != std::wstring::npos) { nPos = nPos1; if (nPos2 != std::wstring::npos && nPos2 > nPos) nPos = nPos2; } else nPos = nPos2; if (nPos == std::wstring::npos) return sPath; return sPath.substr(0, nPos); } }