示例#1
0
IStream *Locate_File(Parser *p, shared_ptr<SceneData>& sd, const UCS2String& filename, unsigned int stype, UCS2String& buffer, bool err_flag)
{
    UCS2String fn(filename);
    UCS2String foundfile(sd->FindFile(p->GetPOVMSContext(), fn, stype));

    if(foundfile.empty() == true)
    {
        if(err_flag == true)
            p->PossibleError("Cannot find file '%s', even after trying to append file type extension.", UCS2toASCIIString(fn).c_str());

        return NULL;
    }

    if(fn.find('.') == UCS2String::npos)
    {
        // the passed-in filename didn't have an extension, but a file has been found,
        // which means one of the appended extensions worked. we need to work out which
        // one and append it to the original filename so we can store it in the cache
        // (since it's that name that the cache search routine looks for).
        UCS2String ext = GetFileExtension(Path(foundfile));
        if (ext.size() != 0)
            fn += ext;
    }

    // ReadFile will store both fn and foundfile in the cache for next time round
    IStream *result(sd->ReadFile(p->GetPOVMSContext(), fn, foundfile.c_str(), stype));

    if((result == NULL) && (err_flag == true))
        p->PossibleError("Cannot open file '%s'.", UCS2toASCIIString(foundfile).c_str());

    buffer = foundfile;

    return result;
}
示例#2
0
bool vfeParsePathString (const UCS2String& path, UCS2String& volume, vector<UCS2String>& components, UCS2String& filename)
{
    UCS2String q;

    if(path.empty() == true)
        return true;

    if(path[0] == '/')
        volume = '/';

    for(size_t i = 0; i < path.length(); ++i)
    {
        if(path[i] == '/')
        {
            if(q.empty() == false)
                components.push_back(q);
            q.clear();
        }
        else
            q += path[i];
    }

    filename = q;

    return true;
}
示例#3
0
UCS2String UTF8toUCS2String(const UTF8String& s)
{
    UCS2String result;
    UCS4 c;
    int len = 0;

    // Compute the encoded length by simply counting all non-continuation bytes.
    // In case of malformed sequences we might get the number wrong, but this is just an estimate
    // used to pre-allocate memory.
    for (UTF8String::const_iterator i = s.begin(); i != s.end(); ++i)
        if (((*i) & 0xC0) != 0x80)
            ++len;

    result.reserve(len);

    for(UTF8String::const_iterator i = s.begin(); i != s.end(); )
    {
        c = DecodeUTF8Character(i);

        if ((c > 0xFFFFu) || (c == 0x0000u))
            // Not valid in UCS2, or we can't deal with it; substitute with a replacement character.
            c = 0xFFFDu;

        result.push_back(c);
    }

    return result;
}
示例#4
0
UCS2String TemporaryFile::SuggestName()
{
    POV_ASSERT(!gTempPath.empty());

    // TODO FIXME - This allows only one temporary file per process!
    // TODO FIXME - Avoid converting back and forth between UCS-2 and system-specific encoding.
    char str [POV_FILENAME_BUFFER_CHARS + 1] = "";
    std::snprintf(str, POV_FILENAME_BUFFER_CHARS + 1, "%spov%d", UCS2toSysString(gTempPath).c_str(), int(getpid()));
    return SysToUCS2String(str);
}
示例#5
0
UCS2 *Parser::Convert_UTF8_To_UCS2(const unsigned char *text_array, int *char_array_size)
{
    POV_PARSER_ASSERT(text_array);
    POV_PARSER_ASSERT(char_array_size);

    UCS2String s = UTF8toUCS2String(UTF8String(reinterpret_cast<const char*>(text_array)));
    UCS2String::size_type len = s.length();
    *char_array_size = len;

    if (len == 0)
        return nullptr;

    size_t size = (len+1)*sizeof(UCS2);

    UCS2 *char_array = reinterpret_cast<UCS2 *>(POV_MALLOC(size, "Character Array"));
    if (char_array == nullptr)
        throw POV_EXCEPTION_CODE(kOutOfMemoryErr);

    memcpy(char_array, s.c_str(), size);

    return char_array;
}
示例#6
0
std::string UCS2toASCIIString(const UCS2String& s)
{
    std::string r;

    for(std::size_t i = 0; i < s.length(); i++)
    {
        if(s[i] >= 256)
            r += ' '; // TODO - according to most encoding conventions, this should be '?'
        else
            r += (char)(s[i]);
    }

    return r;
}
示例#7
0
/* TODO FIXME - this is the correct code but it has a bug. The code above is just a hack [trf]
IStream *BackendSceneData::ReadFile(POVMSContext ctx, const UCS2String& filename, unsigned int stype)
{
    UCS2String scenefile(filename);
    UCS2String localfile;
    UCS2String fileurl;

    // see if the file is available locally
    FilenameToFilenameMap::iterator ilocalfile(scene2LocalFiles.find(scenefile));

    // if available locally, open it end return
    if(ilocalfile != scene2LocalFiles.end())
        return NewIStream(ilocalfile->second.c_str(), stype);

    // see if the file is available as temporary file
    FilenameToFilenameMap::iterator itempfile(scene2TempFiles.find(scenefile));

    // if available as temporary file, open it end return
    if(itempfile != scene2TempFiles.end())
        return NewIStream(itempfile->second.c_str(), stype);

    // otherwise, request the file
    RenderBackend::SendReadFile(ctx, sceneId, frontendAddress, scenefile, localfile, fileurl);

    // if it is available locally, add it to the map and then open it
    if(localfile.length() > 0)
    {
        scene2LocalFiles[scenefile] = localfile;
        local2SceneFiles[localfile] = scenefile;

        return NewIStream(localfile.c_str(), stype);
    }

    // if it is available remotely ...
    if(fileurl.length() > 0)
    {
        // create a temporary file
        UCS2String tempname = POV_PLATFORM_BASE.CreateTemporaryFile();
        OStream *tempfile = NewOStream(tempname.c_str(), stype, false);

        if(tempfile == NULL)
        {
            POV_PLATFORM_BASE.DeleteTemporaryFile(tempname);
            throw POV_EXCEPTION_CODE(kCannotOpenFileErr);
        }

        // download the file from the URL
        // TODO - handle referrer
        if(POV_PLATFORM_BASE.ReadFileFromURL(tempfile, fileurl) == false)
        {
            delete tempfile;
            POV_PLATFORM_BASE.DeleteTemporaryFile(tempname);
            throw POV_EXCEPTION_CODE(kNetworkConnectionErr);
        }

        delete tempfile;

        // add the temporary file to the map
        scene2TempFiles[scenefile] = tempname;
        temp2SceneFiles[tempname] = scenefile;

        return NewIStream(tempname.c_str(), stype);
    }

    // file not found
    return NULL;
}
*/
OStream *BackendSceneData::CreateFile(POVMSContext ctx, const UCS2String& filename, unsigned int stype, bool append)
{
    UCS2String scenefile(filename);

#ifdef USE_SCENE_FILE_MAPPING
    // see if the file is available as temporary file
    FilenameToFilenameMap::iterator itempfile(scene2TempFiles.find(scenefile));

    // if available as temporary file, open it end return
    if(itempfile != scene2TempFiles.end())
        return NewOStream(itempfile->second.c_str(), stype, append);

    // otherwise, create a temporary file ...
    UCS2String tempname = POV_PLATFORM_BASE.CreateTemporaryFile();
    OStream *tempfile = NewOStream(tempname.c_str(), stype, append);

    // failed to open file
    if(tempfile == NULL)
        return NULL;

    // add the temporary file to the map
    scene2TempFiles[scenefile] = tempname;
    temp2SceneFiles[tempname] = scenefile;
#else
    // this is a workaround for the incomplete scene temp file support
    // until someone has time to finish it.

    OStream *tempfile = NewOStream(scenefile.c_str(), stype, append);
    if (tempfile == NULL)
        return NULL;
#endif

    // let the frontend know that a new file was created
    RenderBackend::SendCreatedFile(ctx, sceneId, frontendAddress, scenefile);

    return tempfile;
}
示例#8
0
// Gets the next non-status message (meaning generic or console messages)
// from the aforementioned queues; whichever is the earliest. Returns false
// if there is no message to fetch, otherwise will set the message type,
// filename, line, and column parameters supplied. If the message retrieved
// did not contain this information, the relevent entry is either set to 0
// (line and column) or the empty string (filename). The filename parameter
// is a UCS2String.
bool vfeSession::GetNextNonStatusMessage (MessageType &Type, string& Message, UCS2String& File, int& Line, int& Col)
{
  POV_LONG                    mqTime = 0x7fffffffffffffffLL ;
  POV_LONG                    cqTime = 0x7fffffffffffffffLL ;
  boost::mutex::scoped_lock   lock(m_MessageMutex);

  if (m_MessageQueue.empty() && m_ConsoleQueue.empty())
    return (false);

  if (m_MessageQueue.empty() == false)
    mqTime = m_MessageQueue.front().m_TimeStamp ;
  if (m_ConsoleQueue.empty() == false)
    cqTime = m_ConsoleQueue.front().m_TimeStamp ;
  POV_LONG oldest = min (cqTime, mqTime);

  // if equal we give preference to the console queue
  if (oldest == cqTime)
  {
    MessageBase msg = m_ConsoleQueue.front();
    m_ConsoleQueue.pop();
    Type = msg.m_Type;
    Message = msg.m_Message;
    File.clear();
    Line = 0;
    Col = 0;
  }
  else
  {
    GenericMessage msg = m_MessageQueue.front();
    m_MessageQueue.pop();
    Type = msg.m_Type;
    Message = msg.m_Message;
    File = msg.m_Filename;
    Line = msg.m_Line;
    Col = msg.m_Col;
  }
  return (true);
}
示例#9
0
	/////////////////////////////////////////////////////////////////////////
	// case-sensitive string comparison
	bool vfeUnixSession::StrCompare (const UCS2String& lhs, const UCS2String& rhs) const
	{
		return lhs.compare(rhs);
	}
示例#10
0
  bool vfeParsePathString (const UCS2String& path, UCS2String& volume, vector<UCS2String>& components, UCS2String& filename)
  {
    char str [MAX_PATH * 4] ;

    volume.clear() ;
    filename.clear() ;
    components.clear() ;

    if (path.empty() == true)
      return (true);
    if (path.size () >= sizeof (str))
      return (false) ;
    strcpy (str, UCS2toASCIIString (path).c_str ()) ;
    char lastch = str[strlen(str) - 1];

    // now determine if it's a network or drive path.
    // (we could use the shlwapi functions here but I'd rather avoid the shlwapi.dll dependency).
    char *p2 = str ;
    char *p3 ;
    if ((strlen (str) > 1) && ((str [1] == ':') || (str[0] == '\\' && str[1] == '\\') || (str[0] == '/' && str[1] == '/')))
    {
      if (str [1] == ':')
      {
        // if it's a drive reference the first character must be in range 'a' - 'z'
        if (!isalpha (str[0]))
          return (false) ;

        // currently we don't support relative paths if a volume is specified
        if ((str [2] != '\\') && (str [2] != '/'))
          return (false) ;
        volume = ASCIItoUCS2String (string (str).substr (0, 3).c_str()) ;
        p2 += 3 ;
      }
      else
      {
        // it's a UNC path ... look for the next separator
        p2 = strchr (str + 2, '\\');
        p3 = strchr (str + 2, '/');
        if ((p3 != NULL) && ((p2 == NULL) || (p2-str) > (p3-str)))
            p2 = p3;
        if (p2 == NULL)
        {
          // no separator; technically this is valid, but it's a relative reference
          // and as above we don't currently support this.
          return (false) ;
        }
        volume = ASCIItoUCS2String (string (str).substr (0, (size_t) (++p2 - str)).c_str()) ;
      }
    }
    else if ((str [0] == '\\') || (str [0] == '/'))
    {
      // it's a path relative to the root of the current drive.
      // we will use '\' as the volume name.
      // for volume-relative paths we also accept '/' as a path separator
      volume = ASCIItoUCS2String("\\");
      p2++;
    }

    // p2 now points at the start of any path or file components
    // the first call to strtok will skip over any extra separators
    // at the start of the path
    for (char *p1 = strtok (p2, "\\/"); p1 != NULL; p1 = strtok (NULL, "/\\"))
    {
      if (*p1 == '\0')
        continue;
      if (p1[0] == '.' && p1[1] == '\0')
        continue;
      if (p1[0] == '.' && p1[1] == '.' && p1[2] == '\0')
      {
        // it's a relative directory reference ... see if we can pop a
        // path from components; if not we leave it in there since it
        // is permitted to refer to a directory above the CWD
        if ((components.empty() == false) && (components.back() != ASCIItoUCS2String("..")))
        {
          components.pop_back();
          continue;
        }
      }
      components.push_back (ASCIItoUCS2String (p1)) ;
    }

    // the filename, if present, will be the last entry in components.
    // we first check the last character of the supplied path to see
    // if it's a path separator char; if it is there's no filename.
    if (lastch == '\\' || lastch == '/')
      return true;

    if (components.empty() == false)
    {
      filename = components.back();
      components.pop_back();
    }

    return true ;
  }
示例#11
0
UCS2String BackendSceneData::FindFile(POVMSContext ctx, const UCS2String& filename, unsigned int stype)
{
    vector<UCS2String> filenames;
    UCS2String foundfile;
    bool tryExactFirst;

    // if filename extension, matches one of the standard ones, try the exact name first
    // (otherwise, try it last)
    UCS2String::size_type pos = filename.find_last_of('.');
    tryExactFirst = false;
    if (pos != UCS2String::npos)
    {
        for (size_t i = 0; i < POV_FILE_EXTENSIONS_PER_TYPE; i++)
        {
            if ( ( strlen(gPOV_File_Extensions[stype].ext[i]) > 0 ) &&
                 ( filename.compare(pos,filename.length()-pos, ASCIItoUCS2String(gPOV_File_Extensions[stype].ext[i])) == 0 ) )
            {
                // match
                tryExactFirst = true;
                break;
            }
        }
    }

    // build list of files to search for
    if (tryExactFirst)
        filenames.push_back(filename);

    // add filename with extension variants to list of files to search for
    for (size_t i = 0; i < POV_FILE_EXTENSIONS_PER_TYPE; i++)
    {
        if (strlen(gPOV_File_Extensions[stype].ext[i]) > 0)
        {
            UCS2String fn(filename);
            fn += ASCIItoUCS2String(gPOV_File_Extensions[stype].ext[i]);
            filenames.push_back(fn);
        }
    }

    if (!tryExactFirst)
        filenames.push_back(filename);

#ifdef USE_SCENE_FILE_MAPPING
    // see if the file is available locally
    for(vector<UCS2String>::const_iterator i(filenames.begin()); i != filenames.end(); i++)
    {
        FilenameToFilenameMap::iterator ilocalfile(scene2LocalFiles.find(*i));

        if(ilocalfile != scene2LocalFiles.end())
            return *i;
    }

    // see if the file is available as temporary file
    for(vector<UCS2String>::const_iterator i(filenames.begin()); i != filenames.end(); i++)
    {
        FilenameToFilenameMap::iterator itempfile(scene2TempFiles.find(*i));

        if(itempfile != scene2TempFiles.end())
            return *i;
    }
#endif

    // otherwise, request to find the file
    RenderBackend::SendFindFile(ctx, sceneId, frontendAddress, filenames, foundfile);

    return foundfile;
}
示例#12
0
IStream *BackendSceneData::ReadFile(POVMSContext ctx, const UCS2String& origname, const UCS2String& filename, unsigned int stype)
{
    UCS2String scenefile(filename);
    UCS2String localfile;
    UCS2String fileurl;

#ifdef USE_SCENE_FILE_MAPPING
    // see if the file is available locally
    FilenameToFilenameMap::iterator ilocalfile(scene2LocalFiles.find(scenefile));

    // if available locally, open it end return
    if(ilocalfile != scene2LocalFiles.end())
        return NewIStream(ilocalfile->second.c_str(), stype);

    // now try the original name as given in the scene
    if((ilocalfile = scene2LocalFiles.find(origname)) != scene2LocalFiles.end())
        return NewIStream(ilocalfile->second.c_str(), stype);

    // see if the file is available as temporary file
    FilenameToFilenameMap::iterator itempfile(scene2TempFiles.find(scenefile));

    // if available as temporary file, open it end return
    if(itempfile != scene2TempFiles.end())
        return NewIStream(itempfile->second.c_str(), stype);

    // otherwise, request the file
    RenderBackend::SendReadFile(ctx, sceneId, frontendAddress, scenefile, localfile, fileurl);

    // if it is available locally, add it to the map and then open it
    if(localfile.length() > 0)
    {
        scene2LocalFiles[scenefile] = localfile;
        local2SceneFiles[localfile] = scenefile;

        // yes this is a hack
        scene2LocalFiles[origname] = localfile;

        return NewIStream(localfile.c_str(), stype);
    }

    // if it is available remotely ...
    if(fileurl.length() > 0)
    {
        // create a temporary file
        UCS2String tempname = POV_PLATFORM_BASE.CreateTemporaryFile();
        OStream *tempfile = NewOStream(tempname.c_str(), stype, false);

        if(tempfile == NULL)
        {
            POV_PLATFORM_BASE.DeleteTemporaryFile(tempname);
            throw POV_EXCEPTION_CODE(kCannotOpenFileErr);
        }

        // download the file from the URL
        // TODO - handle referrer
        if(POV_PLATFORM_BASE.ReadFileFromURL(tempfile, fileurl) == false)
        {
            delete tempfile;
            POV_PLATFORM_BASE.DeleteTemporaryFile(tempname);
            throw POV_EXCEPTION_CODE(kNetworkConnectionErr);
        }

        delete tempfile;

        // add the temporary file to the map
        scene2TempFiles[scenefile] = tempname;
        temp2SceneFiles[tempname] = scenefile;

        return NewIStream(tempname.c_str(), stype);
    }

    // file not found
    return NULL;
#else
    return NewIStream(filename.c_str(), stype);
#endif
}
示例#13
0
bool Path::ParsePathString (UCS2String& volume, vector<UCS2String>& dirnames, UCS2String& filename, const UCS2String& path)
{
    UCS2String stash;

    // Unless noted otherwise, all components are considered empty.
    volume.clear();
    dirnames.clear();
    filename.clear();

    // Empty strings are considered valid path names, too.
    if (path.empty() == true)
        return true;

    UCS2String::const_iterator i = path.begin();

    // Check for a volume identifier:
    // - If the second character is a colon, we presume the first two characters to identify the drive. In that case
    //   we'll also check whether the following character is a path separator, indicating an absolute path on that
    //   drive, in which case we'll also include a trailing separator to the drive letter.
    // - If the path starts with two identical path separator characters, we presume the string to be a UNC path, in
    //   which case we set the volume identifier to the network share, including two leading and a trailing separator
    //   characters.
    // - Otherwise, if the first character is a path separator, this indicates an absolute path on the current drive,
    //   in which case we set the volume identifier to a single path separator character.
    // - In any other case, we presume the string to be a relative path, and set the volume identifier to an empty
    //   string.

    if ((*i == POV_PATH_SEPARATOR) || (*i == POV_PATH_SEPARATOR_2))
    {
        // String starts with a path separator; may be an absolute path on the current drive or a UNC path.

        // Stash the separator (use the canonical one, not the one actually used).
        stash += POV_PATH_SEPARATOR;
        ++i;

        if ((i != path.end()) && (*i == stash[0]))
        {
            // The second character is also an (identical) separator character, indicating a UNC path.

            // Stash another path separators (use the canonical one, not the one actually used).
            stash += POV_PATH_SEPARATOR;
            ++i;

            // Stash everything that follows, up to the next path separator.
            for (; (i != path.end()) && (*i != POV_PATH_SEPARATOR) && (*i != POV_PATH_SEPARATOR_2); ++i)
                stash += *i;

            // Currently, we don't support bare UNC share names without trailing separator character,
            // even though allegedly they are technically valid.
            if (i == path.end())
                return false;

            // Stash another path separator (use the canonical one, not the one actually used)
            // to indicate an absolute path.
            stash += POV_PATH_SEPARATOR;
            ++i;
        }
        // If it's not a UNC path, at this point our stash contains a single path separator,
        // which is exactly what we intend to emit as the volume identifier in that case.

        // Emit whatever string we have stashed as the volume identifier.
        volume = stash;
        stash.clear();
    }
    else if (isalpha (*i))
    {
        // String starts with an ASCII letter; may be a relative path or a drive letter.

        // Stash the character, then go on to test what's next.
        stash += *i;
        ++i;

        if ((i != path.end()) && (*i == ':'))
        {
            // Yup, that's a drive letter. Add the colon to the stashed letter.
            stash += ':';
            ++i;

            // Currently, we don't support relative paths if a volume is specified.
            if ((i == path.end()) || ((*i != POV_PATH_SEPARATOR) && (*i != POV_PATH_SEPARATOR_2)))
                return false;

            // Stash another path separator (use the canonical one, not the one actually used)
            // to indicate an absolute path.
            stash += POV_PATH_SEPARATOR;
            ++i;

            // Emit the stashed string as the volume identifier.
            volume = stash;
            stash.clear();
        }
        // If it's not a drive letter, at this point we have only stashed the first letter, but
        // our index still points to the second one so the following algorithm will take care of it.
    }

    // Walk through the path string, stashing any non-separator characters. Whenever we hit a separator
    // character, emit the stashed characters (if any) as a directory name and clear the stash.
    // Also, as we go along, resolve the special directory names `.` and `..` if possible.

    // NB since we do not emit "empty" directory names, any sequence of consecutive separator
    // characters is effectively treated as a single separator character.

    for(; i != path.end(); ++i)
    {
        if ((*i == POV_PATH_SEPARATOR) || (*i == POV_PATH_SEPARATOR_2))
        {
            if (!stash.empty() && !IsCurrentDir(stash))
            {
                if (!dirnames.empty() && IsParentDir(stash))
                    dirnames.pop_back();
                else
                    dirnames.push_back (stash);
                stash.clear();
            }
        }
        else
            stash += *i;
    }

    // Whatever is left in the stash is presumably the actual file name.

    // NB as a consequence of the algorithm chosen, any path name ending in a path separator
    // character will be emitted as a list of directories only, with the file name left empty.

    filename = stash;

    return true;
}
示例#14
0
/// Test for the special directory name denoting the parent directory (`..`).
static inline bool IsParentDir(const UCS2String& s)
{
    return (s.length() == 2) && (s[0] == '.') && (s[1] == '.');
}
示例#15
0
/// Test for the special directory name denoting the current directory (`.`).
static inline bool IsCurrentDir(const UCS2String& s)
{
    return (s.length() == 1) && (s[0] == '.');
}
示例#16
0
namespace Filesystem
{

//******************************************************************************

#if !POV_USE_DEFAULT_DELETEFILE

bool DeleteFile(const UCS2String& fileName)
{
    return (unlink(UCS2toSysString(fileName).c_str()) == 0);
}

#endif // POV_USE_DEFAULT_DELETEFILE

//******************************************************************************

#if !POV_USE_DEFAULT_LARGEFILE

#ifndef POVUNIX_LSEEK64
#define POVUNIX_LSEEK64(h,b,o) lseek(h,b,o)
#endif

using Offset = decltype(POVUNIX_LSEEK64(0,0,0));

static_assert(
    std::numeric_limits<Offset>::digits > 32,
    "Large files (> 2 GiB) not supported, limiting image size to approx. 100 Megapixels. Proceed at your own risk."
    );

struct LargeFile::Data final
{
    int handle;
    Data() : handle(-1) {}
};

LargeFile::LargeFile() :
    mpData(new Data)
{}

LargeFile::~LargeFile()
{
    Close();
}

bool LargeFile::CreateRW(const UCS2String& fileName)
{
    mpData->handle = open(UCS2toSysString(fileName).c_str(),
                          O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
    return (mpData->handle != -1);
}

bool LargeFile::Seek(std::int_least64_t offset)
{
    if (mpData->handle == -1)
        return false;
    if ((offset < 0) || (offset > std::numeric_limits<Offset>::max()))
        return false;
    return (POVUNIX_LSEEK64(mpData->handle, Offset(offset), SEEK_SET) == offset);
}

std::size_t LargeFile::Read(void* data, std::size_t maxSize)
{
    if (mpData->handle == -1)
        return false;
    return read(mpData->handle, data, int(maxSize));
}

bool LargeFile::Write(const void* data, std::size_t size)
{
    if (mpData->handle == -1)
        return false;
    return (write(mpData->handle, data, int(size)) == size);
}

void LargeFile::Close()
{
    if (mpData->handle != -1)
    {
        close(mpData->handle);
        mpData->handle = -1;
    }
}

#endif // POV_USE_DEFAULT_LARGEFILE

//******************************************************************************

#if !POV_USE_DEFAULT_TEMPORARYFILE

static UCS2String gTempPath;

void SetTempFilePath(const UCS2String& tempPath)
{
    gTempPath = tempPath;
}

UCS2String TemporaryFile::SuggestName()
{
    POV_ASSERT(!gTempPath.empty());

    // TODO FIXME - This allows only one temporary file per process!
    // TODO FIXME - Avoid converting back and forth between UCS-2 and system-specific encoding.
    char str [POV_FILENAME_BUFFER_CHARS + 1] = "";
    std::snprintf(str, POV_FILENAME_BUFFER_CHARS + 1, "%spov%d", UCS2toSysString(gTempPath).c_str(), int(getpid()));
    return SysToUCS2String(str);
}

#endif // POV_USE_DEFAULT_TEMPORARYFILE

//******************************************************************************

}