25 #include <sys/types.h>
32 #define snprintf _snprintf
33 #pragma warning (disable : 4355)
38 #define C4NET2RES_DEBUG_LOG
44 static uint32_t iSize, iMaxSize;
45 static bool Helper(
const char *szPath)
47 if (szPath[
SLen(szPath)-1] ==
'.')
58 static bool GetDirSize(
const char *szPath, uint32_t *pSize, uint32_t inMaxSize = ~0)
61 if (!pSize)
return false;
63 iSize = 0; iMaxSize = inMaxSize;
70 uint32_t DirSizeHelper::iSize, DirSizeHelper::iMaxSize;
75 : iFileSize(~0u), iFileCRC(~0u), iContentsCRC(~0u),
132 : iChunk(inChunk), Timestamp(time(nullptr)), iByClient(inByClient), pNext(nullptr)
150 iChunkCnt(Data2.getChunkCnt())
184 pRange->
Next =
nullptr;
196 if (iStart < 0 || iStart + iLength >
iChunkCnt || iLength <= 0)
return;
199 for (pRange =
pChunkRanges, pPrev =
nullptr; pRange; pPrev = pRange, pRange = pRange->
Next)
200 if (pRange->
Start >= iStart)
246 for (int32_t i = 0; i < iLoadingCnt; i++)
261 if (!pRange || !pRange->
Next)
return false;
283 int32_t iFreeStart = 0;
287 Target.
AddChunkRange(iFreeStart, pRange->Start - iFreeStart);
289 iFreeStart = pRange->Start + pRange->Length;
298 if (iNr < pRange->Length)
299 return iNr + pRange->Start;
301 iNr -= pRange->Length;
308 if (deserializing)
Clear();
313 if (!pComp->
Name(
"Ranges"))
314 pComp->
excCorrupt(
"ResChunk ranges expected!");
340 fTempFile(false), fStandaloneFailed(false),
341 iRefCnt(0), fRemoved(false),
344 pCChunks(nullptr), iDiscoverStartTime(0), pLoads(nullptr), iLoadCnt(0),
366 return SetByGroup(&Grp, fTemp, eType, iResID, szResName, fSilent);
370 {
if (!fSilent)
LogF(
"SetByFile: file %s not found!", strFilePath);
return false; }
374 #ifdef C4NET2RES_DEBUG_LOG
376 LogSilentF(
"Network: Resource: complete %d:%s is file %s (%s)", iResID, szResName,
szFile, fTemp ?
"temp" :
"static");
398 sResName = szResName;
407 #ifdef C4NET2RES_DEBUG_LOG
409 LogSilentF(
"Network: Resource: complete %d:%s is file %s (%s)", iResID, sResName.
getData(),
szFile, fTemp ?
"temp" :
"static");
440 const char *szFilenameOnly =
GetFilename(szFilename);
442 if (szFilenameOnly != szFilenameC4)
444 sFilename.
Copy(szFilename,
SLen(szFilename) -
SLen(szFilenameC4));
445 sFilename.
Append(szFilenameOnly);
451 StdStrBuf sSearchPath;
const char *szSearchPath;
456 sSearchPath.
Copy(szFilename,
SLen(szFilename) -
SLen(szFilenameC4));
457 szSearchPath = sSearchPath.
getData();
462 sNetPath.
Take(szNetPath);
466 if (!szNetPath || !*szNetPath || !
ItemIdentical(*i, szNetPath))
489 #ifdef C4NET2RES_DEBUG_LOG
574 if (fAllowUnloadable)
578 {
if (!fSilent)
LogF(
"Network: could not get directory size of %s!",
szFile);
szStandalone[0] =
'\0';
return false; }
588 {
if (!fSilent)
Log(
"GetStandalone: could not find free name for temporary file!");
szStandalone[0] =
'\0';
return false; }
590 {
if (!fSilent)
Log(
"GetStandalone: could not pack directory!");
szStandalone[0] =
'\0';
return false; }
605 {
if (!fSilent)
Log(
"GetStandalone: could not find free name for temporary file!");
szStandalone[0] =
'\0';
return false; }
607 {
if (!fSilent)
Log(
"GetStandalone: could not copy to temporary file!");
szStandalone[0] =
'\0';
return false; }
612 {
if (!fSilent)
Log(
"GetStandalone: file not found!");
szStandalone[0] =
'\0';
return false; }
621 if (fAllowUnloadable)
637 {
if (!fSilent)
Log(
"GetStandalone: could not calculate checksum!");
return false; }
697 {
Log(
"Derive: could not find free name for temporary file!");
return nullptr; }
699 {
Log(
"Derive: could not copy to temporary file!");
return nullptr; }
719 if (!pDRes)
return nullptr;
802 return pTo->
Send(Pkt);
819 if (!pConn)
return false;
825 ResChunk.
Set(
this, iChunk);
862 for (pChunks =
pCChunks; pChunks; pChunks = pChunks->
Next)
873 pChunks->
Chunks = rChunkData;
887 #ifdef C4NET2RES_DEBUG_LOG
898 pNext = pLoad->Next();
899 if (
static_cast<uint32_t
>(pLoad->getChunk()) == rChunk.
getChunkNr())
918 int32_t iLoadsRemoved = 0;
921 pNext = pLoad->Next();
922 if (pLoad->CheckTimeout())
963 LogSilentF(
"Network: Could not delete temporary resource file (%s)", strerror(errno));
967 LogSilentF(
"Network: Could not delete temporary resource file (%s)", strerror(errno));
980 if (!
GetStandalone(
nullptr, 0,
false,
false,
true))
return -1;
1005 for (pChunks =
pCChunks; pChunks; pChunks = pChunks->
Next)
1011 for (i = 0; i < iCChunkCnt; i++) pC[i] =
nullptr;
1013 for (pChunks =
pCChunks, i = 0; i < iCChunkCnt; i++, pChunks = pChunks->
Next)
1018 for (int32_t j = 0; ; j++)
1019 if (!pC[j] && !iPos--)
1030 for (i = 0; i < iCChunkCnt; i++)
1040 if (i >= iCChunkCnt)
1054 if (pPos->getByClient() == iFromClient)
1059 iLoads[i++] = pLoad->getChunk();
1062 if (iRetrieveChunk < 0 || (uint32_t)iRetrieveChunk >=
Core.
getChunkCnt())
1066 if (!pConn)
return false;
1069 { pConn->
DelRef();
return false; }
1071 #ifdef C4NET2RES_DEBUG_LOG
1114 for (pPrev =
pLoads; pPrev && pPrev->
Next() != pLoad; pPrev = pPrev->
Next()) {}
1132 for (pPrev =
pCChunks; pPrev && pPrev->
Next != pChunks; pPrev = pPrev->
Next) {}
1154 {
if (!fSilent)
Log(
"OptimizeStandalone: could not find free name for temporary file!");
return false; }
1156 {
if (!fSilent)
Log(
"OptimizeStandalone: could not copy to temporary file!");
return false; }
1162 {
if (!fSilent)
Log(
"OptimizeStandalone: could not open player file!");
return false; }
1164 size_t iBigIconSize=0;
1187 if (
iSize < 0) {
LogF(
"Network: could not get chunk from offset %d from resource file %s: File size is only %d!", iOffset, pRes->
getFile(), Core.
getFileSize());
return false; }
1190 if (f == -1) {
LogF(
"Network: could not open resource file %s!", pRes->
getFile());
return false; }
1193 if (lseek(f, iOffset, SEEK_SET) != iOffset)
1194 { close(f);
LogF(
"Network: could not read resource file %s!", pRes->
getFile());
return false; }
1196 char *pBuf = (
char *) malloc(
iSize);
1198 { free(pBuf); close(f);
LogF(
"Network: could not read resource file %s!", pRes->
getFile());
return false; }
1209 assert(pRes); assert(pIO);
1214 #ifdef C4NET2RES_DEBUG_LOG
1223 #ifdef C4NET2RES_DEBUG_LOG
1232 #ifdef C4NET2RES_DEBUG_LOG
1239 if (lseek(f, iOffset, SEEK_SET) != iOffset)
1241 #ifdef C4NET2RES_DEBUG_LOG
1250 #ifdef C4NET2RES_DEBUG_LOG
1275 , iNextResID((~0u) << 16)
1302 int32_t iIDDiff = (inClientID -
iClientID) << 16;
1309 if (pRes->getResClient() == iOldClientID)
1310 pRes->ChangeID(pRes->getResID() + iIDDiff);
1329 if (pCur->getResID() == iResID)
1338 if (!pCur->isAnonymous())
1339 if (
SEqual(pCur->getFile(), szFile))
1340 if (!fLocalOnly || pCur->getResClient()==
iClientID)
1354 return getRes(szFile, fLocalOnly);
1362 if (!pCur->isRemoved() && pCur->getResID() >= iResID)
1363 if (!pRes || pRes->
getResID() > pCur->getResID())
1384 if (pRes)
return pRes;
1387 if (iResID < 0) {
Log(
"AddByFile: no more resource IDs available!");
return nullptr; }
1391 if (!pRes->
SetByFile(strFilePath, fTemp, eType, iResID, szResName)) {
return nullptr; }
1395 if (!pRes->
GetStandalone(
nullptr, 0,
true, fAllowUnloadable))
1396 if (!fAllowUnloadable)
1410 if (iResID < 0) {
Log(
"AddByGroup: no more resource IDs available!");
return nullptr; }
1414 if (!pRes->
SetByGroup(pGrp, fTemp, eType, iResID, szResName))
1420 if (!pRes->
GetStandalone(
nullptr, 0,
true, fAllowUnloadable))
1421 if (!fAllowUnloadable)
1435 if (pRes)
return pRes;
1436 #ifdef C4NET2RES_LOAD_ALL
1447 return fLoad ?
AddLoad(Core) :
nullptr;
1491 pRes->iLastReqTime = 0;
1507 return static_cast<const T&
>(*pPacket);
1520 if (!pConn->
isOpen())
break;
1521 auto Pkt = GetPkt<C4PacketResDiscover>(pPacket);
1525 if (Pkt.isIDPresent(pRes->getResID()))
1527 if (pRes->IsBinaryCompatible())
1528 pRes->OnDiscover(pConn);
1534 if (!pConn->
isOpen())
break;
1535 auto Pkt = GetPkt<C4PacketResStatus>(pPacket);
1541 pRes->
OnStatus(Pkt.getChunks(), pConn);
1547 auto Core = GetPkt<C4Network2ResCore>(pPacket);
1548 if (Core.getDerID() < 0)
break;
1552 if (pRes->isAnonymous() && pRes->getCore().getDerID() == Core.getDerID())
1553 pRes->FinishDerive(Core);
1559 auto Pkt = GetPkt<C4PacketResRequest>(pPacket);
1570 auto Chunk = GetPkt<C4Network2ResChunk>(pPacket);
1575 if (pRes) pRes->
OnChunk(Chunk);
1594 bool fSendDiscover =
false;
1606 bool fStatusUpdates =
false;
1622 pNext = pRes->pNext;
1623 if (pRes->isRemoved() && (!pRes->getLastReqTime() || difftime(time(
nullptr), pRes->getLastReqTime()) >
C4NetResDeleteTime))
1626 (pPrev ? pPrev->pNext :
pFirst) = pNext;
1628 pRes->pNext =
nullptr;
1644 if (!pRes->isRemoved())
1645 if (pRes->isLoading())
1647 ResListLock.
Clear();
1682 {
LogFatal(
"Network: could not create network path!");
return false; }
1691 char* safePos = safeFilename;
1694 if ((*szFilename >=
'a' && *szFilename <=
'z') ||
1695 (*szFilename >=
'A' && *szFilename <=
'Z') ||
1696 (*szFilename >=
'0' && *szFilename <=
'9') ||
1697 (*szFilename ==
'.') || (*szFilename ==
'/'))
1698 *safePos = *szFilename;
1706 szFilename = safeFilename;
1717 for (int32_t i = 2; i < 1000; i++)
1719 snprintf(pTarget,
_MAX_PATH, szFileMask, i);
const int32_t C4ClientIDUnknown
C4Application Application
bool C4Group_PackDirectoryTo(const char *filename, const char *to_filename)
bool C4Group_PackDirectory(const char *filename)
bool C4Group_CopyItem(const char *source, const char *target, bool no_sorting, bool reset_attributes)
const char * LoadResStr(const char *id)
bool Log(const char *szMessage)
bool LogSilentF(const char *strMessage,...)
bool LogF(const char *strMessage,...)
bool LogFatal(const char *szMessage)
const T & GetPkt(const C4PacketBase *pPacket)
const int32_t C4NetResStatusInterval
const int32_t C4NetResDiscoverInterval
const int32_t C4NetResIDAnonymous
const int32_t C4NetResLoadTimeout
const int32_t C4NetResMaxLoad
const int32_t C4NetResDeleteTime
const int32_t C4NetResDiscoverTimeout
const StdEnumEntry< C4Network2ResType > C4Network2ResType_EnumMap[]
const uint32_t C4NetResChunkSize
const int32_t C4NetResMaxBigicon
C4NetFilenameAdapt mkNetFilenameAdapt(StdStrBuf &FileName)
C4NetIOPacket MkC4NetIOPacket(char cStatus, const class C4PacketBase &Pkt, const C4NetIO::addr_t &addr=C4NetIO::addr_t())
uint32_t UnsyncedRandom()
StdStrBuf::wchar_t_holder GetWideChar(const char *utf8, bool double_null_terminate=false)
bool GetFileSHA1(const char *szFilename, BYTE *pSHA1)
bool GetFileCRC(const char *szFilename, uint32_t *pCRC32)
#define SHA_DIGEST_LENGTH
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
void SAppend(const char *szSource, char *szTarget, int iMaxL)
bool SEqual(const char *szStr1, const char *szStr2)
size_t SLen(const char *sptr)
StdIntPackAdapt< T > mkIntPackAdapt(T &rVal)
StdNamingCountAdapt< int_t > mkNamingCountAdapt(int_t &iCount, const char *szName)
StdHexAdapt mkHexAdapt(void *pData, size_t iSize)
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
bool EraseItem(const char *szItemName)
const char * GetC4Filename(const char *szPath)
bool DirectoryExists(const char *szFilename)
char * GetExtension(char *szFilename)
bool EraseDirectory(const char *szDirName)
bool ItemIdentical(const char *szFilename1, const char *szFilename2)
char * GetFilename(char *szPath)
void AppendBackslash(char *szFilename)
bool CreatePath(const std::string &path)
void TruncateBackslash(char *szFilename)
int ForEachFile(const char *szDirName, bool(*fnCallback)(const char *))
bool FileExists(const char *szFileName)
bool ItemExists(const char *szItemName)
bool EraseFile(const char *szFileName)
size_t FileSize(const char *fname)
C4InteractiveThread InteractiveThread
const char * AtRelativePath(const char *filename)
const char * AtNetworkPath(const char *filename)
char WorkPath[CFG_MaxString+1]
int32_t MaxResSearchRecursion
C4GameControlNetwork Network
void OnResComplete(C4Network2Res *pRes)
StdStrBuf GetFullName() const
unsigned int EntryCRC32(const char *wildcard=nullptr)
bool Delete(const char *files, bool recursive=false)
bool FindEntry(const char *wildcard, StdStrBuf *filename=nullptr, size_t *size=nullptr)
bool Open(const char *group_name, bool do_create=false)
bool ThreadLog(const char *szMessage,...) GNUC_FORMAT_ATTRIBUTE_O
bool ThreadLogS(const char *szMessage,...) GNUC_FORMAT_ATTRIBUTE_O
bool Send(const C4NetIOPacket &rPkt)
bool BroadcastMsg(const C4NetIOPacket &rPkt)
C4Network2IOConnection * GetMsgConnection(int iClientID)
C4Network2IOConnection * GetDataConnection(int iClientID)
int32_t getPresentChunkCnt() const
void GetNegative(C4Network2ResChunkData &Target) const
int32_t GetChunkToRetrieve(const C4Network2ResChunkData &Available, int32_t iLoadingCnt, int32_t *pLoading) const
C4Network2ResChunkData & operator=(const C4Network2ResChunkData &Data2)
ChunkRange * pChunkRanges
void AddChunk(int32_t iChunk)
bool MergeRanges(ChunkRange *pRange)
~C4Network2ResChunkData() override
int32_t getChunkCnt() const
void Merge(const C4Network2ResChunkData &Data2)
void SetIncomplete(int32_t iChunkCnt)
int32_t getPresentChunk(int32_t iNr) const
void AddChunkRange(int32_t iStart, int32_t iLength)
void SetComplete(int32_t iChunkCnt)
void CompileFunc(StdCompiler *pComp) override
void CompileFunc(StdCompiler *pComp) override
~C4Network2ResChunk() override
bool Set(C4Network2Res *pRes, uint32_t iChunk)
uint32_t getChunkNr() const
bool AddTo(C4Network2Res *pRes, C4Network2IO *pIO) const
void SetDerived(int32_t inDerID)
void SetFileSHA(BYTE *pSHA)
uint32_t getChunkSize() const
void Set(C4Network2ResType eType, int32_t iResID, const char *strFileName, uint32_t iContentsCRC)
uint8_t FileSHA[SHA_DIGEST_LENGTH]
uint32_t getContentsCRC() const
const char * getFileName() const
void CompileFunc(StdCompiler *pComp) override
void SetLoadable(uint32_t iSize, uint32_t iCRC)
uint32_t getFileCRC() const
uint32_t getChunkCnt() const
uint32_t getFileSize() const
C4Network2ResType getType() const
void OnStatus(const C4Network2ResChunkData &rChunkData, C4Network2IOConnection *pBy)
time_t iDiscoverStartTime
C4Network2Res(C4Network2ResList *pnParent)
const char * getFile() const
C4Group * OpenAsGrp() const
C4Network2ResList * pParent
const C4Network2ResCore & getCore() const
C4Network2ResType getType() const
C4Network2ResChunkData Chunks
void RemoveCChunks(ClientChunks *pChunks)
void OnChunk(const C4Network2ResChunk &rChunk)
C4Network2Res::Ref Derive()
bool SetLoad(const C4Network2ResCore &nCore)
C4Network2ResChunkData Chunks
void ChangeID(int32_t inID)
char szFile[_MAX_PATH_LEN]
bool SetByGroup(C4Group *pGrp, bool fTemp, C4Network2ResType eType, int32_t iResID, const char *szResName=nullptr, bool fSilent=false)
bool SendChunk(uint32_t iChunk, int32_t iToClient)
bool SetDerived(const char *strName, const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iDResID)
char szStandalone[_MAX_PATH_LEN]
bool SendStatus(C4Network2IOConnection *pTo=nullptr)
bool IsBinaryCompatible()
struct C4Network2Res::ClientChunks * pCChunks
bool GetStandalone(char *pTo, int32_t iMaxL, bool fSetOfficial, bool fAllowUnloadable=false, bool fSilent=false)
void RemoveLoad(C4Network2ResLoad *pLoad)
bool SetByCore(const C4Network2ResCore &nCore, bool fSilent=false, const char *szAsFilename=nullptr, int32_t iRecursion=0)
bool SetByFile(const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iResID, const char *szResName=nullptr, bool fSilent=false)
C4Network2ResLoad * pLoads
bool OptimizeStandalone(bool fSilent)
void OnDiscover(C4Network2IOConnection *pBy)
bool StartLoad(int32_t iFromClient, const C4Network2ResChunkData &Chunks)
C4Network2Res::Ref getRefRes(int32_t iResID)
void RemoveAtClient(int32_t iClientID)
bool FindTempResFileName(const char *szFilename, char *pTarget)
C4Network2Res::Ref AddByGroup(C4Group *pGrp, bool fTemp, C4Network2ResType eType, int32_t iResID=-1, const char *szResName=nullptr, bool fAllowUnloadable=false)
void Add(C4Network2Res *pRes)
void HandlePacket(char cStatus, const C4PacketBase *pPacket, C4Network2IOConnection *pConn)
C4Network2Res::Ref AddByFile(const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iResID=-1, const char *szResName=nullptr, bool fAllowUnloadable=false)
C4Network2Res * getRes(int32_t iResID)
void OnResComplete(C4Network2Res *pRes)
friend class C4Network2Res
C4Network2IO * getIOClass()
~C4Network2ResList() override
bool CreateNetworkFolder()
bool Init(int32_t iClientID, C4Network2IO *pIOClass)
void SetLocalID(int32_t iClientID)
C4Network2Res::Ref AddByCore(const C4Network2ResCore &Core, bool fLoad=true)
void OnClientConnect(C4Network2IOConnection *pConn)
bool SendDiscover(C4Network2IOConnection *pTo=nullptr)
C4Network2Res::Ref getRefNextRes(int32_t iResID)
void OnShareFree(CStdCSecEx *pCSec) override
C4Network2Res::Ref AddLoad(const C4Network2ResCore &Core)
C4Network2ResLoad * pNext
C4Network2ResLoad * Next() const
C4Network2ResLoad(int32_t iChunk, int32_t iByClient)
bool AddDisID(int32_t iID)
int32_t getDisIDCnt() const
bool LocateItem(const char *filename, StdStrBuf &str) const
bool Open(C4Group &group, const char *filename) const
static bool GetDirSize(const char *szPath, uint32_t *pSize, uint32_t inMaxSize=~0)
void Take(void *pnData, size_t inSize)
const void * getData() const
virtual bool Separator(Sep eSep=SEP_SEP)
void excCorrupt(const char *szMessage,...)
void Value(const T &rStruct)
virtual void NameEnd(bool fBreak=false)
virtual bool isDeserializer()
virtual bool Name(const char *szName)
const char * getData() const
void Append(const char *pnData, size_t iChars)
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O