diff options
author | Karl Berry <karl@freefriends.org> | 2019-11-27 22:03:14 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-11-27 22:03:14 +0000 |
commit | 04fdc1ed68f4000de0075c6c04cc6c2a527f1771 (patch) | |
tree | f154f15e51d8db80048fafa2402c7762b9adbae2 | |
parent | 3f7f2975151387f346462c134e2d1a19410dd816 (diff) |
dviasm (27nov19)
git-svn-id: svn://tug.org/texlive/trunk@52941 c570f23f-e606-0410-a88d-b1316a301751
-rwxr-xr-x | Build/source/texk/texlive/linked_scripts/dviasm/dviasm.py | 134 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/dviasm/README | 2 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/dviasm/dviasm.py | 134 |
3 files changed, 155 insertions, 115 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/dviasm/dviasm.py b/Build/source/texk/texlive/linked_scripts/dviasm/dviasm.py index 05ff94fc685..ae903932c13 100755 --- a/Build/source/texk/texlive/linked_scripts/dviasm/dviasm.py +++ b/Build/source/texk/texlive/linked_scripts/dviasm/dviasm.py @@ -1,10 +1,12 @@ -#! /usr/bin/env python2.7 +#! /usr/bin/env python3 # -*- coding: utf-8 -*- # # This is DVIasm, a DVI utility for editing DVI files directly. # # Copyright (C) 2007-2008 by Jin-Hwan Cho <chofchof@ktug.or.kr> # Copyright (C) 2011-2017 by Khaled Hosny <khaledhosny@eglug.org> +# Copyright (C) 2019 by Arthur Reutenauer <arthur@reutenauer.eu> +# Copyright (C) 2019 by Hironobu Yamashita <h.y.acetaminophen@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -78,7 +80,7 @@ def ValidID(dvi_id): return True def BadDVI(msg): - raise AttributeError, 'Bad DVI file: %s!' % msg + raise AttributeError('Bad DVI file: %s!' % msg) def GetByte(fp): # { returns the next byte, unsigned } try: return ord(fp.read(1)) @@ -91,40 +93,40 @@ def SignedByte(fp): # { returns the next byte, signed } else: return b - 256 def Get2Bytes(fp): # { returns the next two bytes, unsigned } - try: a, b = map(ord, fp.read(2)) + try: a, b = fp.read(2) except: BadDVI('Failed to Get2Bytes()') return (a << 8) + b def SignedPair(fp): # {returns the next two bytes, signed } - try: a, b = map(ord, fp.read(2)) + try: a, b = fp.read(2) except: BadDVI('Failed to SignedPair()') if a < 128: return (a << 8) + b else: return ((a - 256) << 8) + b def Get3Bytes(fp): # { returns the next three bytes, unsigned } - try: a, b, c = map(ord, fp.read(3)) + try: a, b, c = fp.read(3) except: BadDVI('Failed to Get3Bytes()') return (((a << 8) + b) << 8) + c def SignedTrio(fp): # { returns the next three bytes, signed } - try: a, b, c = map(ord, fp.read(3)) + try: a, b, c = fp.read(3) except: BadDVI('Failed to SignedTrio()') if a < 128: return (((a << 8) + b) << 8) + c else: return ((((a - 256) << 8) + b) << 8) + c def Get4Bytes(fp): # { returns the next four bytes, unsigned } - try: a, b, c, d = map(ord, fp.read(4)) + try: a, b, c, d = fp.read(4) except: BadDVI('Failed to Get4Bytes()') return (((((a << 8) + b) << 8) + c) << 8) + d def SignedQuad(fp): # { returns the next four bytes, signed } - try: a, b, c, d = map(ord, fp.read(4)) + try: a, b, c, d = fp.read(4) except: BadDVI('Failed to get SignedQuad()') if a < 128: return (((((a << 8) + b) << 8) + c) << 8) + d else: return ((((((a - 256) << 8) + b) << 8) + c) << 8) + d def PutByte(q): - return chr(q & 0xff) + return bytes.fromhex('%02x' % (q & 0xff)) def Put2Bytes(q): return PutByte(q>>8) + PutByte(q) @@ -161,7 +163,7 @@ def PutGlyphs(width, glyphs): for glyph in glyphs: s.append(Put2Bytes(glyph["id"])) - return ''.join(s) + return b''.join(s) def PutTextGlyphs(text, width, glyphs): s = [] @@ -171,7 +173,7 @@ def PutTextGlyphs(text, width, glyphs): s.append(Put2Bytes(ch)) s.append(PutGlyphs(width, glyphs)) - return ''.join(s) + return b''.join(s) def GetInt(s): try: return int(s) @@ -184,11 +186,11 @@ def GetStrASCII(s): # used in Parse() def UCS2toJIS(c): s = c.encode('iso2022-jp') if len(s) == 1: return ord(s) - else: return (ord(s[3]) << 8) + ord(s[4]) + else: return (s[3] << 8) + s[4] def GetStrUTF8(s): # used in Parse() if len(s) > 1 and ((s[0] == "'" and s[-1] == "'") or (s[0] == '"' and s[-1] == '"')): - t = s[1:-1].decode('string_escape').decode('utf8') + t = s[1:-1] if is_ptex: return [UCS2toJIS(c) for c in t] else: return [ord(c) for c in t] else: return '' @@ -215,19 +217,26 @@ def PutStrLatin1(t): # unsed in Dump() warning('Not support characters > 65535; may skip %d.\n' % o) return "'%s'" % s +def DecodeISO2022JP(c): + try: + s = bytes.fromhex("1b 24 42 %02x %02x" % (c//256, c%256)).decode('iso2022-jp') + except UnicodeDecodeError: + s = '' + return s + def PutStrUTF8(t): # unsed in Dump() s = '' if is_subfont: for o in t: - s += unichr((subfont_idx << 8) + o).encode('utf8') + s += chr((subfont_idx << 8) + o).encode('utf8') else: # not the case of subfont for o in t: if o == 92: s += '\\\\' elif 32 <= o < 127: s += chr(o) elif o < 128: s += ('\\x%02x' % o) elif is_ptex: - s += ''.join(['\x1b$B', chr(o/256), chr(o%256)]).decode('iso2022-jp').encode('utf8') - else: s += unichr(o).encode('utf8') + s += DecodeISO2022JP(o) + else: s += chr(o) return "'%s'" % s def PutStrSJIS(t): # unsed in Dump() @@ -237,7 +246,7 @@ def PutStrSJIS(t): # unsed in Dump() elif 32 <= o < 127: s += chr(o) elif o < 128: s += ('\\x%02x' % o) else: - s += ''.join(['\x1b$B', chr(o/256), chr(o%256)]).decode('iso2022-jp').encode('sjis') + s += DecodeISO2022JP(o).encode('sjis') return "'%s'" % s def IsFontChanged(f, z): @@ -287,7 +296,7 @@ class DVI(object): # Load: DVI -> Internal Format ########################################################## def Load(self, fn): - fp = file(fn, 'rb') + fp = open(fn, 'rb') self.LoadFromFile(fp) fp.close() @@ -301,7 +310,7 @@ class DVI(object): while loc >= 0: fp.seek(loc) if GetByte(fp) != BOP: BadDVI('byte %d is not bop' % fp.tell()) - cnt = [SignedQuad(fp) for i in xrange(10)] + cnt = [SignedQuad(fp) for i in range(10)] loc = SignedQuad(fp) page = self.ProcessPage(fp) self.pages.insert(0, {'count':cnt, 'content':page}) @@ -329,7 +338,7 @@ class DVI(object): warning('magnification is %d; use the default 1000!' % mag) else: self.mag = mag - self.comment = fp.read(GetByte(fp)) + self.comment = fp.read(GetByte(fp)).decode('utf8') self.ComputeConversionFactors() def ProcessPostamble(self, fp): @@ -378,19 +387,22 @@ class DVI(object): m = GetByte(fp) if not ValidID(m): warning('identification in byte %d should be one of: %s!' % (fp.tell() - 1, DVI_IDS)) + if not self.id == m: + if not (self.id == 2 and m == 3): # pTeX/upTeX with dir allowed + warning('ID byte mismatch: preamble %d vs postamble %d!' % (self.id, m)) def DefineFont(self, e, fp): c = SignedQuad(fp) # font_check_sum q = SignedQuad(fp) # font_scaled_size d = SignedQuad(fp) # font_design_size - n = fp.read(GetByte(fp) + GetByte(fp)) + n = fp.read(GetByte(fp) + GetByte(fp)).decode('utf8') try: f = self.font_def[e] except KeyError: self.font_def[e] = {'name':n, 'checksum':c, 'scaled_size':q, 'design_size':d} - if q <= 0 or q >= 01000000000: + if q <= 0 or q >= 0o1000000000: warning("%s---not loaded, bad scale (%d)!" % (n, q)) - elif d <= 0 or d >= 01000000000: + elif d <= 0 or d >= 0o1000000000: warning("%s---not loaded, bad design size (%d)!" % (n, d)) else: if f['checksum'] != c: @@ -406,7 +418,7 @@ class DVI(object): size = Get4Bytes(fp) # scaled size flags = Get2Bytes(fp) l = GetByte(fp) # name length - fnt_name = fp.read(l) + fnt_name = fp.read(l).decode('utf8') index = Get4Bytes(fp) # face index ext = [] embolden = 0 @@ -486,7 +498,7 @@ class DVI(object): elif o < FNT_NUM_0 + 64 or o in (FNT1, FNT2, FNT3, FNT4): s.append([FNT1, p]) elif o in (XXX1, XXX2, XXX3, XXX4): - q = fp.read(p) + q = fp.read(p).decode('utf8') s.append([XXX1, q]) elif o in (FNT_DEF1, FNT_DEF2, FNT_DEF3, FNT_DEF4): self.DefineFont(p, fp) @@ -590,41 +602,41 @@ class DVI(object): # Save: Internal Format -> DVI ########################################################## def Save(self, fn): - fp = file(fn, 'wb') + fp = open(fn, 'wb') self.SaveToFile(fp) fp.close() def SaveToFile(self, fp): # WritePreamble - fp.write(''.join([chr(PRE), PutByte(self.id), PutSignedQuad(self.numerator), PutSignedQuad(self.denominator), PutSignedQuad(self.mag), PutByte(len(self.comment)), self.comment])) + fp.write(b''.join([bytes.fromhex('%02x' % PRE), PutByte(self.id), PutSignedQuad(self.numerator), PutSignedQuad(self.denominator), PutSignedQuad(self.mag), PutByte(len(self.comment)), self.comment.encode('utf8')])) # WriteFontDefinitions self.WriteFontDefinitions(fp) # WritePages stackdepth = 0; loc = -1 for page in self.pages: w = x = y = z = 0; stack = [] - s = [chr(BOP)] + s = [bytes.fromhex('%02x' % BOP)] s.extend([PutSignedQuad(c) for c in page['count']]) s.append(PutSignedQuad(loc)) for cmd in page['content']: if cmd[0] == SET1: for o in cmd[1]: - if o < 128: s.append(chr(SET_CHAR_0 + o)) + if o < 128: s.append(bytes.fromhex('%02x' % (SET_CHAR_0 + o))) else: s.append(self.CmdPair([SET1, o])) elif cmd[0] in (SET_RULE, PUT_RULE): - s.append(chr(cmd[0]) + PutSignedQuad(cmd[1][0]) + PutSignedQuad(cmd[1][1])) + s.append(bytes.fromhex('%02x' % cmd[0]) + PutSignedQuad(cmd[1][0]) + PutSignedQuad(cmd[1][1])) elif cmd[0] == PUT1: s.append(self.CmdPair([PUT1, cmd[1][0]])) elif cmd[0] in (RIGHT1, DOWN1): s.append(self.CmdPair(cmd)) elif cmd[0] in (W0, X0, Y0, Z0): - s.append(chr(cmd[0])) + s.append(bytes.fromhex('%02x' % cmd[0])) elif cmd[0] == PUSH: - s.append(chr(PUSH)) + s.append(bytes.fromhex('%02x' % PUSH)) stack.append((w, x, y, z)) if len(stack) > stackdepth: stackdepth = len(stack) elif cmd[0] == POP: - s.append(chr(POP)) + s.append(bytes.fromhex('%02x' % POP)) w, x, y, z = stack.pop() elif cmd[0] == W1: w = cmd[1]; s.append(self.CmdPair(cmd)) @@ -635,18 +647,19 @@ class DVI(object): elif cmd[0] == Z1: z = cmd[1]; s.append(self.CmdPair(cmd)) elif cmd[0] == FNT1: - if cmd[1] < 64: s.append(chr(FNT_NUM_0 + cmd[1])) + if cmd[1] < 64: s.append(bytes.fromhex('%02x' % (FNT_NUM_0 + cmd[1]))) else: s.append(self.CmdPair(cmd)) elif cmd[0] == XXX1: + cmd1 = cmd[1].encode('utf8') l = len(cmd[1]) - if l < 256: s.append(chr(XXX1) + chr(l) + cmd[1]) - else: s.append(chr(XXX4) + PutSignedQuad(l) + cmd[1]) + if l < 256: s.append(bytes.fromhex('%02x' % XXX1) + bytes.fromhex('%02x' % l) + cmd1) + else: s.append(bytes.fromhex('%02x' % XXX4) + PutSignedQuad(l) + cmd1) elif cmd[0] == DIR: - s.append(chr(DIR) + chr(cmd[1])) + s.append(bytes.fromhex('%02x' % DIR) + bytes.fromhex('%02x' % cmd[1])) elif cmd[0] == BEGIN_REFLECT: - s.append(chr(BEGIN_REFLECT)) + s.append(bytes.fromhex('%02x' % BEGIN_REFLECT)) elif cmd[0] == END_REFLECT: - s.append(chr(END_REFLECT)) + s.append(bytes.fromhex('%02x' % END_REFLECT)) elif cmd[0] == GLYPHS: s.append(PutByte(GLYPHS)) s.append(PutGlyphs(cmd[1], cmd[2])) @@ -655,19 +668,19 @@ class DVI(object): s.append(PutTextGlyphs(cmd[1], cmd[2], cmd[3])) else: warning('invalid command %s!' % cmd[0]) - s.append(chr(EOP)) + s.append(bytes.fromhex('%02x' % EOP)) loc = fp.tell() - fp.write(''.join(s)) + fp.write(b''.join(s)) # WritePostamble post_loc = fp.tell() - fp.write(''.join([chr(POST), PutSignedQuad(loc), PutSignedQuad(self.numerator), PutSignedQuad(self.denominator), PutSignedQuad(self.mag), PutSignedQuad(self.max_v), PutSignedQuad(self.max_h), Put2Bytes(stackdepth+1), Put2Bytes(len(self.pages))])) + fp.write(b''.join([bytes.fromhex('%02x' % POST), PutSignedQuad(loc), PutSignedQuad(self.numerator), PutSignedQuad(self.denominator), PutSignedQuad(self.mag), PutSignedQuad(self.max_v), PutSignedQuad(self.max_h), Put2Bytes(stackdepth+1), Put2Bytes(len(self.pages))])) # WriteFontDefinitions self.WriteFontDefinitions(fp) # WritePostPostamble - fp.write(''.join([chr(POST_POST), PutSignedQuad(post_loc), PutByte(self.id), '\xdf\xdf\xdf\xdf'])) + fp.write(b''.join([bytes.fromhex('%02x' % POST_POST), PutSignedQuad(post_loc), PutByte(self.id_post), b'\xdf\xdf\xdf\xdf'])) loc = fp.tell() while (loc % 4) != 0: - fp.write('\xdf'); loc += 1 + fp.write(b'\xdf'); loc += 1 def WriteFontDefinitions(self, fp): s = [] @@ -679,9 +692,8 @@ class DVI(object): s.append(PutSignedQuad(self.font_def[e]['scaled_size'])) s.append(Put2Bytes(flags)) s.append(PutByte(len(self.font_def[e]['name']))) - s.append(self.font_def[e]['name']) + s.append(self.font_def[e]['name'].encode('utf8')) s.append(PutSignedQuad(self.font_def[e]['index'])) - print >> sys.stderr, self.font_def[e]['name'], self.font_def[e]['index'] if flags & XDV_FLAG_COLORED: s.append(PutSignedQuad(self.font_def[e]['color'])) if flags & XDV_FLAG_EXTEND: s.append(PutSignedQuad(self.font_def[e]['extend'])) if flags & XDV_FLAG_SLANT: s.append(PutSignedQuad(self.font_def[e]['slant'])) @@ -693,20 +705,20 @@ class DVI(object): s.append(PutSignedQuad(self.font_def[e]['checksum'])) s.append(PutSignedQuad(self.font_def[e]['scaled_size'])) s.append(PutSignedQuad(self.font_def[e]['design_size'])) - s.append('\x00') + s.append(b'\x00') s.append(PutByte(len(self.font_def[e]['name']))) - s.append(self.font_def[e]['name']) - fp.write(''.join(s)) + s.append(self.font_def[e]['name'].encode('utf8')) + fp.write(b''.join(s)) def CmdPair(self, cmd): l, q = PutSigned(cmd[1]) - return chr(cmd[0] + l) + q + return bytes.fromhex('%02x' % (cmd[0] + l)) + q ########################################################## # Parse: Text -> Internal Format ########################################################## def Parse(self, fn, encoding=''): - fp = file(fn, 'r') + fp = open(fn, 'r') s = fp.read() fp.close() self.ParseFromString(s, encoding=encoding) @@ -717,6 +729,7 @@ class DVI(object): else: GetStr = GetStrUTF8 self.Initialize() self.fnt_num = 0 + dir_used = 0 for l in s.split('\n'): l = l.strip() if not l or l[0] == '%': continue @@ -818,7 +831,7 @@ class DVI(object): else: is_subfont = False try: - e = self.font_def.keys()[self.font_def.values().index(f)] + e = list(self.font_def.keys())[list(self.font_def.values()).index(f)] except: e = self.fnt_num self.font_def[self.fnt_num] = f @@ -850,6 +863,7 @@ class DVI(object): self.cur_page.append([Z0]) elif key == 'dir': self.cur_page.append([DIR, GetInt(val)]) + dir_used = 1 elif key == 'begin_reflect': self.cur_page.append([BEGIN_REFLECT]) elif key == 'end_reflect': @@ -862,11 +876,15 @@ class DVI(object): self.cur_page.append([TEXT_GLYPHS, text, w, glyphs]) else: warning('invalid command %s!' % key) + if self.id == 2 and dir_used == 1: # standard DVI with dir -> force pTeX/upTeX spec + self.id_post = 3 + else: + self.id_post = self.id def AppendFNT1(self): f = {'name':cur_font+"%02x"%subfont_idx, 'design_size':cur_dsize, 'scaled_size':cur_ssize, 'checksum':0} try: - e = self.font_def.keys()[self.font_def.values().index(f)] + e = list(self.font_def.keys())[list(self.font_def.values()).index(f)] except: e = self.fnt_num self.font_def[e] = f @@ -877,7 +895,7 @@ class DVI(object): # Dump: Internal Format -> Text ########################################################## def Dump(self, fn, tabsize=2, encoding=''): - fp = file(fn, 'w') + fp = open(fn, 'w') self.DumpToFile(fp, tabsize=tabsize, encoding=encoding) fp.close() @@ -1130,10 +1148,12 @@ binary format. It is fully documented at http://tug.org/TUGboat/Articles/tb28-2/tb89cho.pdf http://ajt.ktug.kr/assets/2008/5/1/0201cho.pdf""" - version = """This is %prog-20190202 by Jin-Hwan Cho (Korean TeX Society) + version = """This is %prog-20191126 Copyright (C) 2007-2008 by Jin-Hwan Cho <chofchof@ktug.or.kr> Copyright (C) 2011-2017 by Khaled Hosny <khaledhosny@eglug.org> +Copyright (C) 2019 by Arthur Reutenauer <arthur@reutenauer.eu> +Copyright (C) 2019 by Hironobu Yamashita <h.y.acetaminophen@gmail.com> This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1159,7 +1179,7 @@ the Free Software Foundation, either version 3 of the License, or help="tab size for push/pop [default=%default]") parser.add_option("-p", "--ptex", action="store_true", dest="ptex", default=False, - help="extended DVI for Japanese pTeX") + help="ISO-2022-JP-encoded DVI for Japanese pTeX") parser.add_option("-s", "--subfont", action="append", type="string", dest="subfont", metavar="STR", @@ -1191,7 +1211,7 @@ def IsDVI(fname): from os.path import splitext if splitext(fname)[1] not in ('.dvi', '.xdv'): return False try: - fp = file(fname, 'rb') + fp = open(fname, 'rb') fp.seek(0) if GetByte(fp) != PRE: return False fp.seek(-4, 2) diff --git a/Master/texmf-dist/doc/latex/dviasm/README b/Master/texmf-dist/doc/latex/dviasm/README index d2fc73b610c..f81b426b9c1 100644 --- a/Master/texmf-dist/doc/latex/dviasm/README +++ b/Master/texmf-dist/doc/latex/dviasm/README @@ -1,4 +1,4 @@ -DVIasm is a TeX utility program written by Jin-Hwan Cho, that is +DVIasm is a TeX utility program originally written by Jin-Hwan Cho, that is designed for editing DeVice-Independent (DVI) files directly. It consists of a single Python program, dviasm.py, in a human readable diff --git a/Master/texmf-dist/scripts/dviasm/dviasm.py b/Master/texmf-dist/scripts/dviasm/dviasm.py index 05ff94fc685..ae903932c13 100755 --- a/Master/texmf-dist/scripts/dviasm/dviasm.py +++ b/Master/texmf-dist/scripts/dviasm/dviasm.py @@ -1,10 +1,12 @@ -#! /usr/bin/env python2.7 +#! /usr/bin/env python3 # -*- coding: utf-8 -*- # # This is DVIasm, a DVI utility for editing DVI files directly. # # Copyright (C) 2007-2008 by Jin-Hwan Cho <chofchof@ktug.or.kr> # Copyright (C) 2011-2017 by Khaled Hosny <khaledhosny@eglug.org> +# Copyright (C) 2019 by Arthur Reutenauer <arthur@reutenauer.eu> +# Copyright (C) 2019 by Hironobu Yamashita <h.y.acetaminophen@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -78,7 +80,7 @@ def ValidID(dvi_id): return True def BadDVI(msg): - raise AttributeError, 'Bad DVI file: %s!' % msg + raise AttributeError('Bad DVI file: %s!' % msg) def GetByte(fp): # { returns the next byte, unsigned } try: return ord(fp.read(1)) @@ -91,40 +93,40 @@ def SignedByte(fp): # { returns the next byte, signed } else: return b - 256 def Get2Bytes(fp): # { returns the next two bytes, unsigned } - try: a, b = map(ord, fp.read(2)) + try: a, b = fp.read(2) except: BadDVI('Failed to Get2Bytes()') return (a << 8) + b def SignedPair(fp): # {returns the next two bytes, signed } - try: a, b = map(ord, fp.read(2)) + try: a, b = fp.read(2) except: BadDVI('Failed to SignedPair()') if a < 128: return (a << 8) + b else: return ((a - 256) << 8) + b def Get3Bytes(fp): # { returns the next three bytes, unsigned } - try: a, b, c = map(ord, fp.read(3)) + try: a, b, c = fp.read(3) except: BadDVI('Failed to Get3Bytes()') return (((a << 8) + b) << 8) + c def SignedTrio(fp): # { returns the next three bytes, signed } - try: a, b, c = map(ord, fp.read(3)) + try: a, b, c = fp.read(3) except: BadDVI('Failed to SignedTrio()') if a < 128: return (((a << 8) + b) << 8) + c else: return ((((a - 256) << 8) + b) << 8) + c def Get4Bytes(fp): # { returns the next four bytes, unsigned } - try: a, b, c, d = map(ord, fp.read(4)) + try: a, b, c, d = fp.read(4) except: BadDVI('Failed to Get4Bytes()') return (((((a << 8) + b) << 8) + c) << 8) + d def SignedQuad(fp): # { returns the next four bytes, signed } - try: a, b, c, d = map(ord, fp.read(4)) + try: a, b, c, d = fp.read(4) except: BadDVI('Failed to get SignedQuad()') if a < 128: return (((((a << 8) + b) << 8) + c) << 8) + d else: return ((((((a - 256) << 8) + b) << 8) + c) << 8) + d def PutByte(q): - return chr(q & 0xff) + return bytes.fromhex('%02x' % (q & 0xff)) def Put2Bytes(q): return PutByte(q>>8) + PutByte(q) @@ -161,7 +163,7 @@ def PutGlyphs(width, glyphs): for glyph in glyphs: s.append(Put2Bytes(glyph["id"])) - return ''.join(s) + return b''.join(s) def PutTextGlyphs(text, width, glyphs): s = [] @@ -171,7 +173,7 @@ def PutTextGlyphs(text, width, glyphs): s.append(Put2Bytes(ch)) s.append(PutGlyphs(width, glyphs)) - return ''.join(s) + return b''.join(s) def GetInt(s): try: return int(s) @@ -184,11 +186,11 @@ def GetStrASCII(s): # used in Parse() def UCS2toJIS(c): s = c.encode('iso2022-jp') if len(s) == 1: return ord(s) - else: return (ord(s[3]) << 8) + ord(s[4]) + else: return (s[3] << 8) + s[4] def GetStrUTF8(s): # used in Parse() if len(s) > 1 and ((s[0] == "'" and s[-1] == "'") or (s[0] == '"' and s[-1] == '"')): - t = s[1:-1].decode('string_escape').decode('utf8') + t = s[1:-1] if is_ptex: return [UCS2toJIS(c) for c in t] else: return [ord(c) for c in t] else: return '' @@ -215,19 +217,26 @@ def PutStrLatin1(t): # unsed in Dump() warning('Not support characters > 65535; may skip %d.\n' % o) return "'%s'" % s +def DecodeISO2022JP(c): + try: + s = bytes.fromhex("1b 24 42 %02x %02x" % (c//256, c%256)).decode('iso2022-jp') + except UnicodeDecodeError: + s = '' + return s + def PutStrUTF8(t): # unsed in Dump() s = '' if is_subfont: for o in t: - s += unichr((subfont_idx << 8) + o).encode('utf8') + s += chr((subfont_idx << 8) + o).encode('utf8') else: # not the case of subfont for o in t: if o == 92: s += '\\\\' elif 32 <= o < 127: s += chr(o) elif o < 128: s += ('\\x%02x' % o) elif is_ptex: - s += ''.join(['\x1b$B', chr(o/256), chr(o%256)]).decode('iso2022-jp').encode('utf8') - else: s += unichr(o).encode('utf8') + s += DecodeISO2022JP(o) + else: s += chr(o) return "'%s'" % s def PutStrSJIS(t): # unsed in Dump() @@ -237,7 +246,7 @@ def PutStrSJIS(t): # unsed in Dump() elif 32 <= o < 127: s += chr(o) elif o < 128: s += ('\\x%02x' % o) else: - s += ''.join(['\x1b$B', chr(o/256), chr(o%256)]).decode('iso2022-jp').encode('sjis') + s += DecodeISO2022JP(o).encode('sjis') return "'%s'" % s def IsFontChanged(f, z): @@ -287,7 +296,7 @@ class DVI(object): # Load: DVI -> Internal Format ########################################################## def Load(self, fn): - fp = file(fn, 'rb') + fp = open(fn, 'rb') self.LoadFromFile(fp) fp.close() @@ -301,7 +310,7 @@ class DVI(object): while loc >= 0: fp.seek(loc) if GetByte(fp) != BOP: BadDVI('byte %d is not bop' % fp.tell()) - cnt = [SignedQuad(fp) for i in xrange(10)] + cnt = [SignedQuad(fp) for i in range(10)] loc = SignedQuad(fp) page = self.ProcessPage(fp) self.pages.insert(0, {'count':cnt, 'content':page}) @@ -329,7 +338,7 @@ class DVI(object): warning('magnification is %d; use the default 1000!' % mag) else: self.mag = mag - self.comment = fp.read(GetByte(fp)) + self.comment = fp.read(GetByte(fp)).decode('utf8') self.ComputeConversionFactors() def ProcessPostamble(self, fp): @@ -378,19 +387,22 @@ class DVI(object): m = GetByte(fp) if not ValidID(m): warning('identification in byte %d should be one of: %s!' % (fp.tell() - 1, DVI_IDS)) + if not self.id == m: + if not (self.id == 2 and m == 3): # pTeX/upTeX with dir allowed + warning('ID byte mismatch: preamble %d vs postamble %d!' % (self.id, m)) def DefineFont(self, e, fp): c = SignedQuad(fp) # font_check_sum q = SignedQuad(fp) # font_scaled_size d = SignedQuad(fp) # font_design_size - n = fp.read(GetByte(fp) + GetByte(fp)) + n = fp.read(GetByte(fp) + GetByte(fp)).decode('utf8') try: f = self.font_def[e] except KeyError: self.font_def[e] = {'name':n, 'checksum':c, 'scaled_size':q, 'design_size':d} - if q <= 0 or q >= 01000000000: + if q <= 0 or q >= 0o1000000000: warning("%s---not loaded, bad scale (%d)!" % (n, q)) - elif d <= 0 or d >= 01000000000: + elif d <= 0 or d >= 0o1000000000: warning("%s---not loaded, bad design size (%d)!" % (n, d)) else: if f['checksum'] != c: @@ -406,7 +418,7 @@ class DVI(object): size = Get4Bytes(fp) # scaled size flags = Get2Bytes(fp) l = GetByte(fp) # name length - fnt_name = fp.read(l) + fnt_name = fp.read(l).decode('utf8') index = Get4Bytes(fp) # face index ext = [] embolden = 0 @@ -486,7 +498,7 @@ class DVI(object): elif o < FNT_NUM_0 + 64 or o in (FNT1, FNT2, FNT3, FNT4): s.append([FNT1, p]) elif o in (XXX1, XXX2, XXX3, XXX4): - q = fp.read(p) + q = fp.read(p).decode('utf8') s.append([XXX1, q]) elif o in (FNT_DEF1, FNT_DEF2, FNT_DEF3, FNT_DEF4): self.DefineFont(p, fp) @@ -590,41 +602,41 @@ class DVI(object): # Save: Internal Format -> DVI ########################################################## def Save(self, fn): - fp = file(fn, 'wb') + fp = open(fn, 'wb') self.SaveToFile(fp) fp.close() def SaveToFile(self, fp): # WritePreamble - fp.write(''.join([chr(PRE), PutByte(self.id), PutSignedQuad(self.numerator), PutSignedQuad(self.denominator), PutSignedQuad(self.mag), PutByte(len(self.comment)), self.comment])) + fp.write(b''.join([bytes.fromhex('%02x' % PRE), PutByte(self.id), PutSignedQuad(self.numerator), PutSignedQuad(self.denominator), PutSignedQuad(self.mag), PutByte(len(self.comment)), self.comment.encode('utf8')])) # WriteFontDefinitions self.WriteFontDefinitions(fp) # WritePages stackdepth = 0; loc = -1 for page in self.pages: w = x = y = z = 0; stack = [] - s = [chr(BOP)] + s = [bytes.fromhex('%02x' % BOP)] s.extend([PutSignedQuad(c) for c in page['count']]) s.append(PutSignedQuad(loc)) for cmd in page['content']: if cmd[0] == SET1: for o in cmd[1]: - if o < 128: s.append(chr(SET_CHAR_0 + o)) + if o < 128: s.append(bytes.fromhex('%02x' % (SET_CHAR_0 + o))) else: s.append(self.CmdPair([SET1, o])) elif cmd[0] in (SET_RULE, PUT_RULE): - s.append(chr(cmd[0]) + PutSignedQuad(cmd[1][0]) + PutSignedQuad(cmd[1][1])) + s.append(bytes.fromhex('%02x' % cmd[0]) + PutSignedQuad(cmd[1][0]) + PutSignedQuad(cmd[1][1])) elif cmd[0] == PUT1: s.append(self.CmdPair([PUT1, cmd[1][0]])) elif cmd[0] in (RIGHT1, DOWN1): s.append(self.CmdPair(cmd)) elif cmd[0] in (W0, X0, Y0, Z0): - s.append(chr(cmd[0])) + s.append(bytes.fromhex('%02x' % cmd[0])) elif cmd[0] == PUSH: - s.append(chr(PUSH)) + s.append(bytes.fromhex('%02x' % PUSH)) stack.append((w, x, y, z)) if len(stack) > stackdepth: stackdepth = len(stack) elif cmd[0] == POP: - s.append(chr(POP)) + s.append(bytes.fromhex('%02x' % POP)) w, x, y, z = stack.pop() elif cmd[0] == W1: w = cmd[1]; s.append(self.CmdPair(cmd)) @@ -635,18 +647,19 @@ class DVI(object): elif cmd[0] == Z1: z = cmd[1]; s.append(self.CmdPair(cmd)) elif cmd[0] == FNT1: - if cmd[1] < 64: s.append(chr(FNT_NUM_0 + cmd[1])) + if cmd[1] < 64: s.append(bytes.fromhex('%02x' % (FNT_NUM_0 + cmd[1]))) else: s.append(self.CmdPair(cmd)) elif cmd[0] == XXX1: + cmd1 = cmd[1].encode('utf8') l = len(cmd[1]) - if l < 256: s.append(chr(XXX1) + chr(l) + cmd[1]) - else: s.append(chr(XXX4) + PutSignedQuad(l) + cmd[1]) + if l < 256: s.append(bytes.fromhex('%02x' % XXX1) + bytes.fromhex('%02x' % l) + cmd1) + else: s.append(bytes.fromhex('%02x' % XXX4) + PutSignedQuad(l) + cmd1) elif cmd[0] == DIR: - s.append(chr(DIR) + chr(cmd[1])) + s.append(bytes.fromhex('%02x' % DIR) + bytes.fromhex('%02x' % cmd[1])) elif cmd[0] == BEGIN_REFLECT: - s.append(chr(BEGIN_REFLECT)) + s.append(bytes.fromhex('%02x' % BEGIN_REFLECT)) elif cmd[0] == END_REFLECT: - s.append(chr(END_REFLECT)) + s.append(bytes.fromhex('%02x' % END_REFLECT)) elif cmd[0] == GLYPHS: s.append(PutByte(GLYPHS)) s.append(PutGlyphs(cmd[1], cmd[2])) @@ -655,19 +668,19 @@ class DVI(object): s.append(PutTextGlyphs(cmd[1], cmd[2], cmd[3])) else: warning('invalid command %s!' % cmd[0]) - s.append(chr(EOP)) + s.append(bytes.fromhex('%02x' % EOP)) loc = fp.tell() - fp.write(''.join(s)) + fp.write(b''.join(s)) # WritePostamble post_loc = fp.tell() - fp.write(''.join([chr(POST), PutSignedQuad(loc), PutSignedQuad(self.numerator), PutSignedQuad(self.denominator), PutSignedQuad(self.mag), PutSignedQuad(self.max_v), PutSignedQuad(self.max_h), Put2Bytes(stackdepth+1), Put2Bytes(len(self.pages))])) + fp.write(b''.join([bytes.fromhex('%02x' % POST), PutSignedQuad(loc), PutSignedQuad(self.numerator), PutSignedQuad(self.denominator), PutSignedQuad(self.mag), PutSignedQuad(self.max_v), PutSignedQuad(self.max_h), Put2Bytes(stackdepth+1), Put2Bytes(len(self.pages))])) # WriteFontDefinitions self.WriteFontDefinitions(fp) # WritePostPostamble - fp.write(''.join([chr(POST_POST), PutSignedQuad(post_loc), PutByte(self.id), '\xdf\xdf\xdf\xdf'])) + fp.write(b''.join([bytes.fromhex('%02x' % POST_POST), PutSignedQuad(post_loc), PutByte(self.id_post), b'\xdf\xdf\xdf\xdf'])) loc = fp.tell() while (loc % 4) != 0: - fp.write('\xdf'); loc += 1 + fp.write(b'\xdf'); loc += 1 def WriteFontDefinitions(self, fp): s = [] @@ -679,9 +692,8 @@ class DVI(object): s.append(PutSignedQuad(self.font_def[e]['scaled_size'])) s.append(Put2Bytes(flags)) s.append(PutByte(len(self.font_def[e]['name']))) - s.append(self.font_def[e]['name']) + s.append(self.font_def[e]['name'].encode('utf8')) s.append(PutSignedQuad(self.font_def[e]['index'])) - print >> sys.stderr, self.font_def[e]['name'], self.font_def[e]['index'] if flags & XDV_FLAG_COLORED: s.append(PutSignedQuad(self.font_def[e]['color'])) if flags & XDV_FLAG_EXTEND: s.append(PutSignedQuad(self.font_def[e]['extend'])) if flags & XDV_FLAG_SLANT: s.append(PutSignedQuad(self.font_def[e]['slant'])) @@ -693,20 +705,20 @@ class DVI(object): s.append(PutSignedQuad(self.font_def[e]['checksum'])) s.append(PutSignedQuad(self.font_def[e]['scaled_size'])) s.append(PutSignedQuad(self.font_def[e]['design_size'])) - s.append('\x00') + s.append(b'\x00') s.append(PutByte(len(self.font_def[e]['name']))) - s.append(self.font_def[e]['name']) - fp.write(''.join(s)) + s.append(self.font_def[e]['name'].encode('utf8')) + fp.write(b''.join(s)) def CmdPair(self, cmd): l, q = PutSigned(cmd[1]) - return chr(cmd[0] + l) + q + return bytes.fromhex('%02x' % (cmd[0] + l)) + q ########################################################## # Parse: Text -> Internal Format ########################################################## def Parse(self, fn, encoding=''): - fp = file(fn, 'r') + fp = open(fn, 'r') s = fp.read() fp.close() self.ParseFromString(s, encoding=encoding) @@ -717,6 +729,7 @@ class DVI(object): else: GetStr = GetStrUTF8 self.Initialize() self.fnt_num = 0 + dir_used = 0 for l in s.split('\n'): l = l.strip() if not l or l[0] == '%': continue @@ -818,7 +831,7 @@ class DVI(object): else: is_subfont = False try: - e = self.font_def.keys()[self.font_def.values().index(f)] + e = list(self.font_def.keys())[list(self.font_def.values()).index(f)] except: e = self.fnt_num self.font_def[self.fnt_num] = f @@ -850,6 +863,7 @@ class DVI(object): self.cur_page.append([Z0]) elif key == 'dir': self.cur_page.append([DIR, GetInt(val)]) + dir_used = 1 elif key == 'begin_reflect': self.cur_page.append([BEGIN_REFLECT]) elif key == 'end_reflect': @@ -862,11 +876,15 @@ class DVI(object): self.cur_page.append([TEXT_GLYPHS, text, w, glyphs]) else: warning('invalid command %s!' % key) + if self.id == 2 and dir_used == 1: # standard DVI with dir -> force pTeX/upTeX spec + self.id_post = 3 + else: + self.id_post = self.id def AppendFNT1(self): f = {'name':cur_font+"%02x"%subfont_idx, 'design_size':cur_dsize, 'scaled_size':cur_ssize, 'checksum':0} try: - e = self.font_def.keys()[self.font_def.values().index(f)] + e = list(self.font_def.keys())[list(self.font_def.values()).index(f)] except: e = self.fnt_num self.font_def[e] = f @@ -877,7 +895,7 @@ class DVI(object): # Dump: Internal Format -> Text ########################################################## def Dump(self, fn, tabsize=2, encoding=''): - fp = file(fn, 'w') + fp = open(fn, 'w') self.DumpToFile(fp, tabsize=tabsize, encoding=encoding) fp.close() @@ -1130,10 +1148,12 @@ binary format. It is fully documented at http://tug.org/TUGboat/Articles/tb28-2/tb89cho.pdf http://ajt.ktug.kr/assets/2008/5/1/0201cho.pdf""" - version = """This is %prog-20190202 by Jin-Hwan Cho (Korean TeX Society) + version = """This is %prog-20191126 Copyright (C) 2007-2008 by Jin-Hwan Cho <chofchof@ktug.or.kr> Copyright (C) 2011-2017 by Khaled Hosny <khaledhosny@eglug.org> +Copyright (C) 2019 by Arthur Reutenauer <arthur@reutenauer.eu> +Copyright (C) 2019 by Hironobu Yamashita <h.y.acetaminophen@gmail.com> This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1159,7 +1179,7 @@ the Free Software Foundation, either version 3 of the License, or help="tab size for push/pop [default=%default]") parser.add_option("-p", "--ptex", action="store_true", dest="ptex", default=False, - help="extended DVI for Japanese pTeX") + help="ISO-2022-JP-encoded DVI for Japanese pTeX") parser.add_option("-s", "--subfont", action="append", type="string", dest="subfont", metavar="STR", @@ -1191,7 +1211,7 @@ def IsDVI(fname): from os.path import splitext if splitext(fname)[1] not in ('.dvi', '.xdv'): return False try: - fp = file(fname, 'rb') + fp = open(fname, 'rb') fp.seek(0) if GetByte(fp) != PRE: return False fp.seek(-4, 2) |