| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669 |
- /*
- * Copyright: JessMA Open Source (ldcsaa@gmail.com)
- *
- * Author : Bruce Liang
- * Website : https://github.com/ldcsaa
- * Project : https://github.com/ldcsaa/HP-Socket
- * Blog : http://www.cnblogs.com/ldcsaa
- * Wiki : http://www.oschina.net/p/hp-socket
- * QQ Group : 44636872, 75375912
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "SocketHelper.h"
- #include <sys/ioctl.h>
- #include <arpa/inet.h>
- #include <netinet/tcp.h>
- #include <netinet/udp.h>
- #ifdef _ICONV_SUPPORT
- #include <iconv.h>
- #endif
- #ifndef SO_REUSEPORT
- #define SO_REUSEPORT 15
- #endif
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- static const BYTE s_szUdpCloseNotify[] = {0xBE, 0xB6, 0x1F, 0xEB, 0xDA, 0x52, 0x46, 0xBA, 0x92, 0x33, 0x59, 0xDB, 0xBF, 0xE6, 0xC8, 0xE4};
- static const int s_iUdpCloseNotifySize = ARRAY_SIZE(s_szUdpCloseNotify);
- const hp_addr hp_addr::ANY_ADDR4(AF_INET, TRUE);
- const hp_addr hp_addr::ANY_ADDR6(AF_INET6, TRUE);
- BOOL SetCurrentWorkerThreadName()
- {
- return SetWorkerThreadDefaultName(0);
- }
- BOOL SetWorkerThreadDefaultName(THR_ID tid)
- {
- static volatile UINT _s_uiSeq = MAXUINT;
- return ::SetSequenceThreadName(tid, DEFAULT_WORKER_THREAD_PREFIX, _s_uiSeq);
- }
- LPCTSTR GetSocketErrorDesc(EnSocketError enCode)
- {
- switch(enCode)
- {
- case SE_OK: return _T("SUCCESS");
- case SE_ILLEGAL_STATE: return _T("Illegal State");
- case SE_INVALID_PARAM: return _T("Invalid Parameter");
- case SE_SOCKET_CREATE: return _T("Create SOCKET Fail");
- case SE_SOCKET_BIND: return _T("Bind SOCKET Fail");
- case SE_SOCKET_PREPARE: return _T("Prepare SOCKET Fail");
- case SE_SOCKET_LISTEN: return _T("Listen SOCKET Fail");
- case SE_CP_CREATE: return _T("Create IOCP Fail");
- case SE_WORKER_THREAD_CREATE: return _T("Create Worker Thread Fail");
- case SE_DETECT_THREAD_CREATE: return _T("Create Detector Thread Fail");
- case SE_SOCKE_ATTACH_TO_CP: return _T("Attach SOCKET to IOCP Fail");
- case SE_CONNECT_SERVER: return _T("Connect to Server Fail");
- case SE_NETWORK: return _T("Network Error");
- case SE_DATA_PROC: return _T("Process Data Error");
- case SE_DATA_SEND: return _T("Send Data Fail");
- case SE_GC_START: return _T("Start GC Fail");
- case SE_SSL_ENV_NOT_READY: return _T("SSL environment not ready");
- default: ASSERT(FALSE); return _T("UNKNOWN ERROR");
- }
- }
- ADDRESS_FAMILY DetermineAddrFamily(LPCTSTR lpszAddress)
- {
- if (!lpszAddress || lpszAddress[0] == 0)
- return AF_UNSPEC;
- if(::StrChr(lpszAddress, IPV6_ADDR_SEPARATOR_CHAR))
- return AF_INET6;
- TCHAR c;
- int arr[4];
- if(stscanf(lpszAddress, _T("%d.%d.%d.%d%c"), &arr[0], &arr[1], &arr[2], &arr[3], &c) != 4)
- return AF_UNSPEC;
- for(int i = 0; i < 4; i++)
- {
- if(arr[i] < 0 || arr[i] > 255)
- return AF_UNSPEC;
- }
- return AF_INET;
- }
- BOOL GetInAddr(LPCTSTR lpszAddress, HP_ADDR& addr)
- {
- addr.family = DetermineAddrFamily(lpszAddress);
- if (addr.family == AF_UNSPEC)
- return FALSE;
- return (::InetPton(addr.family, lpszAddress, addr.Addr()) == TRUE);
- }
- BOOL GetSockAddr(LPCTSTR lpszAddress, USHORT usPort, HP_SOCKADDR& addr)
- {
- if(addr.family != AF_INET && addr.family != AF_INET6)
- {
- ::WSASetLastError(ERROR_ADDRNOTAVAIL);
- return FALSE;
- }
- if(addr.family == AF_INET6 && StrChr(lpszAddress, IPV6_ZONE_INDEX_CHAR))
- return GetSockAddrByHostNameDirectly(lpszAddress, usPort, addr);
- addr.ZeroAddr();
- int rs = ::InetPton(addr.family, lpszAddress, addr.SinAddr());
- if(rs != 1)
- {
- if(rs == 0) ::WSASetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- if(usPort != 0)
- addr.SetPort(usPort);
- return TRUE;
- }
- BOOL IsIPAddress(LPCTSTR lpszAddress, EnIPAddrType* penType)
- {
- HP_ADDR addr;
- BOOL isOK = GetInAddr(lpszAddress, addr);
- if(isOK && penType)
- *penType = addr.IsIPv4() ? IPT_IPV4 : IPT_IPV6;
- return isOK;
- }
- BOOL GetIPAddress(LPCTSTR lpszHost, LPTSTR lpszIP, int& iIPLen, EnIPAddrType& enType)
- {
- HP_SOCKADDR addr;
- if(!GetSockAddrByHostName(lpszHost, 0, addr))
- return FALSE;
- enType = addr.IsIPv4() ? IPT_IPV4 : IPT_IPV6;
- USHORT usPort;
- ADDRESS_FAMILY usFamily;
- return sockaddr_IN_2_A(addr, usFamily, lpszIP, iIPLen, usPort);
- }
- BOOL GetSockAddrByHostName(LPCTSTR lpszHost, USHORT usPort, HP_SOCKADDR& addr)
- {
- addr.family = DetermineAddrFamily(lpszHost);
- if(addr.family != AF_UNSPEC)
- return GetSockAddr(lpszHost, usPort, addr);
- return GetSockAddrByHostNameDirectly(lpszHost, usPort, addr);
- }
- BOOL GetSockAddrByHostNameDirectly(LPCTSTR lpszHost, USHORT usPort, HP_SOCKADDR& addr)
- {
- addr.ZeroAddr();
- addrinfo* pInfo = nullptr;
- addrinfo hints = {0};
- #if defined(__ANDROID__)
- hints.ai_flags = 0;
- #else
- hints.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
- #endif
- hints.ai_family = addr.family;
- hints.ai_socktype = SOCK_STREAM;
- int rs = ::getaddrinfo(CT2A(lpszHost), nullptr, &hints, &pInfo);
- if(!IS_NO_ERROR(rs))
- {
- ::WSASetLastError(ERROR_HOSTUNREACH);
- return FALSE;
- }
- BOOL isOK = FALSE;
- for(addrinfo* pCur = pInfo; pCur != nullptr; pCur = pCur->ai_next)
- {
- if(pCur->ai_family == AF_INET || pCur->ai_family == AF_INET6)
- {
- memcpy(addr.Addr(), pCur->ai_addr, pCur->ai_addrlen);
- isOK = TRUE;
- break;
- }
- }
- EXECUTE_RESTORE_ERROR(::freeaddrinfo(pInfo));
- if(isOK)
- addr.SetPort(usPort);
- else
- ::WSASetLastError(ERROR_HOSTUNREACH);
- return isOK;
- }
- BOOL EnumHostIPAddresses(LPCTSTR lpszHost, EnIPAddrType enType, LPTIPAddr** lpppIPAddr, int& iIPAddrCount)
- {
- *lpppIPAddr = nullptr;
- iIPAddrCount = 0;
- ADDRESS_FAMILY usFamily = (enType == IPT_ALL ?
- AF_UNSPEC : (enType == IPT_IPV4 ?
- AF_INET : (enType == IPT_IPV6 ?
- AF_INET6 : 0xFF)));
- if(usFamily == 0xFF)
- {
- ::WSASetLastError(ERROR_AFNOSUPPORT);
- return FALSE;
- }
- vector<HP_PSOCKADDR> vt;
- ADDRESS_FAMILY usFamily2 = DetermineAddrFamily(lpszHost);
- if(usFamily2 != AF_UNSPEC)
- {
- if(usFamily != AF_UNSPEC && usFamily != usFamily2)
- {
- ::WSASetLastError(ERROR_HOSTUNREACH);
- return FALSE;
- }
- HP_SOCKADDR addr(usFamily2);
- if(!GetSockAddr(lpszHost, 0, addr))
- return FALSE;
- vt.emplace_back(&addr);
- return RetrieveSockAddrIPAddresses(vt, lpppIPAddr, iIPAddrCount);
- }
- addrinfo* pInfo = nullptr;
- addrinfo hints = {0};
- #if defined(__ANDROID__)
- hints.ai_flags = 0;
- #else
- hints.ai_flags = AI_ALL;
- #endif
- hints.ai_family = usFamily;
- hints.ai_socktype = SOCK_STREAM;
- int rs = ::getaddrinfo(CT2A(lpszHost), nullptr, &hints, &pInfo);
- if(rs != NO_ERROR)
- {
- ::WSASetLastError(rs);
- return FALSE;
- }
- for(addrinfo* pCur = pInfo; pCur != nullptr; pCur = pCur->ai_next)
- {
- if(pCur->ai_family == AF_INET || pCur->ai_family == AF_INET6)
- vt.emplace_back((HP_PSOCKADDR)pCur->ai_addr);
- }
- BOOL isOK = RetrieveSockAddrIPAddresses(vt, lpppIPAddr, iIPAddrCount);
- ::freeaddrinfo(pInfo);
- if(!isOK) ::WSASetLastError(EHOSTUNREACH);
- return isOK;
- }
- BOOL RetrieveSockAddrIPAddresses(const vector<HP_PSOCKADDR>& vt, LPTIPAddr** lpppIPAddr, int& iIPAddrCount)
- {
- iIPAddrCount = (int)vt.size();
- if(iIPAddrCount == 0) return FALSE;
- HP_PSOCKADDR pSockAddr;
- ADDRESS_FAMILY usFamily;
- USHORT usPort;
- int iAddrLength;
- LPTSTR lpszAddr;
- LPTIPAddr lpItem;
- (*lpppIPAddr) = new LPTIPAddr[iIPAddrCount + 1];
- (*lpppIPAddr)[iIPAddrCount] = nullptr;
- for(int i = 0; i < iIPAddrCount; i++)
- {
- pSockAddr = vt[i];
- iAddrLength = HP_SOCKADDR::AddrMinStrLength(pSockAddr->family);
- lpszAddr = new TCHAR[iAddrLength];
- VERIFY(sockaddr_IN_2_A(*vt[i], usFamily, lpszAddr, iAddrLength, usPort));
- lpItem = new TIPAddr;
- lpItem->type = pSockAddr->IsIPv4() ? IPT_IPV4 : IPT_IPV6;
- lpItem->address = lpszAddr;
- (*lpppIPAddr)[i] = lpItem;
- }
- return TRUE;
- }
- BOOL FreeHostIPAddresses(LPTIPAddr* lppIPAddr)
- {
- if(!lppIPAddr) return FALSE;
- LPTIPAddr p;
- LPTIPAddr* lppCur = lppIPAddr;
- while((p = *lppCur++) != nullptr)
- {
- delete[] p->address;
- delete p;
- }
- delete[] lppIPAddr;
- return TRUE;
- }
- BOOL sockaddr_IN_2_A(const HP_SOCKADDR& addr, ADDRESS_FAMILY& usFamily, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
- {
- BOOL isOK = FALSE;
- usFamily = addr.family;
- usPort = addr.Port();
- if(::InetNtop(addr.family, addr.SinAddr(), lpszAddress, iAddressLen))
- {
- iAddressLen = (int)lstrlen(lpszAddress) + 1;
- isOK = TRUE;
- }
- else
- {
- if(::WSAGetLastError() == ENOSPC)
- iAddressLen = HP_SOCKADDR::AddrMinStrLength(usFamily);
- }
- return isOK;
- }
- BOOL sockaddr_A_2_IN(LPCTSTR lpszAddress, USHORT usPort, HP_SOCKADDR& addr)
- {
- addr.family = DetermineAddrFamily(lpszAddress);
- return GetSockAddr(lpszAddress, usPort, addr);
- }
- BOOL GetSocketAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort, BOOL bLocal)
- {
- HP_SOCKADDR addr;
- int addr_len = addr.AddrSize();
- int result = bLocal ? getsockname(socket, addr.Addr(), (socklen_t*)&addr_len) : getpeername(socket, addr.Addr(), (socklen_t*)&addr_len);
- if(result != NO_ERROR)
- return FALSE;
- ADDRESS_FAMILY usFamily;
- return sockaddr_IN_2_A(addr, usFamily, lpszAddress, iAddressLen, usPort);
- }
- BOOL GetSocketLocalAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
- {
- return GetSocketAddress(socket, lpszAddress, iAddressLen, usPort, TRUE);
- }
- BOOL GetSocketRemoteAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
- {
- return GetSocketAddress(socket, lpszAddress, iAddressLen, usPort, FALSE);
- }
- BOOL SetMultiCastSocketOptions(SOCKET sock, const HP_SOCKADDR& bindAddr, const HP_SOCKADDR& castAddr, int iMCTtl, BOOL bMCLoop)
- {
- if(castAddr.IsIPv4())
- {
- BYTE ttl = (BYTE)iMCTtl;
- BYTE loop = (BYTE)bMCLoop;
- VERIFY(::SSO_SetSocketOption(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) != SOCKET_ERROR);
- VERIFY(::SSO_SetSocketOption(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != SOCKET_ERROR);
- ip_mreq mcast;
- ::ZeroMemory(&mcast, sizeof(mcast));
- mcast.imr_multiaddr = castAddr.addr4.sin_addr;
- mcast.imr_interface = bindAddr.addr4.sin_addr;
- if(::SSO_SetSocketOption(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, sizeof(mcast)) == SOCKET_ERROR)
- return FALSE;
- if(::SSO_SetSocketOption(sock, IPPROTO_IP, IP_MULTICAST_IF, bindAddr.SinAddr(), sizeof(IN_ADDR)) == SOCKET_ERROR)
- return FALSE;
- }
- else
- {
- INT ttl = (INT)iMCTtl;
- UINT loop = (UINT)bMCLoop;
- VERIFY(::SSO_SetSocketOption(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) != SOCKET_ERROR);
- VERIFY(::SSO_SetSocketOption(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop)) != SOCKET_ERROR);
- ipv6_mreq mcast;
- ::ZeroMemory(&mcast, sizeof(mcast));
- mcast.ipv6mr_multiaddr = castAddr.addr6.sin6_addr;
- mcast.ipv6mr_interface = bindAddr.addr6.sin6_scope_id;
- if(::SSO_SetSocketOption(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mcast, sizeof(mcast)) == SOCKET_ERROR)
- return FALSE;
- if(::SSO_SetSocketOption(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (PVOID)(&bindAddr.addr6.sin6_scope_id), sizeof(UINT)) == SOCKET_ERROR)
- return FALSE;
- }
- return TRUE;
- }
- int WaitForSocketWrite(SOCKET sock, DWORD dwTimeout)
- {
- timeval tv = {(__time_t)(dwTimeout / 1000), (__suseconds_t)((dwTimeout % 1000) * 1000)};
- fd_set wfds, efds;
- FD_ZERO(&wfds);
- FD_ZERO(&efds);
- FD_SET(sock, &wfds);
- FD_SET(sock, &efds);
- int rs = NO_EINTR_INT(select(sock + 1, nullptr, &wfds, &efds, &tv));
- if(rs <= 0) return ((rs == 0) ? ERROR_TIMEOUT : ENSURE_ERROR(ERROR_CANT_WAIT));
-
- if(FD_ISSET(sock, &efds))
- {
- rs = SSO_GetError(sock);
- return ((rs != NO_ERROR && rs != SOCKET_ERROR) ? rs : ENSURE_ERROR(ERROR_CANT_WAIT));
- }
- VERIFY(FD_ISSET(sock, &wfds));
- rs = SSO_GetError(sock);
- if(!IS_NO_ERROR(rs))
- return ((rs != SOCKET_ERROR) ? rs : ENSURE_ERROR(ERROR_CANT_WAIT));
- return NO_ERROR;
- }
- ULONGLONG NToH64(ULONGLONG value)
- {
- return (((ULONGLONG)ntohl((UINT)((value << 32) >> 32))) << 32) | ntohl((UINT)(value >> 32));
- }
- ULONGLONG HToN64(ULONGLONG value)
- {
- return (((ULONGLONG)htonl((UINT)((value << 32) >> 32))) << 32) | htonl((UINT)(value >> 32));
- }
- BOOL IsLittleEndian()
- {
- static const USHORT _s_endian_test_value = 0x0102;
- static const BOOL _s_bLE = (*((BYTE*)&_s_endian_test_value) == 0x02);
- return _s_bLE;
- }
- USHORT HToLE16(USHORT value)
- {
- return IsLittleEndian() ? value : ENDIAN_SWAP_16(value);
- }
- USHORT HToBE16(USHORT value)
- {
- return IsLittleEndian() ? ENDIAN_SWAP_16(value) : value;
- }
- DWORD HToLE32(DWORD value)
- {
- return IsLittleEndian() ? value : ENDIAN_SWAP_32(value);
- }
- DWORD HToBE32(DWORD value)
- {
- return IsLittleEndian() ? ENDIAN_SWAP_32(value) : value;
- }
- HRESULT ReadSmallFile(LPCTSTR lpszFileName, CFile& file, CFileMapping& fmap, DWORD dwMaxFileSize)
- {
- ASSERT(lpszFileName != nullptr);
- if(file.Open(lpszFileName, O_RDONLY))
- {
- SIZE_T dwSize;
- if(file.GetSize(dwSize))
- {
- if(dwSize > 0 && dwSize <= dwMaxFileSize)
- {
- if(fmap.Map(file, dwSize))
- return NO_ERROR;
- }
- else if(dwSize == 0)
- ::SetLastError(ERROR_EMPTY);
- else
- ::SetLastError(ERROR_FILE_TOO_LARGE);
- }
- }
- HRESULT rs = ::GetLastError();
- return (!IS_NO_ERROR(rs) ? rs : ERROR_UNKNOWN);
- }
- HRESULT MakeSmallFilePackage(LPCTSTR lpszFileName, CFile& file, CFileMapping& fmap, WSABUF szBuf[3], const LPWSABUF pHead, const LPWSABUF pTail)
- {
- DWORD dwMaxFileSize = MAX_SMALL_FILE_SIZE - (pHead ? pHead->len : 0) - (pTail ? pTail->len : 0);
- ASSERT(dwMaxFileSize <= MAX_SMALL_FILE_SIZE);
- HRESULT hr = ReadSmallFile(lpszFileName, file, fmap, dwMaxFileSize);
- if(IS_NO_ERROR(hr))
- {
- szBuf[1].len = (UINT)fmap.Size();
- szBuf[1].buf = fmap;
- if(pHead) memcpy(&szBuf[0], pHead, sizeof(WSABUF));
- else memset(&szBuf[0], 0, sizeof(WSABUF));
- if(pTail) memcpy(&szBuf[2], pTail, sizeof(WSABUF));
- else memset(&szBuf[2], 0, sizeof(WSABUF));
- }
- return hr;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- int SSO_SetSocketOption(SOCKET sock, int level, int name, LPVOID val, int len)
- {
- return setsockopt(sock, level, name, val, (socklen_t)len);
- }
- int SSO_GetSocketOption(SOCKET sock, int level, int name, LPVOID val, int* len)
- {
- return getsockopt(sock, level, name, val, (socklen_t*)len);
- }
- int SSO_IoctlSocket(SOCKET sock, long cmd, PVOID arg)
- {
- return ioctl(sock, cmd, arg);
- }
- int SSO_NoBlock(SOCKET sock, BOOL bNoBlock)
- {
- return fcntl_SETFL(sock, O_NONBLOCK, bNoBlock) ? NO_ERROR : SOCKET_ERROR;
- }
- int SSO_NoDelay(SOCKET sock, BOOL bNoDelay)
- {
- int val = bNoDelay ? 1 : 0;
- return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
- }
- int SSO_DontLinger(SOCKET sock, BOOL bDont)
- {
- return SSO_Linger(sock, 0, 0);
- }
- int SSO_Linger(SOCKET sock, int l_onoff, int l_linger)
- {
- linger ln = {l_onoff, l_linger};
- return setsockopt(sock, SOL_SOCKET, SO_LINGER, &ln, sizeof(linger));
- }
- int SSO_KeepAlive(SOCKET sock, BOOL bKeepAlive)
- {
- int val = bKeepAlive ? 1 : 0;
- return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(int));
- }
- int SSO_KeepAliveVals(SOCKET sock, BOOL bOnOff, DWORD dwIdle, DWORD dwInterval, DWORD dwCount)
- {
- if(bOnOff)
- {
- dwIdle /= 1000;
- dwInterval /= 1000;
- if(dwIdle == 0 || dwInterval == 0 || dwCount == 0)
- {
- ::WSASetLastError(ERROR_INVALID_PARAMETER);
- return SOCKET_ERROR;
- }
- }
- BOOL isOK = IS_NO_ERROR(SSO_KeepAlive(sock, bOnOff));
- if(isOK && bOnOff)
- {
- isOK &= IS_NO_ERROR(setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &dwIdle, sizeof(DWORD)));
- isOK &= IS_NO_ERROR(setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &dwInterval, sizeof(DWORD)));
- isOK &= IS_NO_ERROR(setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &dwCount, sizeof(DWORD)));
- }
- return isOK ? NO_ERROR : SOCKET_ERROR;
- }
- int SSO_ReuseAddress(SOCKET sock, EnReuseAddressPolicy opt)
- {
- int iSet = 1;
- int iUnSet = 0;
- int rs = NO_ERROR;
- BOOL bReusePortSupported =
- #if defined(__linux) || defined(__linux__)
- ::IsKernelVersionAbove(2, 6, 32);
- #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__) || defined(__MACH__)
- TRUE;
- #else
- FALSE;
- #endif
- if(opt == RAP_NONE)
- {
- rs = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &iUnSet, sizeof(int));
- if(bReusePortSupported)
- rs |= setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &iUnSet, sizeof(int));
- }
- else if(opt == RAP_ADDR_ONLY)
- {
- rs = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &iSet, sizeof(int));
- if(bReusePortSupported)
- rs |= setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &iUnSet, sizeof(int));
- }
- else if(opt == RAP_ADDR_AND_PORT)
- {
- rs = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &iSet, sizeof(int));
- if(bReusePortSupported)
- rs |= setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &iSet, sizeof(int));
- }
- else
- {
- ::SetLastError(ERROR_INVALID_PARAMETER);
- rs = -1;
- }
- return rs;
- }
- int SSO_RecvBuffSize(SOCKET sock, int size)
- {
- return setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int));
- }
- int SSO_SendBuffSize(SOCKET sock, int size)
- {
- return setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int));
- }
- int SSO_RecvTimeOut(SOCKET sock, int ms)
- {
- timeval tv;
- ::MillisecondToTimeval(ms, tv);
-
- return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
- }
- int SSO_SendTimeOut(SOCKET sock, int ms)
- {
- timeval tv;
- ::MillisecondToTimeval(ms, tv);
- return setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
- }
- int SSO_GetError(SOCKET sock)
- {
- int e;
- socklen_t len = sizeof(e);
- if(IS_NO_ERROR(getsockopt(sock, SOL_SOCKET, SO_ERROR, &e, &len)))
- return e;
- return SOCKET_ERROR;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- CONNID GenerateConnectionID()
- {
- static volatile CONNID s_dwConnID = 0;
- CONNID dwConnID = ::InterlockedIncrement(&s_dwConnID);
-
- if(dwConnID == 0)
- dwConnID = ::InterlockedIncrement(&s_dwConnID);
- return dwConnID;
- }
- int IsUdpCloseNotify(const BYTE* pData, int iLength)
- {
- return (iLength == s_iUdpCloseNotifySize &&
- memcmp(pData, s_szUdpCloseNotify, s_iUdpCloseNotifySize) == 0) ;
- }
- int SendUdpCloseNotify(SOCKET sock)
- {
- return (int)send(sock, (LPCSTR)s_szUdpCloseNotify, s_iUdpCloseNotifySize, 0);
- }
- int SendUdpCloseNotify(SOCKET sock, const HP_SOCKADDR& remoteAddr)
- {
- return (int)sendto(sock, (LPCSTR)s_szUdpCloseNotify, s_iUdpCloseNotifySize, 0, remoteAddr.Addr(), remoteAddr.AddrSize());
- }
- int ManualCloseSocket(SOCKET sock, int iShutdownFlag, BOOL bGraceful)
- {
- if(!bGraceful)
- SSO_Linger(sock, 1, 0);
- if(iShutdownFlag != 0xFF)
- shutdown(sock, iShutdownFlag);
- return closesocket(sock);
- }
- DWORD GuessBase64EncodeBound(DWORD dwSrcLen)
- {
- return 4 * ((dwSrcLen + 2) / 3);
- }
- DWORD GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
- {
- if(dwSrcLen < 2)
- return 0;
- if(lpszSrc[dwSrcLen - 2] == '=')
- dwSrcLen -= 2;
- else if(lpszSrc[dwSrcLen - 1] == '=')
- --dwSrcLen;
- DWORD dwMod = dwSrcLen % 4;
- DWORD dwAdd = dwMod == 2 ? 1 : (dwMod == 3 ? 2 : 0);
- return 3 * (dwSrcLen / 4) + dwAdd;
- }
- int Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- static const BYTE CODES[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- DWORD dwRealLen = GuessBase64EncodeBound(dwSrcLen);
- if(lpszDest == nullptr || dwDestLen < dwRealLen)
- {
- dwDestLen = dwRealLen;
- return -5;
- }
- BYTE* p = lpszDest;
- DWORD leven = 3 * (dwSrcLen / 3);
- DWORD i = 0;
- for (; i < leven; i += 3)
- {
- *p++ = CODES[lpszSrc[0] >> 2];
- *p++ = CODES[((lpszSrc[0] & 3) << 4) + (lpszSrc[1] >> 4)];
- *p++ = CODES[((lpszSrc[1] & 0xf) << 2) + (lpszSrc[2] >> 6)];
- *p++ = CODES[lpszSrc[2] & 0x3f];
- lpszSrc += 3;
- }
- if(i < dwSrcLen)
- {
- BYTE a = lpszSrc[0];
- BYTE b = (i + 1 < dwSrcLen) ? lpszSrc[1] : 0;
- *p++ = CODES[a >> 2];
- *p++ = CODES[((a & 3) << 4) + (b >> 4)];
- *p++ = (i + 1 < dwSrcLen) ? CODES[((b & 0xf) << 2)] : '=';
- *p++ = '=';
- }
- ASSERT(dwRealLen == (DWORD)(p - lpszDest));
- if(dwDestLen > dwRealLen)
- {
- *p = 0;
- dwDestLen = dwRealLen;
- }
- return 0;
- }
- int Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- static const BYTE MAP[256] =
- {
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
- 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
- 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
- 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255
- };
- DWORD dwRealLen = GuessBase64DecodeBound(lpszSrc, dwSrcLen);
- if(lpszDest == nullptr || dwDestLen < dwRealLen)
- {
- dwDestLen = dwRealLen;
- return -5;
- }
- BYTE c;
- int g = 3;
- DWORD i, x, y, z;
- for(i = x = y = z = 0; i < dwSrcLen || x != 0;)
- {
- c = i < dwSrcLen ? MAP[lpszSrc[i++]] : 254;
- if(c == 255) {dwDestLen = 0; return -3;}
- else if(c == 254) {c = 0; g--;}
- else if(c == 253) continue;
- z = (z << 6) | c;
- if(++x == 4)
- {
- lpszDest[y++] = (BYTE)((z >> 16) & 255);
- if (g > 1) lpszDest[y++] = (BYTE)((z >> 8) & 255);
- if (g > 2) lpszDest[y++] = (BYTE)(z & 255);
- x = z = 0;
- }
- }
- BOOL isOK = (y == dwRealLen);
- if(!isOK)
- dwDestLen = 0;
- else
- {
- if(dwDestLen > dwRealLen)
- {
- lpszDest[dwRealLen] = 0;
- dwDestLen = dwRealLen;
- }
- }
- return isOK ? 0 : -3;
- }
- DWORD GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
- {
- DWORD dwAdd = 0;
- for(DWORD i = 0; i < dwSrcLen; i++)
- {
- BYTE c = lpszSrc[i];
- if(!(isalnum(c) || c == ' ' || c == '.' || c == '-' || c == '_' || c == '*'))
- dwAdd += 2;
- }
- return dwSrcLen + dwAdd;
- }
- DWORD GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
- {
- DWORD dwPercent = 0;
- for(DWORD i = 0; i < dwSrcLen; i++)
- {
- if(lpszSrc[i] == '%')
- {
- ++dwPercent;
- i += 2;
- }
- }
- DWORD dwSub = dwPercent * 2;
- if(dwSrcLen < dwSub)
- return 0;
- return dwSrcLen - dwSub;
- }
- int UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- BYTE c;
- DWORD j = 0;
- if(lpszDest == nullptr || dwDestLen == 0)
- goto ERROR_DEST_LEN;
- for(DWORD i = 0; i < dwSrcLen; i++)
- {
- if(j >= dwDestLen)
- goto ERROR_DEST_LEN;
- c = lpszSrc[i];
- if (isalnum(c) || c == '.' || c == '-' || c == '_' || c == '*')
- lpszDest[j++] = c;
- else if(c == ' ')
- lpszDest[j++] = '+';
- else
- {
- if(j + 3 >= dwDestLen)
- goto ERROR_DEST_LEN;
- lpszDest[j++] = '%';
- HEX_VALUE_TO_DOUBLE_CHAR(lpszDest + j, c);
- j += 2;
-
- }
- }
- if(dwDestLen > j)
- {
- lpszDest[j] = 0;
- dwDestLen = j;
- }
- return 0;
- ERROR_DEST_LEN:
- dwDestLen = GuessUrlEncodeBound(lpszSrc, dwSrcLen);
- return -5;
- }
- int UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- char c;
- DWORD j = 0;
- if(lpszDest == nullptr || dwDestLen == 0)
- goto ERROR_DEST_LEN;
- for(DWORD i = 0; i < dwSrcLen; i++)
- {
- if(j >= dwDestLen)
- goto ERROR_DEST_LEN;
- c = lpszSrc[i];
- if(c == '+')
- lpszDest[j++] = ' ';
- else if(c != '%')
- lpszDest[j++] = c;
- else
- {
- if(i + 2 >= dwSrcLen)
- goto ERROR_SRC_DATA;
- lpszDest[j++] = HEX_DOUBLE_CHAR_TO_VALUE(lpszSrc + i + 1);
- i += 2;
- }
- }
- if(dwDestLen > j)
- {
- lpszDest[j] = 0;
- dwDestLen = j;
- }
- return 0;
- ERROR_SRC_DATA:
- dwDestLen = 0;
- return -3;
- ERROR_DEST_LEN:
- dwDestLen = GuessUrlDecodeBound(lpszSrc, dwSrcLen);
- return -5;
- }
- void DestroyCompressor(IHPCompressor* pCompressor)
- {
- delete pCompressor;
- }
- void DestroyDecompressor(IHPDecompressor* pDecompressor)
- {
- delete pDecompressor;
- }
- #ifdef _ZLIB_SUPPORT
- CHPZLibCompressor::CHPZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits, int iLevel, int iMethod, int iMemLevel, int iStrategy, DWORD dwBuffSize)
- : m_fnCallback (fnCallback)
- , m_dwBuffSize (dwBuffSize)
- , m_bValid (FALSE)
- {
- ASSERT(m_fnCallback != nullptr);
- ::ZeroObject(m_Stream);
- m_bValid = (::deflateInit2(&m_Stream, iLevel, iMethod, iWindowBits, iMemLevel, iStrategy) == Z_OK);
- }
- CHPZLibCompressor::~CHPZLibCompressor()
- {
- if(m_bValid) ::deflateEnd(&m_Stream);
- }
- BOOL CHPZLibCompressor::Reset()
- {
- return (m_bValid = (::deflateReset(&m_Stream) == Z_OK));
- }
- BOOL CHPZLibCompressor::Process(const BYTE* pData, int iLength, BOOL bLast, PVOID pContext)
- {
- return ProcessEx(pData, iLength, bLast, FALSE, pContext);
- }
- BOOL CHPZLibCompressor::ProcessEx(const BYTE* pData, int iLength, BOOL bLast, BOOL bFlush, PVOID pContext)
- {
- ASSERT(IsValid() && iLength > 0);
- if(!IsValid())
- {
- ::SetLastError(ERROR_INVALID_STATE);
- return FALSE;
- }
- unique_ptr<BYTE[]> szBuff = make_unique<BYTE[]>(m_dwBuffSize);
- m_Stream.next_in = (z_const Bytef*)pData;
- m_Stream.avail_in = iLength;
-
- BOOL isOK = TRUE;
- int rs = Z_OK;
- int flush = bLast ? Z_FINISH : (bFlush ? Z_SYNC_FLUSH : Z_NO_FLUSH);
- while(m_Stream.avail_in > 0)
- {
- do
- {
- m_Stream.next_out = szBuff.get();
- m_Stream.avail_out = m_dwBuffSize;
- rs = ::deflate(&m_Stream, flush);
- if(rs == Z_STREAM_ERROR)
- {
- ::SetLastError(ERROR_INVALID_DATA);
- isOK = FALSE;
-
- goto ZLIB_COMPRESS_END;
- }
- int iRead = (int)(m_dwBuffSize - m_Stream.avail_out);
- if(iRead == 0)
- break;
- if(!m_fnCallback(szBuff.get(), iRead, pContext))
- {
- ::SetLastError(ERROR_CANCELLED);
- isOK = FALSE;
- goto ZLIB_COMPRESS_END;
- }
- } while(m_Stream.avail_out == 0);
- }
- ZLIB_COMPRESS_END:
- ASSERT(!isOK || (rs == Z_OK && !bLast) || (rs == Z_STREAM_END && bLast));
- if(!isOK || bLast) Reset();
- return isOK;
- }
- CHPZLibDecompressor::CHPZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits, DWORD dwBuffSize)
- : m_fnCallback (fnCallback)
- , m_dwBuffSize (dwBuffSize)
- , m_bValid (FALSE)
- {
- ASSERT(m_fnCallback != nullptr);
- ::ZeroObject(m_Stream);
- m_bValid = (::inflateInit2(&m_Stream, iWindowBits) == Z_OK);
- }
- CHPZLibDecompressor::~CHPZLibDecompressor()
- {
- if(m_bValid) ::inflateEnd(&m_Stream);
- }
- BOOL CHPZLibDecompressor::Reset()
- {
- return (m_bValid = (::inflateReset(&m_Stream) == Z_OK));
- }
- BOOL CHPZLibDecompressor::Process(const BYTE* pData, int iLength, PVOID pContext)
- {
- ASSERT(IsValid() && iLength > 0);
- if(!IsValid())
- {
- ::SetLastError(ERROR_INVALID_STATE);
- return FALSE;
- }
- unique_ptr<BYTE[]> szBuff = make_unique<BYTE[]>(m_dwBuffSize);
- m_Stream.next_in = (z_const Bytef*)pData;
- m_Stream.avail_in = iLength;
- BOOL isOK = TRUE;
- int rs = Z_OK;
- while(m_Stream.avail_in > 0)
- {
- do
- {
- m_Stream.next_out = szBuff.get();
- m_Stream.avail_out = m_dwBuffSize;
- rs = ::inflate(&m_Stream, Z_NO_FLUSH);
- if(rs != Z_OK && rs != Z_STREAM_END)
- {
- ::SetLastError(ERROR_INVALID_DATA);
- isOK = FALSE;
- goto ZLIB_DECOMPRESS_END;
- }
- int iRead = (int)(m_dwBuffSize - m_Stream.avail_out);
- if(iRead == 0)
- break;
- if(!m_fnCallback(szBuff.get(), iRead, pContext))
- {
- ::SetLastError(ERROR_CANCELLED);
- isOK = FALSE;
- goto ZLIB_DECOMPRESS_END;
- }
- } while(m_Stream.avail_out == 0);
- if(rs == Z_STREAM_END)
- break;
- }
- ZLIB_DECOMPRESS_END:
- ASSERT(!isOK || rs == Z_OK || rs == Z_STREAM_END);
- if(!isOK || rs == Z_STREAM_END) Reset();
- return isOK;
- }
- IHPCompressor* CreateZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits, int iLevel, int iMethod, int iMemLevel, int iStrategy, DWORD dwBuffSize)
- {
- return new CHPZLibCompressor(fnCallback, iWindowBits, iLevel, iMethod, iMemLevel, iStrategy, dwBuffSize);
- }
- IHPCompressor* CreateGZipCompressor(Fn_CompressDataCallback fnCallback, int iLevel, int iMethod, int iMemLevel, int iStrategy, DWORD dwBuffSize)
- {
- return new CHPZLibCompressor(fnCallback, MAX_WBITS + 16, iLevel, iMethod, iMemLevel, iStrategy, dwBuffSize);
- }
- IHPDecompressor* CreateZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits, DWORD dwBuffSize)
- {
- return new CHPZLibDecompressor(fnCallback, iWindowBits, dwBuffSize);
- }
- IHPDecompressor* CreateGZipDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize)
- {
- return new CHPZLibDecompressor(fnCallback, MAX_WBITS + 32, dwBuffSize);
- }
- int Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
- }
- int CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel, int iMethod, int iWindowBits, int iMemLevel, int iStrategy)
- {
- z_stream stream;
- stream.next_in = (z_const Bytef*)lpszSrc;
- stream.avail_in = dwSrcLen;
- stream.next_out = lpszDest;
- stream.avail_out = dwDestLen;
- stream.zalloc = nullptr;
- stream.zfree = nullptr;
- stream.opaque = nullptr;
- int err = ::deflateInit2(&stream, iLevel, iMethod, iWindowBits, iMemLevel, iStrategy);
- if(err != Z_OK) return err;
- err = ::deflate(&stream, Z_FINISH);
- if(err != Z_STREAM_END)
- {
- ::deflateEnd(&stream);
- return err == Z_OK ? Z_BUF_ERROR : err;
- }
- if(dwDestLen > stream.total_out)
- {
- lpszDest[stream.total_out] = 0;
- dwDestLen = (DWORD)stream.total_out;
- }
- return ::deflateEnd(&stream);
- }
- int Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
- }
- int UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits)
- {
- z_stream stream;
- stream.next_in = (z_const Bytef*)lpszSrc;
- stream.avail_in = (uInt)dwSrcLen;
- stream.next_out = lpszDest;
- stream.avail_out = dwDestLen;
- stream.zalloc = nullptr;
- stream.zfree = nullptr;
- int err = ::inflateInit2(&stream, iWindowBits);
- if(err != Z_OK) return err;
- err = ::inflate(&stream, Z_FINISH);
- if(err != Z_STREAM_END)
- {
- ::inflateEnd(&stream);
- return (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) ? Z_DATA_ERROR : err;
- }
- if(dwDestLen > stream.total_out)
- {
- lpszDest[stream.total_out] = 0;
- dwDestLen = (DWORD)stream.total_out;
- }
- return inflateEnd(&stream);
- }
- DWORD GuessCompressBound(DWORD dwSrcLen, BOOL bGZip)
- {
- DWORD dwBound = (DWORD)::compressBound(dwSrcLen);
-
- if(bGZip) dwBound += 16;
- return dwBound;
- }
- int GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16);
- }
- int GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, MAX_WBITS + 32);
- }
- DWORD GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen)
- {
- if(dwSrcLen < 20 || *(USHORT*)lpszSrc != 0x8B1F)
- return 0;
- return *(DWORD*)(lpszSrc + dwSrcLen - 4);
- }
- #endif
- #ifdef _BROTLI_SUPPORT
- CHPBrotliCompressor::CHPBrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality, int iWindow, int iMode, DWORD dwBuffSize)
- : m_fnCallback (fnCallback)
- , m_iQuality (iQuality)
- , m_iWindow (iWindow)
- , m_iMode (iMode)
- , m_dwBuffSize (dwBuffSize)
- , m_bValid (FALSE)
- {
- ASSERT(m_fnCallback != nullptr);
- Reset();
- }
- CHPBrotliCompressor::~CHPBrotliCompressor()
- {
- if(m_bValid) ::BrotliEncoderDestroyInstance(m_pState);
- }
- BOOL CHPBrotliCompressor::Reset()
- {
- if(m_bValid) ::BrotliEncoderDestroyInstance(m_pState);
- m_pState = ::BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
- if(m_pState != nullptr)
- {
- ::BrotliEncoderSetParameter(m_pState, BROTLI_PARAM_QUALITY , (UINT)m_iQuality);
- ::BrotliEncoderSetParameter(m_pState, BROTLI_PARAM_LGWIN , (UINT)m_iWindow);
- ::BrotliEncoderSetParameter(m_pState, BROTLI_PARAM_MODE , (UINT)m_iMode);
- if (m_iWindow > BROTLI_MAX_WINDOW_BITS)
- ::BrotliEncoderSetParameter(m_pState, BROTLI_PARAM_LARGE_WINDOW, BROTLI_TRUE);
- }
- return (m_bValid = (m_pState != nullptr));
- }
- BOOL CHPBrotliCompressor::Process(const BYTE* pData, int iLength, BOOL bLast, PVOID pContext)
- {
- return ProcessEx(pData, iLength, bLast, FALSE, pContext);
- }
- BOOL CHPBrotliCompressor::ProcessEx(const BYTE* pData, int iLength, BOOL bLast, BOOL bFlush, PVOID pContext)
- {
- ASSERT(IsValid() && iLength > 0);
- if(!IsValid())
- {
- ::SetLastError(ERROR_INVALID_STATE);
- return FALSE;
- }
- unique_ptr<BYTE[]> szBuff = make_unique<BYTE[]>(m_dwBuffSize);
- const BYTE* pNextInData = pData;
- size_t iAvlInLen = (SIZE_T)iLength;
- BYTE* pNextOutData = nullptr;
- size_t iAvlOutLen = 0;
- BOOL isOK = TRUE;
- BrotliEncoderOperation op = bLast ? BROTLI_OPERATION_FINISH : (bFlush ? BROTLI_OPERATION_FLUSH : BROTLI_OPERATION_PROCESS);
- while(iAvlInLen > 0)
- {
- do
- {
- pNextOutData = szBuff.get();
- iAvlOutLen = m_dwBuffSize;
- if(!::BrotliEncoderCompressStream(m_pState, op, &iAvlInLen, &pNextInData, &iAvlOutLen, &pNextOutData, nullptr))
- {
- ::SetLastError(ERROR_INVALID_DATA);
- isOK = FALSE;
- goto BROTLI_COMPRESS_END;
- }
- int iRead = (int)(m_dwBuffSize - iAvlOutLen);
- if(iRead == 0)
- break;
- if(!m_fnCallback(szBuff.get(), iRead, pContext))
- {
- ::SetLastError(ERROR_CANCELLED);
- isOK = FALSE;
-
- goto BROTLI_COMPRESS_END;
- }
- } while (iAvlOutLen == 0);
- }
- BROTLI_COMPRESS_END:
- if(!isOK || bLast) Reset();
- return isOK;
- }
- CHPBrotliDecompressor::CHPBrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize)
- : m_fnCallback (fnCallback)
- , m_dwBuffSize (dwBuffSize)
- , m_bValid (FALSE)
- {
- ASSERT(m_fnCallback != nullptr);
- Reset();
- }
- CHPBrotliDecompressor::~CHPBrotliDecompressor()
- {
- if(m_bValid) ::BrotliDecoderDestroyInstance(m_pState);
- }
- BOOL CHPBrotliDecompressor::Reset()
- {
- if(m_bValid) ::BrotliDecoderDestroyInstance(m_pState);
- m_pState = ::BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
- return (m_bValid = (m_pState != nullptr));
- }
- BOOL CHPBrotliDecompressor::Process(const BYTE* pData, int iLength, PVOID pContext)
- {
- ASSERT(IsValid() && iLength > 0);
- if(!IsValid())
- {
- ::SetLastError(ERROR_INVALID_STATE);
- return FALSE;
- }
- unique_ptr<BYTE[]> szBuff = make_unique<BYTE[]>(m_dwBuffSize);
- const BYTE* pNextInData = pData;
- size_t iAvlInLen = (SIZE_T)iLength;
- BYTE* pNextOutData = nullptr;
- size_t iAvlOutLen = 0;
- BOOL isOK = TRUE;
- BrotliDecoderResult rs = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
- do
- {
- do
- {
- pNextOutData = szBuff.get();
- iAvlOutLen = m_dwBuffSize;
- rs = ::BrotliDecoderDecompressStream(m_pState, &iAvlInLen, &pNextInData, &iAvlOutLen, &pNextOutData, nullptr);
- if(rs == BROTLI_DECODER_RESULT_ERROR)
- {
- ::SetLastError(ERROR_INVALID_DATA);
- isOK = FALSE;
- goto BROTLI_DECOMPRESS_END;
- }
- int iRead = (int)(m_dwBuffSize - iAvlOutLen);
- if(iRead == 0)
- break;
- if(!m_fnCallback(szBuff.get(), iRead, pContext))
- {
- ::SetLastError(ERROR_CANCELLED);
- isOK = FALSE;
- goto BROTLI_DECOMPRESS_END;
- }
- } while (iAvlOutLen == 0);
- if(rs == BROTLI_DECODER_RESULT_SUCCESS)
- break;
- } while(rs == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
- BROTLI_DECOMPRESS_END:
- if(!isOK || rs == BROTLI_DECODER_RESULT_SUCCESS) Reset();
- return isOK;
- }
- IHPCompressor* CreateBrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality, int iWindow, int iMode, DWORD dwBuffSize)
- {
- return new CHPBrotliCompressor(fnCallback, iQuality, iWindow, iMode, dwBuffSize);
- }
- IHPDecompressor* CreateBrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize)
- {
- return new CHPBrotliDecompressor(fnCallback, dwBuffSize);
- }
- int BrotliCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return BrotliCompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE);
- }
- int BrotliCompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iQuality, int iWindow, int iMode)
- {
- size_t stDestLen = (size_t)dwDestLen;
- int rs = ::BrotliEncoderCompress(iQuality, iWindow, (BrotliEncoderMode)iMode, (size_t)dwSrcLen, lpszSrc, &stDestLen, lpszDest);
- dwDestLen = (DWORD)stDestLen;
- return (rs == 1) ? 0 : ((rs == 3) ? -5 : -3);
- }
- int BrotliUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- size_t stDestLen = (size_t)dwDestLen;
- BrotliDecoderResult rs = ::BrotliDecoderDecompress((size_t)dwSrcLen, lpszSrc, &stDestLen, lpszDest);
- dwDestLen = (DWORD)stDestLen;
- return (rs == BROTLI_DECODER_RESULT_SUCCESS) ? 0 : ((rs == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) ? -5 : -3);
- }
- DWORD BrotliGuessCompressBound(DWORD dwSrcLen)
- {
- return (DWORD)::BrotliEncoderMaxCompressedSize((size_t)dwSrcLen);
- }
- #endif
- #ifdef _ICONV_SUPPORT
- BOOL CharsetConvert(LPCSTR lpszFromCharset, LPCSTR lpszToCharset, LPCSTR lpszInBuf, int iInBufLen, LPSTR lpszOutBuf, int& iOutBufLen)
- {
- ASSERT(lpszInBuf != nullptr);
- SIZE_T nInBufLeft = iInBufLen;
- SIZE_T nOutBufLeft = iOutBufLen;
- int iOutBufSize = iOutBufLen;
- iOutBufLen = 0;
- if(lpszInBuf == nullptr)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- iconv_t ic = iconv_open(lpszToCharset, lpszFromCharset);
- if(IS_INVALID_PVOID(ic))
- return FALSE;
- SIZE_T rs = iconv(ic, (LPSTR*)&lpszInBuf, &nInBufLeft, &lpszOutBuf, &nOutBufLeft);
- iOutBufLen = iOutBufSize - (int)nOutBufLeft;
- EXECUTE_RESTORE_ERROR(iconv_close(ic));
- return !IS_HAS_ERROR(rs);
- }
- BOOL GbkToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength)
- {
- int iInBufLen = (int)((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? strlen(szSrc) + 1 : 0));
- int iOutBufLen = (int)(iDestLength * sizeof(WCHAR));
- BOOL isOK = CharsetConvert(CHARSET_GBK, SYSTEM_CHARSET_UNICODE, szSrc, iInBufLen, (char*)szDest, iOutBufLen);
- iDestLength = (int)(iOutBufLen / sizeof(WCHAR));
- return isOK;
- }
- BOOL UnicodeToGbkEx(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength)
- {
- int iInBufLen = (int)(((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? wcslen(szSrc) + 1 : 0)) * sizeof(WCHAR));
- return CharsetConvert(SYSTEM_CHARSET_UNICODE, CHARSET_GBK, (LPCSTR)szSrc, iInBufLen, szDest, iDestLength);
- }
- BOOL Utf8ToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength)
- {
- int iInBufLen = (int)((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? strlen(szSrc) + 1 : 0));
- int iOutBufLen = (int)(iDestLength * sizeof(WCHAR));
- BOOL isOK = CharsetConvert(CHARSET_UTF_8, SYSTEM_CHARSET_UNICODE, szSrc, iInBufLen, (char*)szDest, iOutBufLen);
- iDestLength = (int)(iOutBufLen / sizeof(WCHAR));
- return isOK;
- }
- BOOL UnicodeToUtf8Ex(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength)
- {
- int iInBufLen = (int)(((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? wcslen(szSrc) + 1 : 0)) * sizeof(WCHAR));
- return CharsetConvert(SYSTEM_CHARSET_UNICODE, CHARSET_UTF_8, (LPCSTR)szSrc, iInBufLen, szDest, iDestLength);
- }
- BOOL GbkToUtf8Ex(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength)
- {
- int iInBufLen = (int)((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? strlen(szSrc) + 1 : 0));
- return CharsetConvert(CHARSET_GBK, CHARSET_UTF_8, szSrc, iInBufLen, szDest, iDestLength);
- }
- BOOL Utf8ToGbkEx(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength)
- {
- int iInBufLen = (int)((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? strlen(szSrc) + 1 : 0));
- return CharsetConvert(CHARSET_UTF_8, CHARSET_GBK, szSrc, iInBufLen, szDest, iDestLength);
- }
- BOOL GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
- {
- return GbkToUnicodeEx(szSrc, -1, szDest, iDestLength);
- }
- BOOL UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength)
- {
- return UnicodeToGbkEx(szSrc, -1, szDest, iDestLength);
- }
- BOOL Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
- {
- return Utf8ToUnicodeEx(szSrc, -1, szDest, iDestLength);
- }
- BOOL UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength)
- {
- return UnicodeToUtf8Ex(szSrc, -1, szDest, iDestLength);
- }
- BOOL GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength)
- {
- return GbkToUtf8Ex(szSrc, -1, szDest, iDestLength);
- }
- BOOL Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength)
- {
- return Utf8ToGbkEx(szSrc, -1, szDest, iDestLength);
- }
- #endif
|