mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2025-02-17 23:43:17 +03:00
142 lines
4.8 KiB
Python
Executable File
142 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
'''Fast and efficient parser for XTB files.
|
|
'''
|
|
|
|
|
|
import sys
|
|
import xml.sax
|
|
import xml.sax.handler
|
|
|
|
import grit.node.base
|
|
|
|
|
|
class XtbContentHandler(xml.sax.handler.ContentHandler):
|
|
'''A content handler that calls a given callback function for each
|
|
translation in the XTB file.
|
|
'''
|
|
|
|
def __init__(self, callback, defs=None, debug=False, target_platform=None):
|
|
self.callback = callback
|
|
self.debug = debug
|
|
# 0 if we are not currently parsing a translation, otherwise the message
|
|
# ID of that translation.
|
|
self.current_id = 0
|
|
# Empty if we are not currently parsing a translation, otherwise the
|
|
# parts we have for that translation - a list of tuples
|
|
# (is_placeholder, text)
|
|
self.current_structure = []
|
|
# Set to the language ID when we see the <translationbundle> node.
|
|
self.language = ''
|
|
# Keep track of the if block we're inside. We can't nest ifs.
|
|
self.if_expr = None
|
|
# Root defines to be used with if expr.
|
|
if defs:
|
|
self.defines = defs
|
|
else:
|
|
self.defines = {}
|
|
# Target platform for build.
|
|
if target_platform:
|
|
self.target_platform = target_platform
|
|
else:
|
|
self.target_platform = sys.platform
|
|
|
|
def startElement(self, name, attrs):
|
|
if name == 'translation':
|
|
assert self.current_id == 0 and len(self.current_structure) == 0, (
|
|
"Didn't expect a <translation> element here.")
|
|
self.current_id = attrs.getValue('id')
|
|
elif name == 'ph':
|
|
assert self.current_id != 0, "Didn't expect a <ph> element here."
|
|
self.current_structure.append((True, attrs.getValue('name')))
|
|
elif name == 'translationbundle':
|
|
self.language = attrs.getValue('lang')
|
|
elif name in ('if', 'then', 'else'):
|
|
assert self.if_expr is None, "Can't nest <if> or use <else> in xtb files"
|
|
self.if_expr = attrs.getValue('expr')
|
|
|
|
def endElement(self, name):
|
|
if name == 'translation':
|
|
assert self.current_id != 0
|
|
|
|
defs = self.defines
|
|
def pp_ifdef(define):
|
|
return define in defs
|
|
def pp_if(define):
|
|
return define in defs and defs[define]
|
|
|
|
# If we're in an if block, only call the callback (add the translation)
|
|
# if the expression is True.
|
|
should_run_callback = True
|
|
if self.if_expr:
|
|
should_run_callback = grit.node.base.Node.EvaluateExpression(
|
|
self.if_expr, self.defines, self.target_platform)
|
|
if should_run_callback:
|
|
self.callback(self.current_id, self.current_structure)
|
|
|
|
self.current_id = 0
|
|
self.current_structure = []
|
|
elif name == 'if':
|
|
assert self.if_expr is not None
|
|
self.if_expr = None
|
|
|
|
def characters(self, content):
|
|
if self.current_id != 0:
|
|
# We are inside a <translation> node so just add the characters to our
|
|
# structure.
|
|
#
|
|
# This naive way of handling characters is OK because in the XTB format,
|
|
# <ph> nodes are always empty (always <ph name="XXX"/>) and whitespace
|
|
# inside the <translation> node should be preserved.
|
|
self.current_structure.append((False, content))
|
|
|
|
|
|
class XtbErrorHandler(xml.sax.handler.ErrorHandler):
|
|
def error(self, exception):
|
|
pass
|
|
|
|
def fatalError(self, exception):
|
|
raise exception
|
|
|
|
def warning(self, exception):
|
|
pass
|
|
|
|
|
|
def Parse(xtb_file, callback_function, defs=None, debug=False,
|
|
target_platform=None):
|
|
'''Parse xtb_file, making a call to callback_function for every translation
|
|
in the XTB file.
|
|
|
|
The callback function must have the signature as described below. The 'parts'
|
|
parameter is a list of tuples (is_placeholder, text). The 'text' part is
|
|
either the raw text (if is_placeholder is False) or the name of the placeholder
|
|
(if is_placeholder is True).
|
|
|
|
Args:
|
|
xtb_file: open('fr.xtb')
|
|
callback_function: def Callback(msg_id, parts): pass
|
|
defs: None, or a dictionary of preprocessor definitions.
|
|
debug: Default False. Set True for verbose debug output.
|
|
target_platform: None, or a sys.platform-like identifier of the build
|
|
target platform.
|
|
|
|
Return:
|
|
The language of the XTB, e.g. 'fr'
|
|
'''
|
|
# Start by advancing the file pointer past the DOCTYPE thing, as the TC
|
|
# uses a path to the DTD that only works in Unix.
|
|
# TODO(joi) Remove this ugly hack by getting the TC gang to change the
|
|
# XTB files somehow?
|
|
front_of_file = xtb_file.read(1024)
|
|
xtb_file.seek(front_of_file.find('<translationbundle'))
|
|
|
|
handler = XtbContentHandler(callback=callback_function, defs=defs,
|
|
debug=debug, target_platform=target_platform)
|
|
xml.sax.parse(xtb_file, handler)
|
|
assert handler.language != ''
|
|
return handler.language
|
|
|