Поиск каталога в старом коде C++, вызывающий ошибку каталога в OS X Catalina 10.15

Это узкоспециализированный вопрос, надеюсь, вы мне поможете.

У меня есть ОЧЕНЬ старый проект (примерно 2010 г. - работающий на XCODE 3.2). Он написан на комбинации C ++, а также в некоторых программах с использованием библиотеки JUCE для разработки аудио-плагинов - он компилируется как Audio Unit и VST.

У меня проблема в том, что с тех пор, как вышла OS X Catalina, поиск каталогов в OS X был поврежден.

Вместо того, чтобы указывать на

/Volumes/Macintosh HD/Library/Application Support/Company Name/Product Name/Presets/

он начал указывать на

 /Volumes/Macintosh HD///Macintosh HD/Library/Application Support/Company Name/Product Name/Presets/

Когда это происходит, плагин просто падает и не проходит проверку ни в одной DAW для создания музыки.

Я просмотрел проект и определил следующую область

#ifdef _Mac
  tchar psz[1024]
  IFile::GetSystemDirectory(IFile::SystemDirApplicationSupport, psz);
  sPathName = std::string(psz);
  sPathName += msCompanyName;
  sPathName += ":";
  sPathName += msProductName;
  sPathName += ":Presets:";
#else
  //windows stuff
#endif

return sPathName:

кажется, что-то делать с IFile::SystemDirApplicationSupport ? по какой-то причине сейчас с Каталиной что-то не так, но я не знаю, как это обойти

Любая помощь будет принята с благодарностью - РЕДАКТИРОВАТЬ

Итак, я нашел некоторые из внутренних библиотек

ниже вы можете увидеть GetSystemDirectory и т. д.

IFile.h

    /*! \class IFile
 * \brief Interface for accessing files
 *
 * Note that a file cannot be opened for simultaneous reading and writing
*/

class IFile : public virtual IDestructable

{
public:
//! Creates IFile
static IFile* Create();

//! Enum for defining file access (read / write / create)
enum EOpenFile {
    //! Open file for reading only
    FileRead = 0,
    //! Open file for writing only. File must already exist.
    FileWrite,
    //! Open file for writing only. File may or may not already exist. If already existing it will be deleted.
    FileCreate
};

//! Open file, given filename (full path)
/*!
    \param pszPathName [in]: File to open (full path name).
    \param OpenFile [in]: File access to open with
    \return bool: true if success, false otherwise
*/
virtual tbool Open(const tchar* pszPathName, EOpenFile OpenFile) = 0;

//! Close is automatically called when opening a new file, or when destroying object. However you can call it manually if desired
virtual void Close() = 0;

//! Read from file
/*!
    \param pch [out]: Buffer to be filled
    \param iSize [in]: Number of bytes to read
    \return tuint64: Number of bytes actually read
*/
virtual tuint64 Read(tchar* pch, tuint64 iSize) = 0;

//! Write to file
/*!
    \param pch [in]: Buffer to write
    \param iSize [in]: Number of bytes to write
    \return tuint64: Number of bytes actually written
*/
virtual tuint64 Write(const tchar* pch, tuint64 iSize) = 0;

//! Seek to new position (from start of file). After opening file the position is always 0.
/*!
    \param iPos [in]: Position to seek to (from start of file)
    \return tuint64: New position
*/
virtual tuint64 Seek(tuint64 iPos) = 0;

//! Returns the size of file when it was initially opened
/*!
    \return tuint64: Size of file when it was initially opened
*/
virtual tuint64 GetSizeWhenOpened() const = 0;

//! Returns current file position
/*!
    \return tuint64: Current file position
*/
virtual tuint64 GetCurrentFilePosition() const = 0;

//! Gets (full) path name used when opening file
/*!
    \param pszPathName [out]: Pointer to buffer of min. 513 characters to be filled with path name
*/
virtual void GetPathName(tchar* pszPathName) const = 0;

//! Reads tint32's with automatic crossplatform swapping
/*!
    \param p [in]: Buffer to read into
    \param iSize [in]: Number of tint32's to read
    \return tuint64: Number of tint32's actually read
*/
virtual tuint64 ReadCP(tint32* p, tuint64 iSize) = 0;

//! Writes tint32's with automatic crossplatform swapping
/*!
    \param p [in]: Buffer to write
    \param iSize [in]: Number of tint32's to write
    \return tuint64: Number of tint32's actually write
*/
virtual tuint64 WriteCP(tint32* p, tuint64 iSize) = 0;

//! Reads tfloat32's with automatic crossplatform swapping
/*!
    \param p [in]: Buffer to read into
    \param iSize [in]: Number of tfloat32's to read
    \return tuint64: Number of tfloat32's actually read
*/
virtual tuint64 ReadCP(tfloat32* p, tuint64 iSize) = 0;

//! Writes tfloat32's with automatic crossplatform swapping
/*!
    \param p [in]: Buffer to write
    \param iSize [in]: Number of tfloat32's to write
    \return tuint64: Number of tfloat32's actually write
*/
virtual tuint64 WriteCP(tfloat32* p, tuint64 iSize) = 0;

//! Static call to delete a file
/*!
    \param pszPathName [in]: Full path name of file to delete
    \return tbool: If success true, otherwise false
*/
static tbool DeleteFile(const tchar* pszPathName);

//! Static call to move a file
/*!
    \param pszPathNameDest [in]: Path name of destination directory
    \param pszPathNameSrc [in]: Path name of source directory
    \param pszName [in]: Name of file
    \return tbool: If success true, otherwise false
*/
static tbool MoveFile(const tchar* pszPathNameDest, const tchar* pszPathNameSrc, const tchar* pszName);

//! Static call to copy a file
/*!
    \param pszPathNameDest [in]: Path name of destination directory
    \param pszPathNameSrc [in]: Path name of source directory
    \param pszName [in]: Name of file
    \return tbool: If success true, otherwise false
*/
static tbool CopyFile(const tchar* pszPathNameDest, const tchar* pszPathNameSrc, const tchar* pszName);

static tbool CopyFile(const tchar* pszPathNameDest, const tchar* pszPathNameSrc);

//! Static call to create a directory
/*!
    \param pszPathName [in]: Pathname of directory to create. May or may not have ending deliminator ('\' or ':')
    \return tbool: If success true, otherwise false. Call may return false if the directory already exists.
*/
static tbool CreateDirectory(const tchar* pszPathName);

//! Enumeration of system directories
enum ESystemDir {
    //! OSX: Users Preferences directory. Win32: Not valid
    SystemDirPreferences = 0,
    //! OSX: Users desktop. Win32: Users desktop.
    SystemDirDesktop,
    //! OSX: Application directory. Win32: "Program files" directory (use with caution, since application may be installed in custom location!)
    SystemDirApplications,
    //! OSX: Not implemented (should be users documents directory). Win32: Users documents directory.
    SystemDirDocuments,
    //! OSX: /Library/Application Support. Win32: "Program Files\Common" directory
    SystemDirApplicationSupport,
    //! OSX: The 'Music' folder inside the users private folder. Win32: The 'My Music' folder inside the users Documents folder
    SystemDirMyMusic,
    //! OSX: "Chewable" folder that gets cleaned upon boot. Win32: Temporary folder (same as TEMP env-variable).
    SystemDirScratch,
    //! OSX: Not implemented. Win32: Common application data folder
    SystemDirAppData
};

//! Static call to get system directory
/*!
    \param SystemDir [in]: Directory to get.
    \param pszPathName [out]: Returned full path name. Must be preallocated with minimum 513 bytes.
*/
static void GetSystemDirectory(ESystemDir SystemDir, tchar* pszPathName);

//! Converts from OS specific path to internal path. Only works with full paths (not relative).
/*!
    \param pszPathName [in/out]: Path to be converted. Returns converted path. Note that returned path may be 1 byte longer than the input path.
*/
static void PathFromOS(tchar* pszPathName);

//! Converts from internal path to OS specific path. Only works with full paths (not relative).
/*!
    \param pszPathName [in/out]: Path to be converted. Returns converted path.
*/
static void PathToOS(tchar* pszPathName);

//! Converts an OS format path to internal format (':' separated)
/*!
 \param pszPathNameIn [in]: The path to convert. It can be relative or absolute path, may include filename or not, and it may already be in internal format (won't fail).
 \param pszPathNameOut [out]: The converted path (you can enter the same pointer for in and out to provide in-place convertion, it won't crash).
 \param bMakeAbsPath [in]: True: the converted path will be prepended the current working directory (but only if it is not already an absolute path).
 \param pbIsAbsPath [out]: True: the converted path is absolute, false: the converted path is relative (doesn't start with '/').
 \return tbool: True upon convertion success, false upon internal error. Will almost always return true, since fail-tolerance is high.
 */
static tbool PathFromOS2(const tchar* pszPathNameIn, tchar* pszPathNameOut, tbool bMakeAbsPath = true, tbool* pbIsAbsPath = NULL);

//! Converts any internal format path to OS format (i.e. for Mac OS X => POSIX format, for Windows => DOS format)
/*!
 \param pszPathNameIn [in]: The path to convert. It can be relative or absolute path, may include filename or not, and it may already be in OS format (won't fail).
 \param pszPathNameOut [out]: The converted path (you can enter the same pointer for in and out to provide in-place convertion, it won't crash).
 \param bMakeAbsPath [in]: True: the converted path will be prepended the current working directory (but only if it is not already an absolute path).
 \param pbIsAbsPath [out]: True: the converted path is absolute, false: the converted path is relative (doesn't start with '/').
 \return tbool: True upon convertion success, false upon internal error. Will almost always return true, since fail-tolerance is high.
 */
static tbool PathToOS2(const tchar* pszPathNameIn, tchar* pszPathNameOut, tbool bMakeAbsPath = true, tbool* pbIsAbsPath = NULL);

//! Checks if a string represents an absolute path
/*!
 \param pszPathName [in]: The path to check. It may be in OS or internal format
 \return tbool: True if path is absolute
 */
static tbool IsAbsPath2(const tchar* pszPathName);

//! Checks if a string points to an existing file or folder
/*!
    \param pszItem [in]: The item to check the existance of
    \param pbIsFolder [out]: True if existing item is a folder, False if not.<br>Omit parameter if you don't care
    \return tbool: True if item is an existing file or folder
*/
static tbool Exists(const tchar* pszItem, tbool* pbIsFolder = NULL);

//! Split a full path into a path-only and a filename-only part
/*!
    \param pszFullPath [in]: The full path to split
    \param pszPathOnly [out]: The path-only part. Should be preallocated with 512 or more bytes.
    \param pszNameOnly [out]: The name-only part. Should be preallocated with 512 or more bytes.
    \param bAcceptEmptyPath [in]: True = won't fail even if the "full path" input consisted of only a name part
    \param bAcceptEmptyName [in]: True = won't fail even if there was no filename in full path (it pointed to a path instead of a file)
    \return tbool: True = Success, the two output strings were updated
*/
static tbool SplitPathToPathAndName(const tchar* pszFullPath, tchar* pszPathOnly, tchar* pszNameOnly, tbool bAcceptEmptyPath = true, tbool bAcceptEmptyName = true);

//! Creates an enum string with the names of all valid disk drives
/*
    \param pszEnumNames [out]: Receives the drive letters (Windows) or names (OS X) as an enum string delimited by a char of your name
    \param iBuffSize [in]: Max number of chars to place in the buffer (including trailing zero)
    \param cDelimiter [in]: Character used for delimiting enum string
    \param bAddExtraInfo [in]: For Windows: Returns not only the drive letter but also the volume name. For OS X: Ignored.
    \return tbool: True upon success, False if insufficient buffer space (or other error)
*/
static tbool GetDriveNames(tchar* pszEnumNames, tint32 iBuffSize = -1, char cDelimiter = '@', tbool bAddExtraInfo = false);

virtual int GetLastError() = 0;
};

person Bryan Spence    schedule 21.05.2020    source источник
comment
Является ли IFile частью JUCE? У вас есть источник для этого? Можешь показать? Использование двоеточия (:) в качестве разделителя пути предполагает, что код использует (или пытается использовать) старые пути в стиле HFS.   -  person Ken Thomases    schedule 21.05.2020
comment
@KenThomases, поэтому я думал, что IFile - это системная библиотека, но я только что нашел ее - я включу ее выше   -  person Bryan Spence    schedule 21.05.2020
comment
Это показывает объявление статической функции-члена GetSystemDirectory, но не ее определение.   -  person Ken Thomases    schedule 21.05.2020


Ответы (1)


Текущий правильный способ получить путь к общему каталогу поддержки приложений требует использования Objective-C. Вы можете добавить в проект один исходный файл Objective-C и связать его с остальными. Интерфейс между этим и остальным кодом может быть простым C.

Например:

void GetLocalApplicationSupportDirectory(char *out, size_t capacity)
{
    if (!out || !capacity)
        return;

    NSArray<NSString*>* dirs = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSLocalDomainMask, YES);
    if (dirs.count == 0)
    {
        out[0] = 0;
        return;
    }

    const char *dir = dirs[0].fileSystemRepresentation;
    if (strlen(dir) >= capacity)
    {
        out[0] = 0;
        return;
    }

    strcpy(out, dir);
}

Это создаст строку пути в стиле POSIX, содержащую что-то вроде «/Volumes/Macintosh HD/Library/Application Support». Затем вы можете добавить другие имена каталогов, но вы должны использовать символ «/» в качестве разделителя.

Обратите внимание, что это не замена кода, который вы показали, потому что этот код создал путь в стиле HFS вида ":Macintosh HD:Library:Application Support:…". Предположительно, вызывающий код также ожидает путь в стиле HFS, хотя я предполагаю, что в какой-то момент он преобразуется в путь в стиле POSIX, потому что это то, что вы утверждаете, что он содержит.

Если вам нужно преобразовать эти два стиля пути, вы можете использовать CFURLCreateWithFileSystemPath() и CFURLCopyFileSystemPath(), оба из Core Foundation. Это чистый C. Однако ошибка, которую вы видите в Catalina, может быть следствием того, что эти подпрограммы перестают работать должным образом.

person Ken Thomases    schedule 21.05.2020
comment
спасибо, Кен, это очень помогло - мне удалось найти поиск файлов в JUCE, который делал то же самое, используя File::getSpecialLocation(File::commonApplicationDataDirectory); Каталоги теперь кажутся точными, но сбой остается, поэтому я думаю, что это что-то еще, возможно, как вы говорите, связанное со стилями пути или чем-то еще ... все еще исследую - person Bryan Spence; 27.05.2020