barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

вторник, 6 декабря 2011 г.

Расширение Firefox: Получение пути к файлу xpi-пакета расширения из JavaScript

Задача:
Из JavaScript-кода расширения Firefox получить путь (полноценный абсолютный путь файловой системы) к какому-либо файлу из xpi-пакета приложения, который при установке расширения распаковывается в AppData пользователя. Например, пусть нужен путь к файлу ext.dll, размещенного в папке "components/" xpi-архива, для его последующей загрузки функцией ctypes.open() библиотеки ctypes.

Решение:
Для версий Firefox 4.0+ (Gecko 2.0 и выше) имеется компонент AddonManager, предназначенный для работы с расширениями, и, в частности, позволяющий получать абсолютные пути к любым ресурсам расширения следующим образом:
addonId = "myaddon@somesite.org";// id, указанный в теге <em:id> install.rdf расширения
Components.utils.import("resource://gre/modules/AddonManager.jsm");
AddonManager.getAddonByID(addonId, function(addon)
{
var uri = addon.getResourceURI("components/ext.dll");
if (uri instanceof Components.interfaces.nsIFileURL && uri.file.path)
{
// работаем с путем uri.file.path, например, сохраняем его в какой-нибудь переменной, видимой снаружи
}
else
console.debug(addonId+": getAddonByID callback: uri is not Components.interfaces.nsIFileURL or uri.file.path is null or empty");
});
Однако, если Вам необходимо, чтобы Ваше расширение работало и в Firefox 3.6, придется изменить подход (вернее, можно использовать код, приведенный выше, для новых FF, и отдельный код для 3.6). Вызвана такая необходимость отсутствием в 3.6 AddonManager`а. Выход следующий: разместить файл, к которому нужно получить доступ, в chrome-реестре браузера, после чего воспользоваться преобразованием Chrome URI -> путь файловой системы. Размещение файла в chrome-реестре описывается в chrome.manifest файле расширения. В моем случае оно выглядело так (я продублировал нужную мне dll-ку, поместив её также в chrome/content/ xpi-пакета):
content     myaddon     chrome/content/
Теперь моя dll-ка доступна по chrome-пути "chrome://myaddon/content/ext.dll" (можно проверить, набрав такой URL в браузере). Для того, чтобы получить к ней абсолютный путь файловой системы, понадобится чуть больше кода, чем для 2ого Gecko (для работы данного кода нужен также енкодер/декодер URL, код которого я приводил тут):
/**
* Создает объект URI (реализующий интерфейс nsIURI) из переданной строки-URI, и, опционально, кодировки и базового URI
*/
function makeURI(aURL, aOriginCharset, aBaseURI)
{
var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
return ioService.newURI(aURL, aOriginCharset, aBaseURI);
}
/**
* Получает путь в фаловой системе к объекту, хранимому в chrome-реестре FF.
*/
function getFilepathFromChromeURL(chromeURL)
{
var chromeRegistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"].getService(Components.interfaces.nsIChromeRegistry);
var convertedURI;
try
{
convertedURI = chromeRegistry.convertChromeURL(makeURI(chromeURL,null,null));
}
catch(ex)
{
return false; }
if(convertedURI.scheme!="file")
return false;
return Url.decode(convertedURI.path.substring(1));
}
myPath = getFilepathFromChromeURL("chrome://myaddon/content/ext.dll");
В итоге в переменной myPath мы получим абсолютный путь к искомому файлу или false при ошибке.

Комментариев нет:

Отправить комментарий