mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
HTML Input: Fix handling of @import rules in stylesheets nested more than one level deep. Fixes #1930922 [Incorrect interpretation of CSS @import](https://bugs.launchpad.net/calibre/+bug/1930922)
This commit is contained in:
parent
0818d3a110
commit
9040501684
@ -177,6 +177,7 @@ class HTMLInput(InputFormatPlugin):
|
|||||||
self.urlnormalize, self.DirContainer = urlnormalize, DirContainer
|
self.urlnormalize, self.DirContainer = urlnormalize, DirContainer
|
||||||
self.urldefrag = urldefrag
|
self.urldefrag = urldefrag
|
||||||
self.guess_type, self.BINARY_MIME = guess_type, BINARY_MIME
|
self.guess_type, self.BINARY_MIME = guess_type, BINARY_MIME
|
||||||
|
self.stylesheets_to_process = []
|
||||||
|
|
||||||
self.log('Rewriting HTML links')
|
self.log('Rewriting HTML links')
|
||||||
for f in filelist:
|
for f in filelist:
|
||||||
@ -190,15 +191,14 @@ class HTMLInput(InputFormatPlugin):
|
|||||||
item = oeb.manifest.hrefs[urlnormalize(href)]
|
item = oeb.manifest.hrefs[urlnormalize(href)]
|
||||||
rewrite_links(item.data, partial(self.resource_adder, base=dpath))
|
rewrite_links(item.data, partial(self.resource_adder, base=dpath))
|
||||||
|
|
||||||
for item in oeb.manifest.values():
|
while self.stylesheets_to_process:
|
||||||
|
sheet = self.stylesheets_to_process.pop()
|
||||||
|
css_parser.replaceUrls(sheet.data, partial(self.resource_adder, base=sheet.html_input_dirpath))
|
||||||
|
for item in oeb.manifest:
|
||||||
if item.media_type in self.OEB_STYLES:
|
if item.media_type in self.OEB_STYLES:
|
||||||
dpath = None
|
item.resolve_css_imports = True
|
||||||
for path, href in self.added_resources.items():
|
item.override_css_fetch = None
|
||||||
if href == item.href:
|
item.reparse_css()
|
||||||
dpath = os.path.dirname(path)
|
|
||||||
break
|
|
||||||
css_parser.replaceUrls(item.data,
|
|
||||||
partial(self.resource_adder, base=dpath))
|
|
||||||
|
|
||||||
toc = self.oeb.toc
|
toc = self.oeb.toc
|
||||||
self.oeb.auto_generated_toc = True
|
self.oeb.auto_generated_toc = True
|
||||||
@ -272,10 +272,11 @@ class HTMLInput(InputFormatPlugin):
|
|||||||
if not self.is_case_sensitive(tempfile.gettempdir()):
|
if not self.is_case_sensitive(tempfile.gettempdir()):
|
||||||
link = link.lower()
|
link = link.lower()
|
||||||
if link not in self.added_resources:
|
if link not in self.added_resources:
|
||||||
|
guessed = self.guess_type(os.path.basename(link))[0]
|
||||||
|
media_type = guessed or self.BINARY_MIME
|
||||||
|
is_stylesheet = media_type in self.OEB_STYLES
|
||||||
bhref = os.path.basename(link)
|
bhref = os.path.basename(link)
|
||||||
id, href = self.oeb.manifest.generate(id='added', href=sanitize_file_name(bhref))
|
id, href = self.oeb.manifest.generate(id='added', href=sanitize_file_name(bhref))
|
||||||
guessed = self.guess_type(href)[0]
|
|
||||||
media_type = guessed or self.BINARY_MIME
|
|
||||||
if media_type == 'text/plain':
|
if media_type == 'text/plain':
|
||||||
self.log.warn('Ignoring link to text file %r'%link_)
|
self.log.warn('Ignoring link to text file %r'%link_)
|
||||||
return None
|
return None
|
||||||
@ -289,7 +290,7 @@ class HTMLInput(InputFormatPlugin):
|
|||||||
if img:
|
if img:
|
||||||
media_type = self.guess_type('dummy.'+img)[0] or self.BINARY_MIME
|
media_type = self.guess_type('dummy.'+img)[0] or self.BINARY_MIME
|
||||||
|
|
||||||
self.oeb.log.debug('Added', link)
|
self.oeb.log.debug('Added', link, 'with href:', href)
|
||||||
self.oeb.container = self.DirContainer(os.path.dirname(link),
|
self.oeb.container = self.DirContainer(os.path.dirname(link),
|
||||||
self.oeb.log, ignore_opf=True)
|
self.oeb.log, ignore_opf=True)
|
||||||
# Load into memory
|
# Load into memory
|
||||||
@ -300,9 +301,11 @@ class HTMLInput(InputFormatPlugin):
|
|||||||
if isinstance(bhref, unicode_type):
|
if isinstance(bhref, unicode_type):
|
||||||
bhref = bhref.encode('utf-8')
|
bhref = bhref.encode('utf-8')
|
||||||
item.html_input_href = as_unicode(quote(bhref))
|
item.html_input_href = as_unicode(quote(bhref))
|
||||||
if guessed in self.OEB_STYLES:
|
if is_stylesheet:
|
||||||
item.override_css_fetch = partial(
|
item.html_input_dirpath = os.path.dirname(link)
|
||||||
self.css_import_handler, os.path.dirname(link))
|
item.resolve_css_imports = False
|
||||||
|
item.override_css_fetch = lambda url: (None, '')
|
||||||
|
self.stylesheets_to_process.append(item)
|
||||||
item.data
|
item.data
|
||||||
self.added_resources[link] = href
|
self.added_resources[link] = href
|
||||||
|
|
||||||
@ -310,16 +313,3 @@ class HTMLInput(InputFormatPlugin):
|
|||||||
if frag:
|
if frag:
|
||||||
nlink = '#'.join((nlink, frag))
|
nlink = '#'.join((nlink, frag))
|
||||||
return nlink
|
return nlink
|
||||||
|
|
||||||
def css_import_handler(self, base, href):
|
|
||||||
link, frag = self.link_to_local_path(href, base=base)
|
|
||||||
if link is None or not os.access(link, os.R_OK) or os.path.isdir(link):
|
|
||||||
return None, None
|
|
||||||
try:
|
|
||||||
with open(link, 'rb') as f:
|
|
||||||
raw = f.read().decode('utf-8', 'replace')
|
|
||||||
raw = self.oeb.css_preprocessor(raw, add_namespace=False)
|
|
||||||
except:
|
|
||||||
self.log.exception('Failed to read CSS file: %r'%link)
|
|
||||||
return None, None
|
|
||||||
return None, raw
|
|
||||||
|
@ -279,7 +279,7 @@ def rewrite_links(root, link_repl_func, resolve_base_href=False):
|
|||||||
el.attrib[attrib] = new
|
el.attrib[attrib] = new
|
||||||
|
|
||||||
parser = CSSParser(raiseExceptions=False, log=_css_logger,
|
parser = CSSParser(raiseExceptions=False, log=_css_logger,
|
||||||
fetcher=lambda x:(None, None))
|
fetcher=lambda x:(None, ''))
|
||||||
for el in root.iter(etree.Element):
|
for el in root.iter(etree.Element):
|
||||||
try:
|
try:
|
||||||
tag = el.tag
|
tag = el.tag
|
||||||
@ -922,6 +922,7 @@ class Manifest(object):
|
|||||||
self.media_type = media_type
|
self.media_type = media_type
|
||||||
self.fallback = fallback
|
self.fallback = fallback
|
||||||
self.override_css_fetch = None
|
self.override_css_fetch = None
|
||||||
|
self.resolve_css_imports = True
|
||||||
self.spine_position = None
|
self.spine_position = None
|
||||||
self.linear = True
|
self.linear = True
|
||||||
if loader is None and data is None:
|
if loader is None and data is None:
|
||||||
@ -986,7 +987,8 @@ class Manifest(object):
|
|||||||
fetcher=self.override_css_fetch or self._fetch_css,
|
fetcher=self.override_css_fetch or self._fetch_css,
|
||||||
log=_css_logger)
|
log=_css_logger)
|
||||||
data = parser.parseString(data, href=self.href, validate=False)
|
data = parser.parseString(data, href=self.href, validate=False)
|
||||||
data = resolveImports(data)
|
if self.resolve_css_imports:
|
||||||
|
data = resolveImports(data)
|
||||||
for rule in tuple(data.cssRules.rulesOfType(CSSRule.PAGE_RULE)):
|
for rule in tuple(data.cssRules.rulesOfType(CSSRule.PAGE_RULE)):
|
||||||
data.cssRules.remove(rule)
|
data.cssRules.remove(rule)
|
||||||
return data
|
return data
|
||||||
@ -1054,6 +1056,9 @@ class Manifest(object):
|
|||||||
def data(self):
|
def data(self):
|
||||||
self._data = None
|
self._data = None
|
||||||
|
|
||||||
|
def reparse_css(self):
|
||||||
|
self._data = self._parse_css(str(self))
|
||||||
|
|
||||||
def unload_data_from_memory(self, memory=None):
|
def unload_data_from_memory(self, memory=None):
|
||||||
if isinstance(self._data, bytes):
|
if isinstance(self._data, bytes):
|
||||||
if memory is None:
|
if memory is None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user