При сборке стилями DocBook XSL формата HTML dir и указании 'base.dir' 'путь с национальными символами или пробелом' xsltproc сначала кодирует нац. символы и пробел в %nn, а при создании файлов не раскодирует их обратно. Есть предложение собирать libxslt с таким патчем: diff -ur libxslt-1.1.15.orig/libxslt/transform.c libxslt-1.1.15/libxslt/transform.c --- libxslt-1.1.15.orig/libxslt/transform.c 2005-08-31 14:47:15 +0400 +++ libxslt-1.1.15/libxslt/transform.c 2006-04-06 15:07:00 +0400 @@ -2060,6 +2060,11 @@ } /* + * Unescape filename for non ASCII world + */ + filename = (xmlChar *) xmlURIUnescapeString((const char *)filename,0,NULL); + + /* * Security checking: can we write to this resource */ if (ctxt->sec != NULL) { См. http://bugzilla.gnome.org/show_bug.cgi?id=337486 Правда, автору говорили о проблеме ещё год назад, и похоже, что он в очередной раз упёрся рогом.
У меня тоже есть сомнения, что имена можно безопасно раскодировать. Из какого байтового представления имена файлов кодируются в URI encoding? В каком месте в libxslt происходит кодирование?
Автор не высказывал сомнений в безопасности раскодирования, он просто забил на баг репорт в рассылке. В libxml2-2.6.24 используется xmlURIUnescapeString для доступа к файлу, см. ниже. Почему она не используется при доступе к файлу в libxslt ? Насколько я понимаю, семантика там идентичная. /libxslt/transform.c ./xmlIO.c-772-/** ./xmlIO.c-773- * xmlFileOpen: ./xmlIO.c-774- * @filename: the URI for matching ./xmlIO.c-775- * ./xmlIO.c-776- * Wrapper around xmlFileOpen_real that try it with an unescaped ./xmlIO.c-777- * version of @filename, if this fails fallback to @filename ./xmlIO.c-778- * ./xmlIO.c-779- * Returns a handler or NULL in case or failure ./xmlIO.c-780- */ ./xmlIO.c-781-void * ./xmlIO.c-782-xmlFileOpen (const char *filename) { ./xmlIO.c-783- char *unescaped; ./xmlIO.c-784- void *retval; ./xmlIO.c-785- ./xmlIO.c:786: unescaped = xmlURIUnescapeString(filename, 0, NULL); ./xmlIO.c-787- if (unescaped != NULL) { ./xmlIO.c-788- retval = xmlFileOpen_real(unescaped); ./xmlIO.c-789- xmlFree(unescaped); ./xmlIO.c-790- } else { ./xmlIO.c-791- retval = xmlFileOpen_real(filename); ./xmlIO.c-792- } ./xmlIO.c-793- return retval; ./xmlIO.c-794-} Обсуждения проблемы на тему чтения из файла: http://mail.gnome.org/archives/xslt/2001-July/msg00026.html http://mail.gnome.org/archives/xml/2005-August/msg00019.html Обсуждение на тему exsl:document сходу не нашёл. В любом случае, при записи в файл нужно открывать файл, а не пытаться открыть URI. Проблему с отсутствием явной кодировки я понимаю, и есть мнение, что filename -> escape -> unescape даёт filename независимо от кодировки, потому что функции кодирования/декодирования работают побайтно (AFAIK). Мнение подтверждается тем фактом, что с приложенным патчем у меня работает нормально запись в файлы с пробелами в именах. Под win32 и linux. Запись в файлы с именами в latin1 тоже работает.
В предыдущий комментарий строка: libxslt/transform.c попала по ошибке.
Да, поскольку в <exsl:document> именно URI, то его нужно раскодировать. Сделаю.
Как насчет доработать патч на предмет избавления от утечки памяти? Первый буфер, на который указывает filename, после преобразования просто теряется. Я могу это сделать сам, но позже.
Через несколько строк в коде после предлагаемого изменения вызывается xsltCheckWrite, которая, судя по документации, тоже хочет URI. И outputFile в xsltTransformContext должен быть URI. Наверное, перекодировка должна происходить все-таки позже и уровнем ниже (т.к. должен сработать и xsltCheckWrite, и последующая запись). В существуюм виде патч применять воздержусь, нужно смотреть еще.
Fixed in libxml2-2.6.26-alt2 and libxslt-1.1.17-alt1. See the GNOME bug for details.
Ваш патч впечатляет, спасибо!