400 lines
11 KiB
Plaintext
Executable File
400 lines
11 KiB
Plaintext
Executable File
-- Rockstar File Utility
|
|
-- Rockstar North
|
|
-- 1/3/2005
|
|
-- by Greg Smith
|
|
-- by Luke Openshaw
|
|
|
|
-- Set of utility functions for dealing with files
|
|
|
|
--filein "pipeline/util/string.ms" -- loaded on startup by startup.ms
|
|
|
|
----------------------------------------------------------------------------------------
|
|
-- These old function-names are now aliases of built-in Max functions:
|
|
----------------------------------------------------------------------------------------
|
|
global RsFileExists = DoesFileExist
|
|
global RsRemovePath = FilenameFromPath
|
|
global RsRemoveFile = GetFilenamePath
|
|
|
|
----------------------------------------------------------------------------------------
|
|
-- from a full path to a file return just the filename with no extension
|
|
----------------------------------------------------------------------------------------
|
|
fn RsRemovePathAndExtension path =
|
|
(
|
|
local outVal = getFilenameFile path
|
|
|
|
-- getFilenameFile only strips the last extension, it doesn't deal with piled-up extensions:
|
|
return (filterString outVal ".")[1]
|
|
)
|
|
|
|
----------------------------------------------------------------------------------------
|
|
-- use & - reference for extension
|
|
----------------------------------------------------------------------------------------
|
|
fn RsRemoveExtension path extension: =
|
|
(
|
|
local extParts = (filterString path ".")
|
|
if unsupplied!=extension then
|
|
*extension = extParts[2]
|
|
return extParts[1]
|
|
)
|
|
|
|
----------------------------------------------------------------------------------------
|
|
-- find the last occurance of a character in a string
|
|
----------------------------------------------------------------------------------------
|
|
fn RsFindLast searched char = (
|
|
|
|
retidx = -1
|
|
|
|
for i = 1 to searched.count do (
|
|
|
|
if retidx == -1 then (
|
|
|
|
index = searched.count - (i - 1)
|
|
|
|
if char == searched[index] then (
|
|
|
|
retidx = index
|
|
)
|
|
)
|
|
)
|
|
|
|
retidx
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- makes sure that a passed in string is a valid path
|
|
--------------------------------------------------------------
|
|
fn RsMakeSafeSlashes pathin = (
|
|
|
|
pathout = ""
|
|
|
|
if isKindOf pathin String do
|
|
(
|
|
local c
|
|
local prevSlash = False
|
|
for i = 1 to pathin.count do
|
|
(
|
|
c = pathin[i]
|
|
if (c == "/") or (c == "\\") then
|
|
(
|
|
if not prevSlash do
|
|
(
|
|
pathout += "/"
|
|
)
|
|
prevSlash = True
|
|
)
|
|
else
|
|
(
|
|
prevSlash = False
|
|
pathout += c
|
|
)
|
|
)
|
|
)
|
|
|
|
pathout
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- makes sure that a passed in string is a valid path
|
|
--------------------------------------------------------------
|
|
fn RsMakeBackSlashes pathin = (
|
|
|
|
pathout = ""
|
|
|
|
if isKindOf pathin String do
|
|
(
|
|
local c
|
|
local prevSlash = False
|
|
for i = 1 to pathin.count do
|
|
(
|
|
c = pathin[i]
|
|
if (c == "/") or (c == "\\") then
|
|
(
|
|
if not prevSlash do
|
|
(
|
|
pathout += "\\"
|
|
)
|
|
prevSlash = True
|
|
)
|
|
else
|
|
(
|
|
prevSlash = False
|
|
pathout += c
|
|
)
|
|
)
|
|
)
|
|
|
|
pathout
|
|
)
|
|
|
|
----------------------------------------------------------------------------------------
|
|
-- takes the filename of the path, leaving just the directory that the file is in
|
|
----------------------------------------------------------------------------------------
|
|
fn RsRemoveFilename fullpath =
|
|
(
|
|
RsMakeSafeSlashes (getFilenamePath fullpath)
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- makes sure that a passed in string is a valid path
|
|
--------------------------------------------------------------
|
|
fn RsMakeSafePath pathin = (
|
|
|
|
pathout = RsMakeSafeSlashes pathin
|
|
|
|
if pathout[pathout.count] != "/" then (
|
|
|
|
pathout = pathout + "/"
|
|
)
|
|
|
|
pathout
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- check that all the paths exist for the passed in file path
|
|
-------------------------------------------------------------------------------------------------
|
|
fn RsMakeSurePathExists filePath =
|
|
(
|
|
local dirPath = ""
|
|
if ( "" == ( getFilenameType filePath ) ) then
|
|
dirPath = filePath
|
|
else
|
|
dirPath = (getFilenamePath filePath)
|
|
|
|
makedir DirPath
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- delete a directory and any files in contains
|
|
-------------------------------------------------------------------------------------------------
|
|
fn RsDeleteDirectory dir =
|
|
(
|
|
-- GunnarD found bug 697996, taking out fo now
|
|
diruse = RsMakeSafeSlashes dir
|
|
return rexDeleteDirectory diruse
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- delete all the files of a certain type in a directory
|
|
-------------------------------------------------------------------------------------------------
|
|
fn RsDeleteFiles wildcard = (
|
|
|
|
wildcard = RsMakeBackSlashes wildcard
|
|
|
|
retval = true
|
|
files = getfiles wildcard
|
|
|
|
for file in files do (
|
|
|
|
if retval == true then (
|
|
|
|
if deletefile file == false then (
|
|
|
|
retval = false
|
|
)
|
|
)
|
|
)
|
|
|
|
retval
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- copy all files by wildcard to a target folder
|
|
-------------------------------------------------------------------------------------------------
|
|
fn RsCopyFiles wildcard targetdir = (
|
|
|
|
retval = true
|
|
files = getfiles wildcard
|
|
|
|
for file in files do (
|
|
|
|
if retval == true then (
|
|
|
|
targetfile = filenameFromPath file
|
|
|
|
if copyfile file (targetdir + "/" + targetfile) == false then (
|
|
|
|
retval = false
|
|
)
|
|
)
|
|
)
|
|
|
|
retval
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- returns true if a file exists and is readonly else false
|
|
-------------------------------------------------------------------------------------------------
|
|
fn RsIsFileReadOnly file = (
|
|
|
|
if ( doesFileExist file ) then
|
|
( getfileattribute file #readOnly )
|
|
else
|
|
false
|
|
)
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- RsFindFilesRecursive
|
|
-- Recursively find list of files under rootpath matching wildcard(s)
|
|
-- (e.g. "*.ide" or #("*.tga", "*.jpg))
|
|
-------------------------------------------------------------------------------------------------
|
|
fn RsFindFilesRecursive rootpath wildcards foundFiles:#() =
|
|
(
|
|
local foundFiles = #()
|
|
|
|
if not isKindOf wildcards Array do
|
|
(
|
|
wildcards = #(wildcards)
|
|
)
|
|
|
|
for wildcard in wildcards do
|
|
(
|
|
join foundFiles (getFiles (rootpath + "/" + wildcard))
|
|
)
|
|
|
|
-- Post process to have consistent file paths
|
|
for i = 1 to foundFiles.count do
|
|
(
|
|
foundFiles[i] = RsMakeSafeSlashes foundFiles[i]
|
|
)
|
|
|
|
for subDir in getDirectories (rootpath + "/*") do
|
|
(
|
|
join foundFiles (RsFindFilesRecursive subDir wildcards foundFiles:foundFiles)
|
|
)
|
|
|
|
return foundFiles
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- name: RsFileExist
|
|
-- description: Check if a file exists
|
|
-------------------------------------------------------------------------------------------------
|
|
global RsFileExist = doesFileExist
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- RsFindDirsRec
|
|
-- Do not call this externally, use RsFindDirsRecursive
|
|
-------------------------------------------------------------------------------------------------
|
|
fn RsFindDirsRec dirpath dirList =
|
|
(
|
|
dirs = getDirectories (dirpath + "*")
|
|
join dirList dirs
|
|
for dir in dirs do (
|
|
RsFindDirsRec dir dirList
|
|
)
|
|
)
|
|
-------------------------------------------------------------------------------------------------
|
|
-- RsFindDirsRecursive
|
|
-- Recursively find list of dirs under rootpath with the folder name pattern
|
|
-------------------------------------------------------------------------------------------------
|
|
fn RsFindDirsRecursive rootpath pattern foundDirs:#() =
|
|
(
|
|
matchedDirs = #()
|
|
RsFindDirsRec rootpath foundDirs
|
|
|
|
for dir in foundDirs do
|
|
(
|
|
-- Checks for trailing slash too as that is included in getDirectories incase * is not
|
|
-- on the end of the pattern passed in
|
|
if ( matchPattern dir pattern:pattern or matchPattern dir pattern:(pattern + "\\") ) do
|
|
(
|
|
appendIfUnique matchedDirs dir
|
|
)
|
|
)
|
|
matchedDirs
|
|
)
|
|
|
|
--
|
|
-- name: RsDirectoryWriteable
|
|
-- desc: Check that a directory exists and is writeable
|
|
--
|
|
fn RsDirectoryWriteable dir = (
|
|
|
|
-- Because RsConfigGetNetworkStreamDir() returns a path ending with a '/', this should check
|
|
-- if the '/' is present and if so remove it.
|
|
if (matchPattern dir pattern:"*/" == true) then (
|
|
|
|
dir = substring dir 1 (dir.count - 1)
|
|
)
|
|
|
|
-- DHM 2/8/10 -- to be blunt "isDirectoryWriteable" doesn't work with our
|
|
-- network paths at least. Lets try to write a test file; which is kind of nasty and could
|
|
-- leave a temporary file behind; but its got the machine name so its relatively safe.
|
|
-- isDirectoryWriteable dir
|
|
try
|
|
(
|
|
local filename = (dir + "\\3dsmax_writeable_" + sysInfo.computername + ".txt")
|
|
local fp = openFile filename mode:"w"
|
|
format "File created for RsDirectoryWriteable(). Delete if modified date is not now!" to:fp
|
|
close fp
|
|
deleteFile filename
|
|
true
|
|
)
|
|
catch
|
|
(
|
|
false
|
|
)
|
|
)
|
|
|
|
--
|
|
-- name: RsFileModDate
|
|
-- desc: Return file modifier date/time as .Net DateTime object
|
|
-- (for comparison)
|
|
--
|
|
fn RsFileModDate filename = (
|
|
|
|
local fileClass = dotNetClass "System.IO.File"
|
|
local md = fileClass.GetLastWriteTime( filename )
|
|
md
|
|
)
|
|
|
|
--
|
|
-- name: RsFileCreateDate
|
|
-- desc: Return file creation date/time as .Net DateTime object
|
|
-- (for comparison)
|
|
--
|
|
fn RsFileCreateDate filename = (
|
|
|
|
local fileClass = dotNetClass "System.IO.File"
|
|
local md = fileClass.GetCreationTime( filename )
|
|
md
|
|
)
|
|
|
|
-- Open-dialog to get multiple filenames at once:
|
|
fn RSgetOpenFilenames caption:"Open" filename:"" types:"All Files (*.*)|*.*" default:1 =
|
|
(
|
|
local openDialog = DotNetObject "System.Windows.Forms.OpenFileDialog"
|
|
openDialog.multiSelect = true
|
|
openDialog.title = caption
|
|
|
|
local filePath = getFilenamePath filename
|
|
if doesFileExist filePath do
|
|
(
|
|
openDialog.initialDirectory = filePath
|
|
)
|
|
|
|
-- MAXScript getOpenFilename uses trailing |; DotNet's OpenFileDialog filter does not.
|
|
if (types[types.count] == "|") do (types = (substring types 1 (types.count - 1)))
|
|
|
|
openDialog.filter = types
|
|
openDialog.filterIndex = default
|
|
|
|
local result = openDialog.ShowDialog()
|
|
if (result.Equals result.OK) then openDialog.filenames else undefined
|
|
)
|
|
|
|
-- Removes any empty directories under path dirPath
|
|
fn RsRemoveEmptyFolders dirPath =
|
|
(
|
|
HiddenDOSCommand ("for /f \"usebackq delims=\" %d in (`\"dir \"" + (RsMakeBackSlashes dirPath) + "\" /ad/b/s | sort /R\"`) do rd \"%d\"")
|
|
)
|
|
|
|
-- Returns hash of dirPath's file-times, allowing for easy change-tracking:
|
|
fn RsPathTimeHash dirPath =
|
|
(
|
|
local dirFilenames = RsFindFilesRecursive dirPath #("*.*")
|
|
local fileTimes = for filename in dirFilenames collect (getFileModDate filename)
|
|
getHashValue fileTimes 1
|
|
) |