Pull to refresh

О том как я имя файла из С++ в Java передавал

Reading time3 min
Views1.7K
image
В кроссплатформенных приложениях чего только не встретишь. Или напишешь. Вот, намедни родили против шерсти очередного ежика наступили на заботливо разложенных грабель, на сей раз под маком.



Напомню предыдущую серию саги: грабли под Windows.

То есть у нас все тот же экзотический еж + питон = колючая проволока. На сей раз счастье привалило нам попался сюрприз на маке. Java в InDesign интегрировали, работает, теперь надо имя файла передать нашему коду на Java написанному.

Темный рыцарь: начало


Начиналось все так обыденно:
void FooExpFilter::ExportToStream(
	IPMStream* stream, IDocument* doc, IPMUnknown* targetboss, 
	const PMString& formatName, UIFlags uiFlags)
{
	IDFile outputFile;
	InterfacePtr<IFileStreamData> fileData(stream, IID_IFILESTREAMDATA);
	outputFile = fileData->GetSysFile();

	SDKFileHelper fh(outputFile);

	PMString pathID = fh.GetPath();
	WideString pathWID(pathID);
	std::string xID;
	StringUtils::ConvertWideStringToUTF8 (pathWID, xID);

и работало на маке и на Windows. Пока InDesign не дорос до версии CS5.5. И тут счастье наступило приехал в лог наш любимый и эпический java.io.FileNotFoundException.

Звездные войны: империя наносит ответный удар


В сторону: вот эти записи в лог «как бы чего не вышло» очень помогают, рекомендую. Если конечно логи с умом писать, а то (лично видел!) однажды от обилия логов получился performance degradation и «кодярник» (С) лог 40 секунд писал, а без лога полсекунды работает. Индусы постарались — написали свой log4j с блэкджеком но без буферизации.

Получаем лог от клиента, а там — Macintosh HD::Foo::Bar!

Приезжайте к нам в Простоквашино — если у вас нет бальных платьев


Быстрое гугление (как перевести карбоно-маковые пути в Unix) приводит к подробной инструкции, как переводить руками с учетом mount points. И applescript в качестве примера, что и в каком порядке у Finder спрашивать. Ага, ага — нам вот только ObjectiveC не хватало для полного счастья.

Хлебнув полведра кофе, и погрепав Adobe SDK, находим решение, достойное ithappens. Вот оно.

	IDFile outputFile;
	InterfacePtr<IFileStreamData> fileData(stream, IID_IFILESTREAMDATA);
	outputFile = fileData->GetSysFile();

	// URL for java
	PMString pathJ = FileUtils::SysFileToFileURL(outputFile);
	WideString pathWJ(pathJ);
	std::string xj;
	StringUtils::ConvertWideStringToUTF8 (pathWJ, xj);

и в Java появляются еще 3 строчки:
	if(externFile.startsWith("file://")) {
		File externFd = new File(new java.net.URI(externFile));
		externFile = externFd.getAbsolutePath();
	}


То есть, не найдя как передать путь, мы передали… URL!

И это даже работает.

Disclaimer: не откажусь от правильного примера — как перевести карбоновые пути в Unix без ObjectiveC. Хоть и неактуально, но интересно. Если оно вообще есть, а не «отрезать голову и поменять :: на /», неправильно я и сам умею.

Игры разума: как можно было сделать лучше


Update 1: notorca навел на мысль использовать маковую CFURLCopyFileSystemPath:

void FooExpFilter::ExportToStream(
    IPMStream* stream, IDocument* doc, IPMUnknown* targetboss, 
    const PMString& formatName, UIFlags uiFlags)
{
    IDFile outputFile;
    InterfacePtr<IFileStreamData> fileData(stream, IID_IFILESTREAMDATA);
    outputFile = fileData->GetSysFile();

#ifdef WINDOWS
    SDKFileHelper fh(outputFile);
    PMString pathID = fh.GetPath();
#endif
#ifdef MACINTOSH			
    FSSpec fsSpec;
    PMString pathID;
    OSErr err = FileUtils::IDFileToFSSpec(outputFile, fsSpec);
    if (err == noErr) {
        FSRef fsRef;
        err = MacFileUtils::FSSpecToFSRef(fsSpec, fsRef);
        if (err == noErr) {
            CFURLRef appURL = ::CFURLCreateFromFSRef(NULL, &fsRef);
            CFStringRef app_str = ::CFURLCopyFileSystemPath(appURL, kCFURLPOSIXPathStyle);
            if (app_str) {
                pathID.SetCFString(app_str);
                ::CFRelease(app_str);
            }
            if (appURL) ::CFRelease(appURL);
        }
    }
#endif
    WideString pathWID(pathID);
    std::string xID;
    StringUtils::ConvertWideStringToUTF8 (pathWID, xID);


Update 2: А strizh дал еще одну подсказку — можно было использовать FileUtils::FileURLToPosixPath, в этом случае код становится таким:

    IDFile outputFile;
    InterfacePtr<IFileStreamData> fileData(stream, IID_IFILESTREAMDATA);
    outputFile = fileData->GetSysFile();

#ifdef WINDOWS
    SDKFileHelper fh(outputFile);
    PMString pathID = fh.GetPath();
    WideString pathWID(pathID);
    std::string xfinal;
    StringUtils::ConvertWideStringToUTF8 (pathWID, xfinal);
#endif
#ifdef MACINTOSH			
    PMString pathJ = FileUtils::SysFileToFileURL(outputFile);
    WideString pathWJ(pathJ);
    std::string xj;
    StringUtils::ConvertWideStringToUTF8 (pathWJ, xj);
    std::string xfinal = FileUtils::FileURLToPosixPath(xj);
#endif


Так что если через URL — то варианты есть. Без перехода path -> URL -> posix path пока подсказок не поступало (нет, я все еще не согласен тащить с собой кусок на ObjectiveC).
Tags:
Hubs:
Total votes 34: ↑27 and ↓7+20
Comments13

Articles