Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

304 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Helper methods + classes for file access
  4. //
  5. //===========================================================================//
  6. #include "tier2/fileutils.h"
  7. #include "tier2/tier2.h"
  8. #include "tier1/strtools.h"
  9. #include "filesystem.h"
  10. #include "tier0/icommandline.h"
  11. #include "tier1/utlbuffer.h"
  12. // NOTE: This has to be the last file included!
  13. #include "tier0/memdbgon.h"
  14. //-----------------------------------------------------------------------------
  15. // Builds a directory which is a subdirectory of the current mod
  16. //-----------------------------------------------------------------------------
  17. void GetModSubdirectory( const char *pSubDir, char *pBuf, int nBufLen )
  18. {
  19. // Compute starting directory
  20. Assert( g_pFullFileSystem->GetSearchPath( "MOD_WRITE", false, NULL, 0 ) < nBufLen );
  21. if ( g_pFullFileSystem->GetSearchPath( "MOD_WRITE", false, pBuf, nBufLen ) == 0 )
  22. {
  23. // if we didn't find MOD_WRITE, back to the old MOD
  24. Assert( g_pFullFileSystem->GetSearchPath( "MOD", false, NULL, 0 ) < nBufLen );
  25. g_pFullFileSystem->GetSearchPath( "MOD", false, pBuf, nBufLen );
  26. }
  27. char *pSemi = strchr( pBuf, ';' );
  28. if ( pSemi )
  29. {
  30. *pSemi = 0;
  31. }
  32. Q_StripTrailingSlash( pBuf );
  33. if ( pSubDir )
  34. {
  35. int nLen = Q_strlen( pSubDir );
  36. Q_strncat( pBuf, "\\", nBufLen, 1 );
  37. Q_strncat( pBuf, pSubDir, nBufLen, nLen );
  38. }
  39. Q_FixSlashes( pBuf );
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Builds a directory which is a subdirectory of the current mod's *content*
  43. //-----------------------------------------------------------------------------
  44. void GetModContentSubdirectory( const char *pSubDir, char *pBuf, int nBufLen )
  45. {
  46. char pTemp[ MAX_PATH ];
  47. GetModSubdirectory( pSubDir, pTemp, sizeof(pTemp) );
  48. ComputeModContentFilename( pTemp, pBuf, nBufLen );
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Generates a filename under the 'game' subdirectory given a subdirectory of 'content'
  52. //-----------------------------------------------------------------------------
  53. void ComputeModFilename( const char *pContentFileName, char *pBuf, size_t nBufLen )
  54. {
  55. char pRelativePath[ MAX_PATH ];
  56. if ( !g_pFullFileSystem->FullPathToRelativePathEx( pContentFileName, "CONTENTROOT", pRelativePath, sizeof(pRelativePath) ) )
  57. {
  58. Q_strncpy( pBuf, pContentFileName, (int)nBufLen );
  59. return;
  60. }
  61. char pGameRoot[ MAX_PATH ];
  62. g_pFullFileSystem->GetSearchPath( "GAMEROOT", false, pGameRoot, sizeof(pGameRoot) );
  63. char *pSemi = strchr( pGameRoot, ';' );
  64. if ( pSemi )
  65. {
  66. *pSemi = 0;
  67. }
  68. Q_ComposeFileName( pGameRoot, pRelativePath, pBuf, (int)nBufLen );
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Generates a filename under the 'content' subdirectory given a subdirectory of 'game'
  72. //-----------------------------------------------------------------------------
  73. void ComputeModContentFilename( const char *pGameFileName, char *pBuf, size_t nBufLen )
  74. {
  75. char pRelativePath[ MAX_PATH ];
  76. if ( !g_pFullFileSystem->FullPathToRelativePathEx( pGameFileName, "GAMEROOT", pRelativePath, sizeof(pRelativePath) ) )
  77. {
  78. Q_strncpy( pBuf, pGameFileName, (int)nBufLen );
  79. return;
  80. }
  81. char pContentRoot[ MAX_PATH ];
  82. g_pFullFileSystem->GetSearchPath( "CONTENTROOT", false, pContentRoot, sizeof(pContentRoot) );
  83. char *pSemi = strchr( pContentRoot, ';' );
  84. if ( pSemi )
  85. {
  86. *pSemi = 0;
  87. }
  88. Q_ComposeFileName( pContentRoot, pRelativePath, pBuf, (int)nBufLen );
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose: Generates an Xbox 360 filename from a PC filename
  92. //-----------------------------------------------------------------------------
  93. char *CreateX360Filename( const char *pSourceName, char *pTargetName, int targetLen )
  94. {
  95. Q_StripExtension( pSourceName, pTargetName, targetLen );
  96. int idx = Q_strlen( pTargetName );
  97. // restore extension
  98. Q_snprintf( pTargetName, targetLen, "%s.360%s", pTargetName, &pSourceName[idx] );
  99. return pTargetName;
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose: Generates a PC filename from a possible 360 name.
  103. // Strips the .360. from filename.360.extension.
  104. // Filenames might have multiple '.', need to be careful and only consider the
  105. // last true extension. Complex filenames do occur:
  106. // d:\foo\.\foo.dat
  107. // d:\zip0.360.zip\foo.360.dat
  108. // Returns source if no change needs to occur, othwerwise generates and
  109. // returns target.
  110. //-----------------------------------------------------------------------------
  111. char *RestoreFilename( const char *pSourceName, char *pTargetName, int targetLen )
  112. {
  113. // find extension
  114. // scan backward for '.', but not past a seperator
  115. int end = V_strlen( pSourceName ) - 1;
  116. while ( end > 0 && pSourceName[end] != '.' && !( pSourceName[end] == '\\' || pSourceName[end] == '/' ) )
  117. {
  118. --end;
  119. }
  120. if ( end >= 4 && pSourceName[end] == '.' && !V_strncmp( pSourceName + end - 4 , ".360", 4 ) )
  121. {
  122. // cull the .360, leave the trailing extension
  123. end -= 4;
  124. int length = MIN( end + 1, targetLen );
  125. V_strncpy( pTargetName, pSourceName, length );
  126. V_strncat( pTargetName, pSourceName + end + 4, targetLen );
  127. return pTargetName;
  128. }
  129. // source filename is as expected
  130. return (char *)pSourceName;
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Generate an Xbox 360 file if it doesn't exist or is out of date. This function determines
  134. // the source and target path and whether the file needs to be generated. The caller provides
  135. // a callback function to do the actual creation of the 360 file. "pExtraData" is for the caller to
  136. // pass the address of any data that the callback function may need to access. This function
  137. // is ONLY to be called by caller's who expect to have 360 versions of their file.
  138. //-----------------------------------------------------------------------------
  139. int UpdateOrCreate( const char *pSourceName, char *pTargetName, int targetLen, const char *pPathID, CreateCallback_t pfnCreate, bool bForce, void *pExtraData )
  140. {
  141. if ( pTargetName )
  142. {
  143. // caller could supply source as PC or 360 name, we want the PC filename
  144. char szFixedSourceName[MAX_PATH];
  145. pSourceName = RestoreFilename( pSourceName, szFixedSourceName, sizeof( szFixedSourceName ) );
  146. // caller wants us to provide 360 named version of source
  147. CreateX360Filename( pSourceName, pTargetName, targetLen );
  148. }
  149. // no conversion are performed by the game at runtime anymore
  150. // SMB access was removed by the XDK for Vista....
  151. return UOC_NOT_CREATED;
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Returns the search path as a list of paths
  155. //-----------------------------------------------------------------------------
  156. void GetSearchPath( CUtlVector< CUtlString > &path, const char *pPathID )
  157. {
  158. int nMaxLen = g_pFullFileSystem->GetSearchPath( pPathID, false, NULL, 0 );
  159. char *pBuf = (char*)stackalloc( nMaxLen );
  160. g_pFullFileSystem->GetSearchPath( pPathID, false, pBuf, nMaxLen );
  161. char *pSemi;
  162. while ( NULL != ( pSemi = strchr( pBuf, ';' ) ) )
  163. {
  164. *pSemi = 0;
  165. path.AddToTail( pBuf );
  166. pBuf = pSemi + 1;
  167. }
  168. path.AddToTail( pBuf );
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Given file name in the current dir generate a full path to it.
  172. //-----------------------------------------------------------------------------
  173. bool GenerateFullPath( const char *pFileName, char const *pPathID, char *pBuf, int nBufLen )
  174. {
  175. if ( V_IsAbsolutePath( pFileName ) )
  176. {
  177. V_strncpy( pBuf, pFileName, nBufLen );
  178. return true;
  179. }
  180. const char *pFullPath = g_pFullFileSystem->RelativePathToFullPath( pFileName, pPathID, pBuf, nBufLen );
  181. if ( pFullPath && Q_IsAbsolutePath( pFullPath ) )
  182. return true;
  183. char pDir[ MAX_PATH ];
  184. if ( !g_pFullFileSystem->GetCurrentDirectory( pDir, sizeof( pDir ) ) )
  185. return false;
  186. V_ComposeFileName( pDir, pFileName, pBuf, nBufLen );
  187. V_RemoveDotSlashes( pBuf );
  188. return true;
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Builds a list of all files under a directory with a particular extension
  192. //-----------------------------------------------------------------------------
  193. void AddFilesToList( CUtlVector< CUtlString > &list, const char *pDirectory, const char *pPathID, const char *pExtension )
  194. {
  195. char pSearchString[MAX_PATH];
  196. Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pDirectory );
  197. bool bIsAbsolute = Q_IsAbsolutePath( pDirectory );
  198. // get the list of files
  199. FileFindHandle_t hFind;
  200. const char *pFoundFile = g_pFullFileSystem->FindFirstEx( pSearchString, pPathID, &hFind );
  201. // add all the items
  202. CUtlVector< CUtlString > subDirs;
  203. for ( ; pFoundFile; pFoundFile = g_pFullFileSystem->FindNext( hFind ) )
  204. {
  205. char pChildPath[MAX_PATH];
  206. Q_snprintf( pChildPath, MAX_PATH, "%s\\%s", pDirectory, pFoundFile );
  207. if ( g_pFullFileSystem->FindIsDirectory( hFind ) )
  208. {
  209. if ( Q_strnicmp( pFoundFile, ".", 2 ) && Q_strnicmp( pFoundFile, "..", 3 ) )
  210. {
  211. subDirs.AddToTail( pChildPath );
  212. }
  213. continue;
  214. }
  215. // Check the extension matches
  216. const char *pExt = Q_GetFileExtension( pFoundFile );
  217. if ( !pExt || Q_stricmp( pExt, pExtension ) != 0 )
  218. continue;
  219. char pFullPathBuf[MAX_PATH];
  220. char *pFullPath = pFullPathBuf;
  221. if ( !bIsAbsolute )
  222. {
  223. g_pFullFileSystem->RelativePathToFullPath( pChildPath, pPathID, pFullPathBuf, sizeof(pFullPathBuf) );
  224. }
  225. else
  226. {
  227. pFullPath = pChildPath;
  228. }
  229. V_strlower( pFullPath );
  230. Q_FixSlashes( pFullPath );
  231. list.AddToTail( pFullPath );
  232. }
  233. g_pFullFileSystem->FindClose( hFind );
  234. int nCount = subDirs.Count();
  235. for ( int i = 0; i < nCount; ++i )
  236. {
  237. AddFilesToList( list, subDirs[i], pPathID, pExtension );
  238. }
  239. }
  240. void CBaseFile::ReadLines( CUtlStringList &lineList, int nMaxLineLength )
  241. {
  242. char *pLine = ( char * ) stackalloc( nMaxLineLength );
  243. while( ReadLine( pLine, nMaxLineLength ) )
  244. {
  245. char *pEOL = strchr( pLine, '\n' ); // kill the \n
  246. if ( pEOL )
  247. *pEOL = 0;
  248. lineList.CopyAndAddToTail( pLine );
  249. }
  250. }
  251. void CBaseFile::ReadFile( CUtlBuffer &fileData )
  252. {
  253. int nFileSize = Size();
  254. fileData.EnsureCapacity( Size() );
  255. int nSize = Read( fileData.Base(), nFileSize );
  256. fileData.SeekPut( CUtlBuffer::SEEK_HEAD, nSize );
  257. }