Example #1
0
void appStrcatn(char *dst, int count, const char *src)
{
	char *p = strchr(dst, 0);
	int maxLen = count - (p - dst);
	if (maxLen > 1)
		appStrncpyz(p, src, maxLen);
}
Example #2
0
void appMakeDirectory(const char *dirname)
{
	if (!dirname[0]) return;
	// Win32 and Unix: there is no API to create directory chains
	// so - we will create "a", then "a/b", then "a/b/c"
	char Name[256];
	appStrncpyz(Name, dirname, ARRAY_COUNT(Name));
	appNormalizeFilename(Name);

	for (char *s = Name; /* empty */ ; s++)
	{
		char c = *s;
		if (c != '/' && c != 0)
			continue;
		*s = 0;						// temporarily cut rest of path
		// here: path delimiter or end of string
		if (Name[0] != '.' || Name[1] != 0)		// do not create "."
#if _WIN32
			_mkdir(Name);
#else
			mkdir(Name, S_IRWXU);
#endif
		if (!c) break;				// end of string
		*s = '/';					// restore string (c == '/')
	}
}
Example #3
0
void appSetRootDirectory(const char *dir, bool recurse)
{
	guard(appSetRootDirectory);
	if (dir[0] == 0) dir = ".";	// using dir="" will cause scanning of "/dir1", "/dir2" etc (i.e. drive root)
	appStrncpyz(RootDirectory, dir, ARRAY_COUNT(RootDirectory));
	ScanGameDirectory(RootDirectory, recurse);
	appPrintf("Found %d game files (%d skipped)\n", GNumGameFiles, GNumForeignFiles);
#if PRINT_HASH_DISTRIBUTION
	PrintHashDistribution();
#endif
	unguardf("dir=%s", dir);
}
Example #4
0
void appMakeDirectoryForFile(const char *filename)
{
	char Name[256];
	appStrncpyz(Name, filename, ARRAY_COUNT(Name));
	appNormalizeFilename(Name);

	char *s = strrchr(Name, '/');
	if (s)
	{
		*s = 0;
		appMakeDirectory(Name);
	}
}
Example #5
0
unsigned appGetFileType(const char *filename)
{
	char Name[256];
	appStrncpyz(Name, filename, ARRAY_COUNT(Name));
	appNormalizeFilename(Name);

	struct stat buf;
	if (stat(filename, &buf) == -1)
		return 0;					// no such file/dir
	if (S_ISDIR(buf.st_mode))
		return FS_DIR;
	else if (S_ISREG(buf.st_mode))
		return FS_FILE;
	return 0;						// just in case ... (may be, win32 have other file types?)
}
Example #6
0
static void Field_Draw(menuField_t *f)
{
	int		i;
	char	tempbuffer[128];

	// draw caption
	if (f->name)
		Menu_DrawStringR2L(f->x + f->parent->x + LCOLUMN_OFFSET, f->y + f->parent->y,
			va(S_GREEN"%s", f->name));

	int x = f->x + f->parent->x;
	int y = f->y + f->parent->y;

	// draw border
#if 1
	RE_DrawChar(x + CHAR_WIDTH * 2, y - CHAR_HEIGHT/2, 18);				// left
	RE_DrawChar(x + CHAR_WIDTH * 2, y + CHAR_HEIGHT/2, 24);
	RE_DrawChar(x + (f->visible_length + 3) * CHAR_WIDTH, y - CHAR_HEIGHT/2, 20);	// right
	RE_DrawChar(x + (f->visible_length + 3) * CHAR_WIDTH, y + CHAR_HEIGHT/2, 26);
	for (i = 0; i < f->visible_length; i++)
	{
		RE_DrawChar(x + (i + 3) * CHAR_WIDTH, y - CHAR_HEIGHT/2, 19);	// top
		RE_DrawChar(x + (i + 3) * CHAR_WIDTH, y + CHAR_HEIGHT/2, 25);	// bottom
	}
#else
	RE_Fill(x + CHAR_WIDTH * 2, y - CHAR_HEIGHT / 2, (f->visible_length + 2) * CHAR_WIDTH, CHAR_HEIGHT * 2, RGBA(1, 0, 0, 0.2));
#endif

	// perform string drawing without text coloring
	appStrncpyz(tempbuffer, f->buffer + f->visible_offset, max(f->visible_length, sizeof(tempbuffer)));
	const char *s = tempbuffer;
	int x1 = x + 3 * CHAR_WIDTH;
	while (char c = *s++)
	{
		RE_DrawChar(x1, y, c);
		x1 += CHAR_WIDTH;
	}

	if (f->parent->ItemAtCursor() == f)
	{
		int offset = (f->visible_offset) ? f->visible_length : f->cursor;
		// show cursor
		RE_DrawChar(x + (offset + 3) * CHAR_WIDTH, y, ((cls.realtime >> 8) & 1) ? 11 : ' ');
	}
Example #7
0
//?? TODO: may be pass "Ext" here
void appFindGameFiles(const char *Filename, TArray<const CGameFileInfo*>& Files)
{
	guard(appFindGameFiles);

	if (!appContainsWildcard(Filename))
	{
		const CGameFileInfo* File = appFindGameFile(Filename);
		if (File)
			Files.Add(File);
		return;
	}

	// here we're working with wildcard and should iterate over all files

	char buf[MAX_PACKAGE_PATH];
	appStrncpyz(buf, Filename, ARRAY_COUNT(buf));
	// replace backslashes
	bool containsPath = false;
	for (char* s = buf; *s; s++)
	{
		char c = *s;
		if (c == '\\')
		{
			*s = '/';
			containsPath = true;
		}
		else if (c == '/')
		{
			containsPath = true;
		}
	}

	FindPackageWildcardData findData;
	findData.WildcardContainsPath = containsPath;
	findData.Wildcard = buf;
	appEnumGameFiles(FindPackageWildcardCallback, findData);

	CopyArray(Files, findData.FoundFiles);

	unguardf("wildcard=%s", Filename);
}
Example #8
0
const CGameFileInfo *appFindGameFile(const char *Filename, const char *Ext)
{
	guard(appFindGameFile);

#if UNREAL3
	bool findStartupPackage = (strcmp(Filename, GStartupPackage) == 0);
	if (findStartupPackage)
		return GStartupPackageInfo;
#endif

	char buf[MAX_PACKAGE_PATH];
	appStrncpyz(buf, Filename, ARRAY_COUNT(buf));

	// replace backslashes
	const char* ShortFilename = buf;
	for (char* s = buf; *s; s++)
	{
		char c = *s;
		if (c == '\\') *s = '/';
		if (*s == '/') ShortFilename = s + 1;
	}

	if (Ext)
	{
		// extension is provided
		assert(!strchr(buf, '.'));
	}
	else
	{
		// check for extension in filename
		char *s = strrchr(buf, '.');
		if (s)
		{
			Ext = s + 1;	// remember extension
			*s = 0;			// cut extension
		}
	}

	int nameLen = strlen(ShortFilename);
	int hash = GetHashForFileName(buf);
#ifdef DEBUG_HASH_NAME
	printf("--> Loading %s (%s, len=%d)\n", buf, ShortFilename, nameLen);
#endif

	CGameFileInfo* bestMatch = NULL;
	int bestMatchWeight = -1;
	for (CGameFileInfo* info = GGameFileHash[hash]; info; info = info->HashNext)
	{
#ifdef DEBUG_HASH_NAME
		printf("----> verify %s\n", info->RelativeName);
#endif
		if (info->Extension - 1 - info->ShortFilename != nameLen)	// info->Extension points to char after '.'
		{
//			printf("-----> wrong length %d\n", info->Extension - info->ShortFilename);
			continue;		// different filename length
		}

		// verify extension
		if (Ext)
		{
			if (stricmp(info->Extension, Ext) != 0) continue;
		}
		else
		{
			// Ext = NULL => should be any package extension
			if (!info->IsPackage) continue;
		}

		// verify a filename
		if (strnicmp(info->ShortFilename, ShortFilename, nameLen) != 0)
			continue;
//		if (info->ShortFilename[nameLen] != '.') -- verified before extension comparison
//			continue;

		// Short filename matched, now compare path before the filename.
		// Assume 'ShortFilename' is part of 'buf' and 'info->ShortFilename' is part of 'info->RelativeName'.
		int matchWeight = 0;
		const char *s = ShortFilename;
		const char *d = info->ShortFilename;
		while (--s >= buf && --d >= info->RelativeName)
		{
			if (*s != *d) break;
			matchWeight++;
		}
//		printf("--> matched: %s (weight=%d)\n", info->RelativeName, matchWeight);
		if (matchWeight > bestMatchWeight)
		{
//			printf("---> better match\n");
			bestMatch = info;
			bestMatchWeight = matchWeight;
		}
	}
	return bestMatch;

	unguardf("name=%s ext=%s", Filename, Ext);
}
Example #9
0
void appSetRootDirectory2(const char *filename)
{
	char buf[MAX_PACKAGE_PATH], buf2[MAX_PACKAGE_PATH];
	appStrncpyz(buf, filename, ARRAY_COUNT(buf));
	char *s;
	// replace slashes
	for (s = buf; *s; s++)
		if (*s == '\\') *s = '/';
	// cut filename
	s = strrchr(buf, '/');
	*s = 0;
	// make a copy for fallback
	strcpy(buf2, buf);

	FString root;
	int detected = 0;				// weigth; 0 = not detected
	root = buf;

	// analyze path
	const char *pCooked = NULL;
	for (int i = 0; i < 8; i++)
	{
		// find deepest directory name
		s = strrchr(buf, '/');
		if (!s) break;
		*s++ = 0;
		bool found = false;
		if (i == 0)
		{
			for (int j = 0; j < ARRAY_COUNT(KnownDirs2); j++)
				if (!stricmp(KnownDirs2[j], s))
				{
					found = true;
					break;
				}
		}
		if (found)
		{
			if (detected < 1)
			{
				detected = 1;
				root = buf;
			}
		}
		pCooked = appStristr(s, "Cooked");
		if (pCooked || appStristr(s, "Content"))
		{
			s[-1] = '/';			// put it back
			if (detected < 2)
			{
				detected = 2;
				root = buf;
				break;
			}
		}
	}
	appPrintf("Detected game root %s%s", *root, (detected == false) ? " (no recurse)" : "");
	// detect platform
	if (GForcePlatform == PLATFORM_UNKNOWN && pCooked)
	{
		pCooked += 6;	// skip "Cooked" string
		if (!strnicmp(pCooked, "PS3", 3))
			GForcePlatform = PLATFORM_PS3;
		else if (!strnicmp(pCooked, "Xenon", 5))
			GForcePlatform = PLATFORM_XBOX360;
		else if (!strnicmp(pCooked, "IPhone", 6))
			GForcePlatform = PLATFORM_IOS;
		if (GForcePlatform != PLATFORM_UNKNOWN)
		{
			static const char *PlatformNames[] =
			{
				"",
				"PC",
				"XBox360",
				"PS3",
				"iPhone",
				"Android",
			};
			staticAssert(ARRAY_COUNT(PlatformNames) == PLATFORM_COUNT, Verify_PlatformNames);
			appPrintf("; platform %s", PlatformNames[GForcePlatform]);
		}
	}
	// scan root directory
	appPrintf("\n");
	appSetRootDirectory(*root, detected);
}
Example #10
0
static bool RegisterGameFile(const char *FullName, FVirtualFileSystem* parentVfs = NULL)
{
	guard(RegisterGameFile);

//	printf("..file %s\n", FullName);
	// return false when MAX_GAME_FILES
	if (GNumGameFiles >= ARRAY_COUNT(GameFiles))
		return false;

	if (!parentVfs)		// no nested VFSs
	{
		const char* ext = strrchr(FullName, '.');
		if (ext)
		{
			guard(MountVFS);

			ext++;
			FVirtualFileSystem* vfs = NULL;
			FArchive* reader = NULL;

#if SUPPORT_ANDROID
			if (!stricmp(ext, "obb"))
			{
				GForcePlatform = PLATFORM_ANDROID;
				reader = new FFileReader(FullName);
				if (!reader) return true;
				reader->Game = GAME_UE3;
				vfs = new FObbVFS();
			}
#endif // SUPPORT_ANDROID
#if UNREAL4
			if (!stricmp(ext, "pak"))
			{
				reader = new FFileReader(FullName);
				if (!reader) return true;
				reader->Game = GAME_UE4;
				vfs = new FPakVFS();
				//!! detect game by file name
			}
#endif // UNREAL4
			//!! process other VFS types here
			if (vfs)
			{
				assert(reader);
				// read VF directory
				if (!vfs->AttachReader(reader))
				{
					// something goes wrong
					delete vfs;
					delete reader;
					return true;
				}
				// add game files
				int NumVFSFiles = vfs->NumFiles();
				for (int i = 0; i < NumVFSFiles; i++)
				{
					if (!RegisterGameFile(vfs->FileName(i), vfs))
						return false;
				}
				return true;
			}

			unguard;
		}
	}

	bool IsPackage;
	if (FindExtension(FullName, ARRAY_ARG(PackageExtensions)))
	{
		IsPackage = true;
	}
	else
	{
#if HAS_SUPORT_FILES
		if (!FindExtension(FullName, ARRAY_ARG(KnownExtensions)))
#endif
		{
			// perhaps this file was exported by our tool - skip it
			if (FindExtension(FullName, ARRAY_ARG(SkipExtensions)))
				return true;
			// unknown file type
			if (++GNumForeignFiles >= MAX_FOREIGN_FILES)
				appError("Too much unknown files - bad root directory (%s)?", RootDirectory);
			return true;
		}
		IsPackage = false;
	}

	// create entry
	CGameFileInfo *info = new CGameFileInfo;
	GameFiles[GNumGameFiles++] = info;
	info->IsPackage = IsPackage;
	info->FileSystem = parentVfs;
	if (IsPackage) GNumPackageFiles++;

	if (!parentVfs)
	{
		// regular file
		FILE* f = fopen(FullName, "rb");
		if (f)
		{
			fseek(f, 0, SEEK_END);
			info->SizeInKb = (ftell(f) + 512) / 1024;
			fclose(f);
		}
		else
		{
			info->SizeInKb = 0;
		}
		// cut RootDirectory from filename
		const char *s = FullName + strlen(RootDirectory) + 1;
		assert(s[-1] == '/');
		appStrncpyz(info->RelativeName, s, ARRAY_COUNT(info->RelativeName));
	}
	else
	{
		// file in virtual file system
		info->SizeInKb = parentVfs->GetFileSize(FullName);
		appStrncpyz(info->RelativeName, FullName, ARRAY_COUNT(info->RelativeName));
	}

	// find filename
	const char* s = strrchr(info->RelativeName, '/');
	if (s) s++; else s = info->RelativeName;
	info->ShortFilename = s;
	// find extension
	s = strrchr(info->ShortFilename, '.');
	if (s) s++;
	info->Extension = s;
//	printf("..  -> %s (pkg=%d)\n", info->ShortFilename, info->IsPackage);

#if UNREAL3
	if (info->IsPackage && (strnicmp(info->ShortFilename, "startup", 7) == 0))
	{
		// Register a startup package
		// possible name variants:
		// - startup
		// - startup_int
		// - startup_*
		int startupWeight = 0;
		if (info->ShortFilename[7] == '.')
			startupWeight = 30;							// "startup.upk"
		else if (strnicmp(info->ShortFilename+7, "_int.", 5) == 0)
			startupWeight = 20;							// "startup_int.upk"
		else if (strnicmp(info->ShortFilename+7, "_loc_int.", 9) == 0)
			startupWeight = 20;							// "startup_int.upk"
		else if (info->ShortFilename[7] == '_')
			startupWeight = 1;							// non-int locale, lower priority - use if when other is not detected
		if (startupWeight > GStartupPackageInfoWeight)
		{
			GStartupPackageInfoWeight = startupWeight;
			GStartupPackageInfo = info;
		}
	}
#endif // UNREAL3

	// insert CGameFileInfo into hash table
	int hash = GetHashForFileName(info->ShortFilename);
	info->HashNext = GGameFileHash[hash];
	GGameFileHash[hash] = info;

	return true;

	unguardf("%s", FullName);
}
Example #11
0
static bool ReadXprFile(const CGameFileInfo *file)
{
	guard(ReadXprFile);

	FArchive *Ar = appCreateFileReader(file);

	int Tag, FileLen, DataStart, DataCount;
	*Ar << Tag << FileLen << DataStart << DataCount;
	//?? "XPR0" - xpr variant with a single object (texture) inside
	if (Tag != BYTES4('X','P','R','1'))
	{
#if XPR_DEBUG
		appPrintf("Unknown XPR tag in %s\n", file->RelativeName);
#endif
		delete Ar;
		return true;
	}
#if XPR_DEBUG
	appPrintf("Scanning %s ...\n", file->RelativeName);
#endif

	XprInfo *Info = new(xprFiles) XprInfo;
	Info->File      = file;
	Info->DataStart = DataStart;
	// read filelist
	int i;
	for (i = 0; i < DataCount; i++)
	{
		int NameOffset, DataOffset;
		*Ar << NameOffset << DataOffset;
		int savePos = Ar->Tell();
		Ar->Seek(NameOffset + 12);
		// read name
		char c, buf[256];
		int n = 0;
		while (true)
		{
			*Ar << c;
			if (n < ARRAY_COUNT(buf))
				buf[n++] = c;
			if (!c) break;
		}
		buf[ARRAY_COUNT(buf)-1] = 0;			// just in case
		// create item
		XprEntry *Entry = new(Info->Items) XprEntry;
		appStrncpyz(Entry->Name, buf, ARRAY_COUNT(Entry->Name));
		Entry->DataOffset = DataOffset + 12;
		assert(Entry->DataOffset < DataStart);
		// seek back
		Ar->Seek(savePos);
		// setup size of previous item
		if (i >= 1)
		{
			XprEntry *PrevEntry = &Info->Items[i - 1];
			PrevEntry->DataSize = Entry->DataOffset - PrevEntry->DataOffset;
		}
		// setup size of the last item
		if (i == DataCount - 1)
			Entry->DataSize = DataStart - Entry->DataOffset;
	}
	// scan data
	// data block is either embedded in this block or followed after DataStart position
	for (i = 0; i < DataCount; i++)
	{
		XprEntry *Entry = &Info->Items[i];
#if XPR_DEBUG
//		appPrintf("  %08X [%08X]  %s\n", Entry->DataOffset, Entry->DataSize, Entry->Name);
#endif
		Ar->Seek(Entry->DataOffset);
		int id;
		*Ar << id;
		switch (id)
		{
		case 0x80020001:
			// header is 4 dwords + immediately followed data
			Entry->DataOffset += 4 * 4;
			Entry->DataSize   -= 4 * 4;
			break;

		case 0x00040001:
			// header is 5 dwords + external data
			{
				int pos;
				*Ar << pos;
				Entry->DataOffset = DataStart + pos;
			}
			break;

		case 0x00020001:
			// header is 4 dwords + external data
			{
				int d1, d2, pos;
				*Ar << d1 << d2 << pos;
				Entry->DataOffset = DataStart + pos;
			}
			break;

		default:
			// header is 2 dwords - offset and size + external data
			{
				int pos;
				*Ar << pos;
				Entry->DataOffset = DataStart + pos;
			}
			break;
		}
	}
	// setup sizes of blocks placed after DataStart (not embedded into file list)
	for (i = 0; i < DataCount; i++)
	{
		XprEntry *Entry = &Info->Items[i];
		if (Entry->DataOffset < DataStart) continue; // embedded data
		// Entry points to a data block placed after DataStart position
		// we should find a next block
		int NextPos = FileLen;
		for (int j = i + 1; j < DataCount; j++)
		{
			XprEntry *NextEntry = &Info->Items[j];
			if (NextEntry->DataOffset < DataStart) continue; // embedded data
			NextPos = NextEntry->DataOffset;
			break;
		}
		Entry->DataSize = NextPos - Entry->DataOffset;
	}
#if XPR_DEBUG
	for (i = 0; i < DataCount; i++)
	{
		XprEntry *Entry = &Info->Items[i];
		appPrintf("  %3d %08X [%08X] .. %08X  %s\n", i, Entry->DataOffset, Entry->DataSize, Entry->DataOffset + Entry->DataSize, Entry->Name);
	}
#endif

	delete Ar;
	return true;

	unguardf("%s", file->RelativeName);
}
Example #12
0
FString ShowFileSelectionDialog(
	bool bIsSaveDialog,
	UIBaseDialog* ParentDialog,
	const FString& InitialFilename,
	const FString& InitialDirectory,
	const FString& Title,
	const TArray<FString>& Filters)
{
	OPENFILENAME ofn;
	memset(&ofn, 0, sizeof(ofn));

	char szPathName[1024];
	appStrncpyz(szPathName, *InitialFilename, ARRAY_COUNT(szPathName));

	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner   = ParentDialog->GetWnd();
	ofn.lpstrFile   = szPathName;
	ofn.nMaxFile    = ARRAY_COUNT(szPathName);

	// Build filters string. It consists of null-terminated strings concatenated
	// into single buffer. Ends with extra null character.
	FStaticString<1024> filterBuf;
	for (int i = 0; i < Filters.Num(); i++)
	{
		const char* s = *Filters[i];
		const char* s2 = strchr(s, '|');
		if (s2)
		{
			int delimRSize = Filters[i].Len() - int(s2 - s);
			filterBuf += s;
			filterBuf[filterBuf.Len() - delimRSize] = 0;
			filterBuf.AppendChar(0);
		}
		else
		{
			filterBuf += s;
			filterBuf.AppendChar(0);
			filterBuf += s;
			filterBuf.AppendChar(0);
		}
	}
	// Add "all files" filter, and finish it with extra null character.
	filterBuf += "All Files (*.*)";
	filterBuf.AppendChar(0);
	filterBuf += "*.*";
	filterBuf.AppendChar(0);
	filterBuf.AppendChar(0);
	ofn.lpstrFilter = *filterBuf;

	if (!InitialDirectory.IsEmpty())
	{
		ofn.lpstrInitialDir = *InitialDirectory;
	}

	if (!Title.IsEmpty())
	{
		ofn.lpstrTitle = *Title;
	}

	ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING | OFN_EXPLORER;
	if (bIsSaveDialog)
	{
		ofn.Flags |= OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT | OFN_NOVALIDATE;
	}
	else
	{
		ofn.Flags |= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
	}

	int bSuccess = (bIsSaveDialog) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
	if (bSuccess)
	{
		return szPathName;
	}
	else
	{
		return "";
	}
}
Example #13
0
// Mask variants:
// 1) *      - any file
// 2) *.*    - any file
// 3) *rest  - name ends with "rest" (for example, ".ext")
// 4) start* - name starts with "start"
// 4) text   - name equals "text"
// Comparision is case-sensitive, when ignoreCase == false (default)
// A few masks can be separated with ','
bool appMatchWildcard(const char *name, const char *mask, bool ignoreCase)
{
	guard(appMatchWildcard);

	if (!name[0] && !mask[0]) return true;		// empty strings matched

	char NameCopy[1024], MaskCopy[1024];
	if (ignoreCase)
	{
		appStrncpylwr(NameCopy, name, ARRAY_COUNT(NameCopy));
		appStrncpylwr(MaskCopy, mask, ARRAY_COUNT(MaskCopy));
	}
	else
	{
		appStrncpyz(NameCopy, name, ARRAY_COUNT(NameCopy));
		appStrncpyz(MaskCopy, mask, ARRAY_COUNT(MaskCopy));
	}

	int namelen = strlen(NameCopy);

	// can use TStringSplitter here
	const char *next;
	for (mask = MaskCopy; mask; mask = next)
	{
		// find next wildcard (comma-separated)
		next = strchr(mask, ',');
		int masklen;
		if (next)
		{
			masklen = next - mask;
			next++;					// skip ','
		}
		else
			masklen = strlen(mask);

		if (!masklen)
		{
			// used something like "mask1,,mask3" (2nd mask is empty)
//??		appPrintf("appMatchWildcard: skip empty mask in \"%s\"\n", mask);
			continue;
		}

		// check for a trivial wildcard
		if (mask[0] == '*')
		{
			if (masklen == 1 || (masklen == 3 && mask[1] == '.' && mask[2] == '*'))
				return true;		// "*" or "*.*" -- any name valid
		}

		// "*text*" mask
		if (masklen >= 3 && mask[0] == '*' && mask[masklen-1] == '*')
		{
			int		i;

			mask++;
			masklen -= 2;
			for (i = 0; i <= namelen - masklen; i++)
				if (!memcmp(&NameCopy[i], mask, masklen)) return true;
		}
		else
		{
			// "*text" or "text*" mask
			const char *suff = strchr(mask, '*');
			if (next && suff >= next) suff = NULL;		// suff can be in next wildcard
			if (suff)
			{
				int preflen = suff - mask;
				int sufflen = masklen - preflen - 1;
				suff++;

				if (namelen < preflen + sufflen)
					continue;		// name is not long enough
				if (preflen && memcmp(NameCopy, mask, preflen))
					continue;		// different prefix
				if (sufflen && memcmp(NameCopy + namelen - sufflen, suff, sufflen))
					continue;		// different suffix

				return true;
			}
			// exact match ("text")
			if (namelen == masklen && !memcmp(NameCopy, mask, namelen))
				return true;
		}
	}

	return false;
	unguard;
}
Example #14
0
/*
==================
cDirectConnect

A connection request that did not come from the master
==================
*/
static void cDirectConnect(int argc, char **argv)
{
	int		i;

	netadr_t adr = net_from;

	Com_DPrintf("SVC_DirectConnect()\n");

	int version = atoi(argv[1]);
	if (version != PROTOCOL_VERSION)
	{
		Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
		Com_DPrintf("  rejected connect from version %d\n", version);
		return;
	}

	int port = atoi(argv[2]);
	int challenge = atoi(argv[3]);

	// get userinfo
	char userinfo[MAX_INFO_STRING];
	appStrncpyz(userinfo, argv[4], sizeof(userinfo));
	// force the IP key/value pair to be in userinfo (for game-side IP filters)
	Info_SetValueForKey(userinfo, "ip", NET_AdrToString(&net_from));

	// attractloop servers are ONLY for local clients
	if (sv.attractloop)
	{
		if (!NET_IsLocalAddress(&adr))
		{
			appPrintf("Remote connect in attract loop. Ignored.\n");
			Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nConnection refused.\n");
			return;
		}
	}

	// see if the challenge is valid
	if (!NET_IsLocalAddress(&adr))
	{
		for (i = 0; i < MAX_CHALLENGES; i++)
			if (NET_CompareBaseAdr(&net_from, &svs.challenges[i].adr))
			{
				if (challenge == svs.challenges[i].challenge)
					break;		// good
				Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nBad challenge.\n");
				return;
			}
		if (i == MAX_CHALLENGES)
		{
			Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nNo challenge for address.\n");
			return;
		}
	}

	client_t temp, *cl;
	memset(&temp, 0, sizeof(client_t));
	client_t *newcl = NULL;

	// if there is already a slot for this ip, reuse it
	for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++,cl++)
	{
		if (cl->state == cs_free) continue;

		if (NET_CompareBaseAdr(&adr, &cl->netchan.remote_address) &&
			(cl->netchan.port == port || adr.port == cl->netchan.remote_address.port))
		{
			if (!NET_IsLocalAddress(&adr) && (svs.realtime - cl->lastconnect) < (sv_reconnect_limit->integer * 1000))
			{
				Com_DPrintf("%s:reconnect rejected : too soon\n", NET_AdrToString(&adr));
				return;
			}
			appPrintf("%s:reconnect\n", NET_AdrToString(&adr));
			newcl = cl;
			break;
		}
	}

	// find a client slot
	if (!newcl)
	{
		for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++,cl++)
			if (cl->state == cs_free)
			{
				newcl = cl;
				break;
			}
	}
	if (!newcl)
	{
		Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nServer is full.\n");
		Com_DPrintf("Rejected a connection.\n");
		return;
	}

	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	*newcl = temp;
	sv_client = newcl;
	int edictnum = (newcl-svs.clients)+1;
	edict_t *ent = EDICT_NUM(edictnum);
	newcl->edict = ent;
	newcl->challenge = challenge;		// save challenge for checksumming

	// get the game a chance to reject this connection or modify the userinfo
	qboolean result;
	guardGame(ge.ClientConnect);
	result = ge->ClientConnect(ent, userinfo);
	unguardGame;

	if (!result)
	{
		if (*Info_ValueForKey(userinfo, "rejmsg"))
			Netchan_OutOfBandPrint(NS_SERVER, adr, "print\n%s\nConnection refused.\n",
				Info_ValueForKey(userinfo, "rejmsg"));
		else
			Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nConnection refused.\n" );
		Com_DPrintf("Game rejected a connection.\n");
		return;
	}

	// parse some info from the info strings
	newcl->Userinfo = userinfo;
	SV_UserinfoChanged(newcl);

	// check if client trying to connect with a new protocol
	newcl->newprotocol = !strcmp(argv [5], NEW_PROTOCOL_ID) && sv_extProtocol->integer;
	// send the connect packet to the client
	if (newcl->newprotocol)
	{
		int ver = atoi(argv[6]);
		if (ver != NEW_PROTOCOL_VERSION)
		{
			//?? we may also perform extended protocol checking by adding "[cl_]extprotocol" to userinfo
			Com_DPrintf("Client used extended protocol %d != "STR(NEW_PROTOCOL_VERSION)"\n", ver);
			if (ver < NEW_PROTOCOL_VERSION)
				Netchan_OutOfBandPrint(NS_SERVER, adr, "print\n"
				S_YELLOW"Server provides newer version of extended protocol\nPlease upgrade your client\n" );
			newcl->newprotocol = false;
		}
	}
	if (newcl->newprotocol)
	{
		Com_DPrintf("Connecting client using extended protocol\n");
		Netchan_OutOfBandPrint(NS_SERVER, adr, "client_connect "NEW_PROTOCOL_ID" "STR(NEW_PROTOCOL_VERSION));
	}
	else
		Netchan_OutOfBandPrint(NS_SERVER, adr, "client_connect");

	newcl->netchan.Setup(NS_SERVER, adr, port);
	newcl->maxPacketSize = cl->newprotocol ? MAX_MSGLEN : MAX_MSGLEN_OLD;
	newcl->state         = cs_connected;

	newcl->datagram.Init(newcl->datagram_buf, sizeof(newcl->datagram_buf));
	newcl->datagram.allowoverflow = true;
	newcl->lastmessage   = svs.realtime;	// don't timeout
	newcl->lastconnect   = svs.realtime;
}
Example #15
0
char *Sys_ConsoleInput()
{
	guard(Sys_ConsoleInput);

#if !NO_DEDICATED
	if (console_drawInput)
	{
		// display input line
		Win32Log.WriteChar(']');
		if (console_textlen)
		{
			console_text[console_textlen] = 0;
			Win32Log.WriteStr(console_text);
		}
		console_drawInput = false;
	}

	while (true)
	{
		DWORD	numevents, numread;
		GetNumberOfConsoleInputEvents(hConInput, &numevents);
		if (numevents <= 0) break;

		INPUT_RECORD rec;
		ReadConsoleInput(hConInput, &rec, 1, &numread);
		if (rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown)
		{
			int ch = rec.Event.KeyEvent.uChar.AsciiChar;
			switch (ch)
			{
				case '\r':		// ENTER
					Win32Log.WriteStr("\r\n");
					console_drawInput = true;
					if (console_textlen)
					{
						console_textlen = 0;
						return console_text;
					}
					break;

				case '\b':		// BACKSPACE
					if (console_textlen)
					{
						console_text[--console_textlen] = 0;
						Win32Log.WriteStr("\b \b");
					}
					break;

				case '\t':		// TAB
					{
						appSprintf(ARRAY_ARG(editLine), "]%s", console_text);
						CompleteCommand();
						const char *s = editLine;
						if (s[0] == ']') s++;
						if (s[0] == '/') s++;
						int len = strlen(s);
						if (len > 0)
						{
							console_textlen = min(len, sizeof(console_text)-2);
							appStrncpyz(console_text, s, console_textlen+1);
							Win32Log.EraseInput();
							console_drawInput = true;	// next time ...
						}
					}
					break;

				case '\x1B':	// ESC
					Win32Log.EraseInput();
					console_textlen = 0;
					console_text[0] = 0;
					break;

				default:
					if (ch >= ' ')
					{
						if (console_textlen < sizeof(console_text)-2)
						{
							Win32Log.WriteChar(ch);
							console_text[console_textlen++] = ch;
							console_text[console_textlen] = 0;
						}
					}
//					else
//						appPrintf("%2X\n",ch);
					break;
			}
		}
	}
#endif
	return NULL;

	unguard;
}