|
|
package eqn
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
"container/list"
|
|
|
"encoding/binary"
|
|
|
"fmt"
|
|
|
"github.com/extrame/ole2"
|
|
|
"io"
|
|
|
"log"
|
|
|
)
|
|
|
|
|
|
const oleCbHdr = uint16(28)
|
|
|
|
|
|
// [MTEFv5](https://docs.wiris.com/en/mathtype/mathtype_desktop/mathtype-sdk/mtef5)
|
|
|
type MTEFv5 struct {
|
|
|
mMtefVer uint8
|
|
|
mPlatform uint8
|
|
|
mProduct uint8
|
|
|
mVersion uint8
|
|
|
mVersionSub uint8
|
|
|
mApplication string
|
|
|
mInline uint8
|
|
|
|
|
|
reader io.ReadSeeker
|
|
|
|
|
|
ast *MtAST
|
|
|
nodes []*MtAST
|
|
|
|
|
|
//是否合法,顺利解析
|
|
|
Valid bool
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readRecord() (err error) {
|
|
|
/**
|
|
|
读取body的每一行数据并保存到数组里
|
|
|
*/
|
|
|
//默认设置为合法的,除非遇到不可解析数据
|
|
|
m.Valid = true
|
|
|
|
|
|
//Header
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &m.mMtefVer)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &m.mPlatform)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &m.mProduct)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &m.mVersion)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &m.mVersionSub)
|
|
|
m.mApplication, _ = m.readNullTerminatedString()
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &m.mInline)
|
|
|
|
|
|
//fmt.Println(m.mMtefVer, m.mPlatform, m.mProduct, m.mVersion, m.mVersionSub)
|
|
|
//fmt.Println(m.mInline)
|
|
|
//fmt.Println(m.reader)
|
|
|
|
|
|
//Body
|
|
|
for {
|
|
|
record := RecordType(0)
|
|
|
err = binary.Read(m.reader, binary.LittleEndian, &record)
|
|
|
|
|
|
// 根据future定义,>=100的后面会跟一个字节,这个字节代表需要跳过的长度
|
|
|
//For now, readers can assume that an unsigned integer follows the record type and is the number of bytes following it in the record
|
|
|
//This makes it easy for software that reads MTEF to skip these records.
|
|
|
if record >= FUTURE {
|
|
|
var skipFutureLength uint8
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &skipFutureLength)
|
|
|
|
|
|
_, _ = m.reader.Seek(int64(skipFutureLength), io.SeekCurrent)
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
//debug 使用
|
|
|
//fmt.Println(record)
|
|
|
|
|
|
if err != nil {
|
|
|
break
|
|
|
}
|
|
|
switch record {
|
|
|
case END:
|
|
|
m.nodes = append(m.nodes, &MtAST{END, nil, nil})
|
|
|
case LINE:
|
|
|
line := new(MtLine)
|
|
|
_ = m.readLine(line)
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{LINE, line, nil})
|
|
|
case CHAR:
|
|
|
char := new(MtChar)
|
|
|
_ = m.readChar(char)
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{CHAR, char, nil})
|
|
|
case TMPL:
|
|
|
tmpl := new(MtTmpl)
|
|
|
_ = m.readTMPL(tmpl)
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{TMPL, tmpl, nil})
|
|
|
case PILE:
|
|
|
pile := new(MtPile)
|
|
|
_ = m.readPile(pile)
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{PILE, pile, nil})
|
|
|
case MATRIX:
|
|
|
matrix := new(MtMatrix)
|
|
|
_ = m.readMatrix(matrix)
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{MATRIX, matrix, nil})
|
|
|
|
|
|
//匹配矩阵数据下面的2个nil
|
|
|
m.nodes = append(m.nodes, &MtAST{LINE, new(MtLine), nil})
|
|
|
m.nodes = append(m.nodes, &MtAST{LINE, new(MtLine), nil})
|
|
|
case EMBELL:
|
|
|
embell := new(MtEmbellRd)
|
|
|
_ = m.readEmbell(embell)
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{tag: EMBELL, value: embell, children: nil})
|
|
|
case FONT_STYLE_DEF:
|
|
|
fsDef := new(MtfontStyleDef)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &fsDef.fontDefIndex)
|
|
|
fsDef.name, _ = m.readNullTerminatedString()
|
|
|
|
|
|
//读取字节,但是不关心数据,注释
|
|
|
//m.nodes = append(m.nodes, &MtAST{FONT_STYLE_DEF, fsDef, nil})
|
|
|
case SIZE:
|
|
|
mtSize := new(MtSize)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &mtSize.lsize)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &mtSize.dsize)
|
|
|
case SUB:
|
|
|
m.nodes = append(m.nodes, &MtAST{SUB, nil, nil})
|
|
|
case SUB2:
|
|
|
m.nodes = append(m.nodes, &MtAST{SUB2, nil, nil})
|
|
|
case SYM:
|
|
|
m.nodes = append(m.nodes, &MtAST{SYM, nil, nil})
|
|
|
case SUBSYM:
|
|
|
m.nodes = append(m.nodes, &MtAST{SUBSYM, nil, nil})
|
|
|
case FONT_DEF:
|
|
|
fdef := new(MtfontDef)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &fdef.encDefIndex)
|
|
|
fdef.name, _ = m.readNullTerminatedString()
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{FONT_DEF, fdef, nil})
|
|
|
case COLOR:
|
|
|
cIndex := new(MtColorDefIndex)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &cIndex.index)
|
|
|
|
|
|
//读取字节,但是不关心数据,注释
|
|
|
//m.nodes = append(m.nodes, &MtAST{tag: COLOR, value: cIndex, children: nil})
|
|
|
case COLOR_DEF:
|
|
|
cDef := new(MtColorDef)
|
|
|
_ = m.readColorDef(cDef)
|
|
|
|
|
|
//读取字节,但是不关心数据,注释
|
|
|
//m.nodes = append(m.nodes, &MtAST{tag: COLOR_DEF, value: cDef, children: nil})
|
|
|
case FULL:
|
|
|
m.nodes = append(m.nodes, &MtAST{FULL, nil, nil})
|
|
|
case EQN_PREFS:
|
|
|
prefs := new(MtEqnPrefs)
|
|
|
_ = m.readEqnPrefs(prefs)
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{EQN_PREFS, prefs, nil})
|
|
|
case ENCODING_DEF:
|
|
|
enc, _ := m.readNullTerminatedString()
|
|
|
|
|
|
m.nodes = append(m.nodes, &MtAST{ENCODING_DEF, enc, nil})
|
|
|
default:
|
|
|
m.Valid = false
|
|
|
log.Println("FUTURE RECORD", record)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readNullTerminatedString() (s string, err error) {
|
|
|
buf, p := bytes.Buffer{}, []byte{0}
|
|
|
for {
|
|
|
_, err = m.reader.Read(p)
|
|
|
if p[0] == 0 {
|
|
|
break
|
|
|
}
|
|
|
buf.WriteByte(p[0])
|
|
|
}
|
|
|
return buf.String(), err
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readLine(line *MtLine) (err error) {
|
|
|
options := OptionType(0)
|
|
|
err = binary.Read(m.reader, binary.LittleEndian, &options)
|
|
|
|
|
|
if MtefOptNudge == MtefOptNudge&options {
|
|
|
line.nudgeX, line.nudgeY, _ = m.readNudge()
|
|
|
}
|
|
|
if MtefOptLineLspace == MtefOptLineLspace&options {
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &line.lineSpace)
|
|
|
}
|
|
|
|
|
|
//RULER解析
|
|
|
if mtefOPT_LP_RULER == mtefOPT_LP_RULER&options {
|
|
|
var nStops uint8
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &nStops)
|
|
|
|
|
|
var tabList []uint8
|
|
|
for i := uint8(0); i < nStops; i++ {
|
|
|
var stopVal uint8
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &stopVal)
|
|
|
tabList = append(tabList, stopVal)
|
|
|
|
|
|
var tabOffset uint16
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &tabOffset)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if MtefOptLineNull == MtefOptLineNull&options {
|
|
|
line.null = true
|
|
|
}
|
|
|
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readDimensionArrays(size int64) (array []string, err error) {
|
|
|
var flag = true
|
|
|
var tmpStr = new(bytes.Buffer)
|
|
|
var count = int64(0)
|
|
|
|
|
|
var fx = func(x uint8) {
|
|
|
if flag {
|
|
|
switch x {
|
|
|
case 0x00:
|
|
|
flag = false
|
|
|
tmpStr.WriteString("in")
|
|
|
case 0x01:
|
|
|
flag = false
|
|
|
tmpStr.WriteString("cm")
|
|
|
case 0x02:
|
|
|
flag = false
|
|
|
tmpStr.WriteString("pt")
|
|
|
case 0x03:
|
|
|
flag = false
|
|
|
tmpStr.WriteString("pc")
|
|
|
case 0x04:
|
|
|
flag = false
|
|
|
tmpStr.WriteString("%")
|
|
|
default:
|
|
|
fmt.Println("invalid bytes")
|
|
|
}
|
|
|
} else {
|
|
|
switch x {
|
|
|
case 0x00:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('0')
|
|
|
case 0x01:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('1')
|
|
|
case 0x02:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('2')
|
|
|
case 0x03:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('3')
|
|
|
case 0x04:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('4')
|
|
|
case 0x05:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('5')
|
|
|
case 0x06:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('6')
|
|
|
case 0x07:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('7')
|
|
|
case 0x08:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('8')
|
|
|
case 0x09:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('9')
|
|
|
case 0x0a:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('.')
|
|
|
case 0x0b:
|
|
|
flag = false
|
|
|
tmpStr.WriteByte('-')
|
|
|
case 0x0f:
|
|
|
flag = true
|
|
|
count += 1
|
|
|
array = append(array, tmpStr.String())
|
|
|
tmpStr.Reset()
|
|
|
default:
|
|
|
fmt.Println("invalid bytes")
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
for {
|
|
|
if count >= size {
|
|
|
//fmt.Println("break with size=", size)
|
|
|
break
|
|
|
}
|
|
|
ch := uint8(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &ch)
|
|
|
|
|
|
//fmt.Println("ch=", ch)
|
|
|
|
|
|
hi := (ch & 0xf0) / 16
|
|
|
lo := ch & 0x0f
|
|
|
fx(hi)
|
|
|
fx(lo)
|
|
|
}
|
|
|
return array, nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readEqnPrefs(eqnPrefs *MtEqnPrefs) (err error) {
|
|
|
options := uint8(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &options)
|
|
|
|
|
|
//sizes
|
|
|
size := uint8(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &size)
|
|
|
eqnPrefs.sizes, _ = m.readDimensionArrays(int64(size))
|
|
|
|
|
|
//spaces
|
|
|
size = 0
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &size)
|
|
|
eqnPrefs.spaces, _ = m.readDimensionArrays(int64(size))
|
|
|
|
|
|
//styles
|
|
|
size = 0
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &size)
|
|
|
styles := make([]byte, size)
|
|
|
for i := uint8(0); i < size; i++ {
|
|
|
c := uint8(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &c)
|
|
|
if c == 0 {
|
|
|
styles = append(styles, 0)
|
|
|
} else {
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &c)
|
|
|
styles = append(styles, c)
|
|
|
}
|
|
|
}
|
|
|
eqnPrefs.styles = styles
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readChar(char *MtChar) (err error) {
|
|
|
options := OptionType(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &options)
|
|
|
|
|
|
if MtefOptNudge == MtefOptNudge&options {
|
|
|
char.nudgeX, char.nudgeY, _ = m.readNudge()
|
|
|
}
|
|
|
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &char.typeface)
|
|
|
|
|
|
if MtefOptCharEncNoMtcode != MtefOptCharEncNoMtcode&options {
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &char.mtcode)
|
|
|
}
|
|
|
if MtefOptCharEncChar8 == MtefOptCharEncChar8&options {
|
|
|
//todo 强行设置值,有BUG。。。。。
|
|
|
//if char.mtcode >= 34528 {
|
|
|
// _ = binary.Read(m.reader, binary.LittleEndian, &char.bits16)
|
|
|
//}else {
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &char.bits8)
|
|
|
//}
|
|
|
}
|
|
|
if MtefOptCharEncChar16 == MtefOptCharEncChar16&options {
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &char.bits16)
|
|
|
}
|
|
|
|
|
|
//fmt.Println(char)
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readNudge() (nudgeX int16, nudgeY int16, err error) {
|
|
|
b1 := 0
|
|
|
b2 := 0
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &b1)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &b2)
|
|
|
|
|
|
if b1 == 128 || b2 == 128 {
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &nudgeX)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &nudgeY)
|
|
|
return nudgeX, nudgeY, err
|
|
|
} else {
|
|
|
nudgeX = int16(b1)
|
|
|
nudgeY = int16(b2)
|
|
|
return nudgeX, nudgeY, err
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readTMPL(tmpl *MtTmpl) (err error) {
|
|
|
options := OptionType(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &options)
|
|
|
|
|
|
if MtefOptNudge == MtefOptNudge&options {
|
|
|
tmpl.nudgeX, tmpl.nudgeY, _ = m.readNudge()
|
|
|
}
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &tmpl.selector)
|
|
|
|
|
|
// variation, 1 or 2 bytes
|
|
|
byte1 := uint8(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &byte1)
|
|
|
if 0x80 == byte1&0x80 {
|
|
|
byte2 := uint8(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &byte2)
|
|
|
tmpl.variation = (uint16(byte1) & 0x7F) | (uint16(byte2) << 8)
|
|
|
} else {
|
|
|
tmpl.variation = uint16(byte1)
|
|
|
}
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &tmpl.options)
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readPile(pile *MtPile) (err error) {
|
|
|
options := OptionType(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &options)
|
|
|
|
|
|
if MtefOptNudge == MtefOptNudge&options {
|
|
|
pile.nudgeX, pile.nudgeY, _ = m.readNudge()
|
|
|
}
|
|
|
|
|
|
//读取halign和valign
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &pile.halign)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &pile.valign)
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readMatrix(matrix *MtMatrix) (err error) {
|
|
|
options := OptionType(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &options)
|
|
|
|
|
|
if MtefOptNudge == MtefOptNudge&options {
|
|
|
matrix.nudgeX, matrix.nudgeY, _ = m.readNudge()
|
|
|
}
|
|
|
|
|
|
//读取valign和h_just、v_just
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &matrix.valign)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &matrix.h_just)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &matrix.v_just)
|
|
|
|
|
|
//读取rows和cols
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &matrix.rows)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &matrix.cols)
|
|
|
|
|
|
//fmt.Printf("%v", matrix)
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readEmbell(embell *MtEmbellRd) (err error) {
|
|
|
options := OptionType(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &options)
|
|
|
|
|
|
if MtefOptNudge == MtefOptNudge&options {
|
|
|
embell.nudgeX, embell.nudgeY, _ = m.readNudge()
|
|
|
}
|
|
|
|
|
|
//读取embellishment type
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &embell.embellType)
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) readColorDef(colorDef *MtColorDef) (err error) {
|
|
|
options := OptionType(0)
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &options)
|
|
|
|
|
|
var color uint16
|
|
|
if mtefCOLOR_CMYK == mtefCOLOR_CMYK&options {
|
|
|
//CMYK,读4个值
|
|
|
for i := 0; i < 4; i++ {
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &color)
|
|
|
colorDef.values = append(colorDef.values, uint8(color))
|
|
|
}
|
|
|
} else {
|
|
|
// RGB,读3个值
|
|
|
for i := 0; i < 3; i++ {
|
|
|
_ = binary.Read(m.reader, binary.LittleEndian, &color)
|
|
|
colorDef.values = append(colorDef.values, uint8(color))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if mtefCOLOR_NAME == mtefCOLOR_NAME&options {
|
|
|
colorDef.name, _ = m.readNullTerminatedString()
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) Translate() string {
|
|
|
latexStr, err := m.makeLatex(m.ast)
|
|
|
if err != nil {
|
|
|
fmt.Println(err)
|
|
|
}
|
|
|
|
|
|
if m.Valid {
|
|
|
return latexStr
|
|
|
} else {
|
|
|
return ""
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) makeAST() (err error) {
|
|
|
/**
|
|
|
根据数组生成出栈入栈结构
|
|
|
*/
|
|
|
ast := new(MtAST)
|
|
|
ast.tag = 0xff
|
|
|
ast.value = nil
|
|
|
m.ast = ast
|
|
|
|
|
|
stack := list.New()
|
|
|
stack.PushBack(ast)
|
|
|
|
|
|
for _, node := range m.nodes {
|
|
|
//debug 可用
|
|
|
//fmt.Printf("%+v %+v \n", node.tag, node.value)
|
|
|
|
|
|
switch node.tag {
|
|
|
case LINE:
|
|
|
if stack.Len() > 0 {
|
|
|
ele := stack.Back()
|
|
|
|
|
|
//将对象强制转为MtAST类型
|
|
|
parent := ele.Value.(*MtAST)
|
|
|
|
|
|
parent.children = append(parent.children, node)
|
|
|
}
|
|
|
if !node.value.(*MtLine).null {
|
|
|
//如果与0 <nil> 匹配,则需要入栈
|
|
|
stack.PushBack(node)
|
|
|
}
|
|
|
case TMPL:
|
|
|
if stack.Len() > 0 {
|
|
|
ele := stack.Back()
|
|
|
|
|
|
//将对象强制转为MtAST类型
|
|
|
parent := ele.Value.(*MtAST)
|
|
|
|
|
|
parent.children = append(parent.children, node)
|
|
|
}
|
|
|
|
|
|
//如果与0 <nil> 匹配,则需要入栈
|
|
|
stack.PushBack(node)
|
|
|
case PILE:
|
|
|
if stack.Len() > 0 {
|
|
|
ele := stack.Back()
|
|
|
|
|
|
//将对象强制转为MtAST类型
|
|
|
parent := ele.Value.(*MtAST)
|
|
|
|
|
|
parent.children = append(parent.children, node)
|
|
|
}
|
|
|
|
|
|
//如果与0 <nil> 匹配,则需要入栈
|
|
|
stack.PushBack(node)
|
|
|
case MATRIX:
|
|
|
if stack.Len() > 0 {
|
|
|
ele := stack.Back()
|
|
|
|
|
|
//将对象强制转为MtAST类型
|
|
|
parent := ele.Value.(*MtAST)
|
|
|
|
|
|
parent.children = append(parent.children, node)
|
|
|
}
|
|
|
|
|
|
//如果与0 <nil> 匹配,则需要入栈
|
|
|
stack.PushBack(node)
|
|
|
case END:
|
|
|
if stack.Len() > 0 {
|
|
|
ele := stack.Back()
|
|
|
stack.Remove(ele)
|
|
|
}
|
|
|
case CHAR:
|
|
|
if stack.Len() > 0 {
|
|
|
ele := stack.Back()
|
|
|
|
|
|
//将对象强制转为MtAST类型
|
|
|
parent := ele.Value.(*MtAST)
|
|
|
|
|
|
parent.children = append(parent.children, node)
|
|
|
} else if stack.Len() == 0 {
|
|
|
//never go there
|
|
|
ast.children = append(ast.children, node)
|
|
|
}
|
|
|
case EMBELL:
|
|
|
if stack.Len() > 0 {
|
|
|
//读取父节点
|
|
|
ele := stack.Back()
|
|
|
|
|
|
//并将对象强制转为MtAST类型
|
|
|
parent := ele.Value.(*MtAST)
|
|
|
parent.children = append(parent.children, node)
|
|
|
|
|
|
switch EmbellType(node.value.(*MtEmbellRd).embellType) {
|
|
|
//数据结构中,这些数据是在字符后面,但是在latex展示中某些字符需要在字符前面
|
|
|
//比如: $$ \hat y $$
|
|
|
//所以我们需要交换最后2位
|
|
|
case emb1DOT, embHAT, embOBAR:
|
|
|
if len(parent.children) >= 2 {
|
|
|
embellData := parent.children[len(parent.children)-1]
|
|
|
charData := parent.children[len(parent.children)-2]
|
|
|
parent.children = parent.children[:len(parent.children)-2]
|
|
|
|
|
|
parent.children = append(parent.children, embellData, charData)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//如果与0 <nil> 匹配,则需要入栈
|
|
|
stack.PushBack(node)
|
|
|
|
|
|
//case COLOR_DEF:
|
|
|
// /*
|
|
|
// 这个数据结构有3或4个(RGB或者CMYK)对应的nil,所以需要循环把每个值都push到栈里面
|
|
|
//
|
|
|
// 16 &{values:[0 0 0] name:}
|
|
|
// 0 <nil>
|
|
|
// 0 <nil>
|
|
|
// 0 <nil>
|
|
|
// */
|
|
|
//
|
|
|
// colorList := node.value.(*MtColorDef).values
|
|
|
// if len(colorList) > 0 {
|
|
|
// //读取每个color的值,然后入栈
|
|
|
// for _, val := range colorList {
|
|
|
// //如果与0 <nil> 匹配,则需要入栈
|
|
|
// stack.PushBack(val)
|
|
|
// }
|
|
|
// }
|
|
|
//case FONT_STYLE_DEF:
|
|
|
// /*
|
|
|
// 这个数据结构如下,所以需要配对6个入栈
|
|
|
// 8 &{fontDefIndex:1 name:}
|
|
|
// 0 <nil>
|
|
|
// 0 <nil>
|
|
|
// 0 <nil>
|
|
|
// 0 <nil>
|
|
|
// 0 <nil>
|
|
|
// 0 <nil>
|
|
|
// */
|
|
|
//
|
|
|
// fontIndex := node.value.(*MtfontStyleDef).fontDefIndex
|
|
|
// if fontIndex == 1 {
|
|
|
// for i := 0; i < 6; i++ {
|
|
|
// //如果与0 <nil> 匹配,则需要入栈
|
|
|
// stack.PushBack(0)
|
|
|
// }
|
|
|
// }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//m.ast.debug(0)
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (m *MTEFv5) makeLatex(ast *MtAST) (latex string, err error) {
|
|
|
/**
|
|
|
根据出栈入栈结构生成latex字符串
|
|
|
*/
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
|
switch ast.tag {
|
|
|
case ROOT:
|
|
|
buf.WriteString("$$ ")
|
|
|
for _, _ast := range ast.children {
|
|
|
_latex, _ := m.makeLatex(_ast)
|
|
|
buf.WriteString(_latex)
|
|
|
}
|
|
|
buf.WriteString(" $$")
|
|
|
return buf.String(), nil
|
|
|
case CHAR:
|
|
|
mtcode := ast.value.(*MtChar).mtcode
|
|
|
typeface := ast.value.(*MtChar).typeface
|
|
|
char := string(mtcode)
|
|
|
|
|
|
//生成char的一些特殊集
|
|
|
hexExtend := ""
|
|
|
typefaceFmt := ""
|
|
|
switch typeface - 128 {
|
|
|
case fnMTEXTRA:
|
|
|
hexExtend = "/mathmode"
|
|
|
case fnSPACE:
|
|
|
hexExtend = "/mathmode"
|
|
|
case fnTEXT:
|
|
|
typefaceFmt = "{ \\rm{ %v } }"
|
|
|
}
|
|
|
|
|
|
//生成扩展字符的key
|
|
|
hexCode := fmt.Sprintf("%04x", mtcode)
|
|
|
hexKey := fmt.Sprintf("char/0x%v%v", hexCode, hexExtend)
|
|
|
|
|
|
//fmt.Println(char, hexKey)
|
|
|
|
|
|
//首先去找扩展字符
|
|
|
sChar, ok := Chars[hexKey]
|
|
|
if ok {
|
|
|
char = sChar
|
|
|
} else {
|
|
|
//如果char是特殊symbol,需要转义
|
|
|
sChar, ok := SpecialChar[char]
|
|
|
if ok {
|
|
|
char = sChar
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//确定字符是否为文本,如果是文本,则需要包一层
|
|
|
if typefaceFmt != "" {
|
|
|
char = fmt.Sprintf(typefaceFmt, char)
|
|
|
}
|
|
|
|
|
|
buf.WriteString(char)
|
|
|
return buf.String(), nil
|
|
|
case TMPL:
|
|
|
//强制类型转换为MtTmpl
|
|
|
tmpl := ast.value.(*MtTmpl)
|
|
|
|
|
|
switch SelectorType(tmpl.selector) {
|
|
|
case tmANGLE:
|
|
|
mainAST := ast.children[0]
|
|
|
leftAST := ast.children[1]
|
|
|
rightAST := ast.children[2]
|
|
|
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
leftSlot, _ := m.makeLatex(leftAST)
|
|
|
rightSlot, _ := m.makeLatex(rightAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr, leftStr, rightStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("{ %v }", mainSlot)
|
|
|
}
|
|
|
if leftSlot != "" {
|
|
|
leftStr = fmt.Sprintf("\\left %v", leftSlot)
|
|
|
}
|
|
|
if rightSlot != "" {
|
|
|
rightStr = fmt.Sprintf("\\right %v", rightSlot)
|
|
|
}
|
|
|
|
|
|
buf.WriteString(fmt.Sprintf("%v %v %v", leftStr, mainStr, rightStr))
|
|
|
return buf.String(), nil
|
|
|
|
|
|
case tmPAREN:
|
|
|
mainAST := ast.children[0]
|
|
|
leftAST := ast.children[1]
|
|
|
rightAST := ast.children[2]
|
|
|
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
leftSlot, _ := m.makeLatex(leftAST)
|
|
|
rightSlot, _ := m.makeLatex(rightAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr, leftStr, rightStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("{ %v }", mainSlot)
|
|
|
}
|
|
|
if leftSlot != "" {
|
|
|
leftStr = fmt.Sprintf("\\left %v", leftSlot)
|
|
|
}
|
|
|
if rightSlot != "" {
|
|
|
rightStr = fmt.Sprintf("\\right %v", rightSlot)
|
|
|
}
|
|
|
|
|
|
buf.WriteString(fmt.Sprintf("%v %v %v", leftStr, mainStr, rightStr))
|
|
|
return buf.String(), nil
|
|
|
case tmBRACE:
|
|
|
var mainSlot, leftSlot, rightSlot string
|
|
|
for idx, astData := range ast.children {
|
|
|
if idx == 0 {
|
|
|
mainSlot, _ = m.makeLatex(astData)
|
|
|
} else if idx == 1 {
|
|
|
leftSlot, _ = m.makeLatex(astData)
|
|
|
} else {
|
|
|
rightSlot, _ = m.makeLatex(astData)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if rightSlot == "" {
|
|
|
rightSlot = "."
|
|
|
} else {
|
|
|
rightSlot = " " + rightSlot
|
|
|
}
|
|
|
|
|
|
//组装公式
|
|
|
buf.WriteString(fmt.Sprintf(
|
|
|
"\\left %v \\begin{array}{l} %v \\end{array} \\right%v",
|
|
|
leftSlot, mainSlot, rightSlot))
|
|
|
|
|
|
return buf.String(), nil
|
|
|
case tmBRACK:
|
|
|
mainAST := ast.children[0]
|
|
|
leftAST := ast.children[1]
|
|
|
rightAST := ast.children[2]
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
if mainSlot == "" {
|
|
|
mainSlot = "\\space"
|
|
|
}
|
|
|
leftSlot, _ := m.makeLatex(leftAST)
|
|
|
rightSlot, _ := m.makeLatex(rightAST)
|
|
|
buf.WriteString(fmt.Sprintf("\\left%v %v \\right%v", leftSlot, mainSlot, rightSlot))
|
|
|
return buf.String(), nil
|
|
|
case tmBAR:
|
|
|
//读取数据 ParBoxClass
|
|
|
var mainSlot, leftSlot, rightSlot string
|
|
|
for idx, astData := range ast.children {
|
|
|
if idx == 0 {
|
|
|
mainSlot, _ = m.makeLatex(astData)
|
|
|
} else if idx == 1 {
|
|
|
leftSlot, _ = m.makeLatex(astData)
|
|
|
} else {
|
|
|
rightSlot, _ = m.makeLatex(astData)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if rightSlot == "" {
|
|
|
rightSlot = "."
|
|
|
} else {
|
|
|
rightSlot = " " + rightSlot
|
|
|
}
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr, leftStr, rightStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("{ %v }", mainSlot)
|
|
|
}
|
|
|
if leftSlot != "" {
|
|
|
leftStr = fmt.Sprintf("\\left %v", leftSlot)
|
|
|
}
|
|
|
if rightSlot != "" {
|
|
|
rightStr = fmt.Sprintf("\\right %v", rightSlot)
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v %v", leftStr, mainStr, rightStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
return buf.String(), nil
|
|
|
case tmINTERVAL:
|
|
|
//读取数据 ParBoxClass
|
|
|
mainAST := ast.children[0]
|
|
|
leftAST := ast.children[1]
|
|
|
rightAST := ast.children[2]
|
|
|
|
|
|
//读取latex数据
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
leftSlot, _ := m.makeLatex(leftAST)
|
|
|
rightSlot, _ := m.makeLatex(rightAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr, leftStr, rightStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("{ %v }", mainSlot)
|
|
|
}
|
|
|
if leftSlot != "" {
|
|
|
leftStr = fmt.Sprintf("\\left %v", leftSlot)
|
|
|
}
|
|
|
if rightSlot != "" {
|
|
|
rightStr = fmt.Sprintf("\\right %v", rightSlot)
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v %v", leftStr, mainStr, rightStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
return buf.String(), nil
|
|
|
case tmROOT:
|
|
|
mainAST := ast.children[0]
|
|
|
radiAST := ast.children[1]
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
radiSlot, _ := m.makeLatex(radiAST)
|
|
|
buf.WriteString(fmt.Sprintf("\\sqrt[%v] { %v }", radiSlot, mainSlot))
|
|
|
return buf.String(), nil
|
|
|
case tmFRACT:
|
|
|
numAST := ast.children[0]
|
|
|
denAST := ast.children[1]
|
|
|
numSlot, _ := m.makeLatex(numAST)
|
|
|
denSlot, _ := m.makeLatex(denAST)
|
|
|
buf.WriteString(fmt.Sprintf("\\frac { %v } { %v }", numSlot, denSlot))
|
|
|
return buf.String(), nil
|
|
|
case tmARROW:
|
|
|
/*
|
|
|
variation symbol description
|
|
|
0×0000 tvAR_SINGLE single arrow
|
|
|
0×0001 tvAR_DOUBLE double arrow
|
|
|
0×0002 tvAR_HARPOON harpoon
|
|
|
0×0004 tvAR_TOP top slot is present
|
|
|
0×0008 tvAR_BOTTOM bottom slot is present
|
|
|
0×0010 tvAR_LEFT if single, arrow points left
|
|
|
0×0020 tvAR_RIGHT if single, arrow points right
|
|
|
0×0010 tvAR_LOS if double or harpoon, large over small
|
|
|
0×0020 tvAR_SOL if double or harpoon, small over large
|
|
|
*/
|
|
|
topAST := ast.children[0]
|
|
|
bottomAST := ast.children[1]
|
|
|
|
|
|
//读取latex数据
|
|
|
topSlot, _ := m.makeLatex(topAST)
|
|
|
bottomSlot, _ := m.makeLatex(bottomAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var topStr, bottomStr string
|
|
|
if topSlot != "" {
|
|
|
topStr = fmt.Sprintf("{\\mathrm{ %v }}", topSlot)
|
|
|
}
|
|
|
if bottomSlot != "" {
|
|
|
bottomStr = fmt.Sprintf("[\\mathrm{ %v }]", bottomSlot)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
variation转码
|
|
|
*/
|
|
|
variationsMap := make(map[uint16]string)
|
|
|
variationsMap[0x0000] = "single"
|
|
|
variationsMap[0x0001] = "double"
|
|
|
variationsMap[0x0002] = "harpoon"
|
|
|
variationsMap[0x0004] = "topSlotPresent"
|
|
|
variationsMap[0x0008] = "bottomSlotPresent"
|
|
|
variationsMap[0x0010] = "pointLeft"
|
|
|
variationsMap[0x0020] = "pointRight"
|
|
|
|
|
|
//有序循环
|
|
|
variationsCode := []uint16{0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020}
|
|
|
|
|
|
arrowStyle := "single"
|
|
|
latexFmt := "\\x"
|
|
|
for _, vCode := range variationsCode {
|
|
|
//如果存在掩码
|
|
|
if vCode&uint16(tmpl.variation) != 0 {
|
|
|
//判断类型,默认是single
|
|
|
if variationsMap[vCode] == "double" {
|
|
|
arrowStyle = "double"
|
|
|
} else if variationsMap[vCode] == "harpoon" {
|
|
|
arrowStyle = "harpoon"
|
|
|
}
|
|
|
|
|
|
if arrowStyle == "single" && variationsMap[vCode] == "pointLeft" {
|
|
|
latexFmt = latexFmt + "leftarrow"
|
|
|
} else if arrowStyle == "double" && variationsMap[vCode] == "pointLeft" {
|
|
|
fmt.Println("not implement double , large over small")
|
|
|
} else if arrowStyle == "harpoon" && variationsMap[vCode] == "pointLeft" {
|
|
|
fmt.Println("not implement harpoon, large over small")
|
|
|
}
|
|
|
|
|
|
if arrowStyle == "single" && variationsMap[vCode] == "pointRight" {
|
|
|
latexFmt = latexFmt + "rightarrow"
|
|
|
} else if arrowStyle == "double" && variationsMap[vCode] == "pointRight" {
|
|
|
fmt.Println("not implement double , small over large")
|
|
|
} else if arrowStyle == "harpoon" && variationsMap[vCode] == "pointRight" {
|
|
|
fmt.Println("not implement harpoon, small over large")
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
/*
|
|
|
variation转码 END
|
|
|
*/
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v %v", latexFmt, bottomStr, topStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
return buf.String(), nil
|
|
|
case tmUBAR:
|
|
|
//读取数据
|
|
|
mainAST := ast.children[0]
|
|
|
|
|
|
//读取latex数据
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf(" {\\underline{ %v }} ", mainSlot)
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf(" %v ", mainStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
//返回数据
|
|
|
return buf.String(), nil
|
|
|
case tmSUM:
|
|
|
//读取数据 BigOpBoxClass
|
|
|
var mainSlot, upperSlot, lowerSlot, operatorSlot string
|
|
|
for idx, astData := range ast.children {
|
|
|
if idx == 0 {
|
|
|
mainSlot, _ = m.makeLatex(astData)
|
|
|
} else if idx == 1 {
|
|
|
lowerSlot, _ = m.makeLatex(astData)
|
|
|
} else if idx == 2 {
|
|
|
upperSlot, _ = m.makeLatex(astData)
|
|
|
} else {
|
|
|
operatorSlot, _ = m.makeLatex(astData)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr, lowerStr, upperStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("{ %v }", mainSlot)
|
|
|
}
|
|
|
if lowerSlot != "" {
|
|
|
lowerStr = fmt.Sprintf("\\limits_{ %v }", lowerSlot)
|
|
|
}
|
|
|
if upperSlot != "" {
|
|
|
upperStr = fmt.Sprintf("^ %v", upperSlot)
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v %v %v", operatorSlot, lowerStr, upperStr, mainStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
return buf.String(), nil
|
|
|
case tmLIM:
|
|
|
//读取数据 LimBoxClass
|
|
|
var mainSlot, lowerSlot, upperSlot string
|
|
|
for idx, astData := range ast.children {
|
|
|
if idx == 0 {
|
|
|
mainSlot, _ = m.makeLatex(astData)
|
|
|
} else if idx == 1 {
|
|
|
lowerSlot, _ = m.makeLatex(astData)
|
|
|
} else {
|
|
|
upperSlot, _ = m.makeLatex(astData)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr, lowerStr, upperStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("\\mathop { %v }", mainSlot)
|
|
|
}
|
|
|
if lowerSlot != "" {
|
|
|
lowerStr = fmt.Sprintf("\\limits_{ %v }", lowerSlot)
|
|
|
}
|
|
|
if upperSlot != "" {
|
|
|
upperStr = ""
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v %v", mainStr, lowerStr, upperStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
return buf.String(), nil
|
|
|
case tmSUP:
|
|
|
subAST := ast.children[0]
|
|
|
supAST := ast.children[1]
|
|
|
subSlot, _ := m.makeLatex(subAST)
|
|
|
supSlot, _ := m.makeLatex(supAST)
|
|
|
|
|
|
buf.WriteString(" ^ { ")
|
|
|
buf.WriteString(supSlot)
|
|
|
buf.WriteString(" } ")
|
|
|
if subSlot != "" {
|
|
|
buf.WriteString(" { ")
|
|
|
buf.WriteString(subSlot)
|
|
|
buf.WriteString(" } ")
|
|
|
}
|
|
|
return buf.String(), nil
|
|
|
case tmSUB:
|
|
|
//读取下标和上标
|
|
|
subAST := ast.children[0]
|
|
|
supAST := ast.children[1]
|
|
|
|
|
|
//读取latex数据
|
|
|
subSlot, _ := m.makeLatex(subAST)
|
|
|
supSlot, _ := m.makeLatex(supAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var subFmt, supFmt string
|
|
|
if subSlot != "" {
|
|
|
subFmt = fmt.Sprintf("_{ %v }", subSlot)
|
|
|
}
|
|
|
if supSlot != "" {
|
|
|
supFmt = fmt.Sprintf("^{ %v }", supSlot)
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v", subFmt, supFmt)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
//返回数据
|
|
|
return buf.String(), nil
|
|
|
case tmSUBSUP:
|
|
|
//读取下标和上标
|
|
|
subAST := ast.children[0]
|
|
|
supAST := ast.children[1]
|
|
|
|
|
|
//读取latex数据
|
|
|
subSlot, _ := m.makeLatex(subAST)
|
|
|
supSlot, _ := m.makeLatex(supAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var subFmt, supFmt string
|
|
|
if subSlot != "" {
|
|
|
subFmt = fmt.Sprintf("_{ %v }", subSlot)
|
|
|
}
|
|
|
if supSlot != "" {
|
|
|
supFmt = fmt.Sprintf("^{ %v }", supSlot)
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v", subFmt, supFmt)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
//返回数据
|
|
|
return buf.String(), nil
|
|
|
case tmVEC:
|
|
|
/*
|
|
|
variations:
|
|
|
variation symbol description
|
|
|
0×0001 tvVE_LEFT arrow points left
|
|
|
0×0002 tvVE_RIGHT arrow points right
|
|
|
0×0004 tvVE_UNDER arrow under slot, else over slot
|
|
|
0×0008 tvVE_HARPOON harpoon
|
|
|
|
|
|
这个转换是通过掩码计算的:
|
|
|
比如variation的值是3,即0000 0000 0000 0011
|
|
|
|
|
|
对应的是0×0001和0×0002:
|
|
|
0000 0000 0000 0001
|
|
|
0000 0000 0000 0010
|
|
|
*/
|
|
|
|
|
|
//读取数据 HatBoxClass
|
|
|
mainAST := ast.children[0]
|
|
|
|
|
|
//读取latex数据
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("{ %v }", mainSlot)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
variation转码
|
|
|
*/
|
|
|
variationsMap := make(map[uint16]string)
|
|
|
variationsMap[0x0001] = "left"
|
|
|
variationsMap[0x0002] = "right"
|
|
|
variationsMap[0x0004] = "tvVE_UNDER"
|
|
|
variationsMap[0x0008] = "harpoonup"
|
|
|
|
|
|
//有序循环
|
|
|
variationsCode := []uint16{0x0001, 0x0002, 0x0004, 0x0008}
|
|
|
|
|
|
topStr := "\\overset\\"
|
|
|
for _, vCode := range variationsCode {
|
|
|
if vCode&uint16(tmpl.variation) != 0 {
|
|
|
topStr = topStr + variationsMap[vCode]
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//如果variationCode小于8,则一定不是harpoon,那么默认就使用arrow
|
|
|
if tmpl.variation < 8 {
|
|
|
topStr = topStr + "arrow"
|
|
|
}
|
|
|
/*
|
|
|
variation转码 END
|
|
|
*/
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v", topStr, mainStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
return buf.String(), nil
|
|
|
case tmHAT:
|
|
|
//读取数据 HatBoxClass
|
|
|
mainAST := ast.children[0]
|
|
|
topAST := ast.children[1]
|
|
|
|
|
|
//读取latex数据
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
topSlot, _ := m.makeLatex(topAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr, topStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("{ %v }", mainSlot)
|
|
|
}
|
|
|
if topSlot != "" {
|
|
|
topStr = fmt.Sprintf(" %v ", topSlot)
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v", topStr, mainStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
return buf.String(), nil
|
|
|
case tmARC:
|
|
|
//读取数据 HatBoxClass
|
|
|
mainAST := ast.children[0]
|
|
|
topAST := ast.children[1]
|
|
|
|
|
|
//读取latex数据
|
|
|
mainSlot, _ := m.makeLatex(mainAST)
|
|
|
topSlot, _ := m.makeLatex(topAST)
|
|
|
|
|
|
//转成latex代码
|
|
|
var mainStr, topStr string
|
|
|
if mainSlot != "" {
|
|
|
mainStr = fmt.Sprintf("{ %v }", mainSlot)
|
|
|
}
|
|
|
if topSlot != "" {
|
|
|
topStr = fmt.Sprintf("\\overset %v", topSlot)
|
|
|
}
|
|
|
|
|
|
//组成整体公式
|
|
|
tmplStr := fmt.Sprintf("%v %v", topStr, mainStr)
|
|
|
buf.WriteString(tmplStr)
|
|
|
|
|
|
return buf.String(), nil
|
|
|
default:
|
|
|
m.Valid = false
|
|
|
log.Println("TMPL NOT IMPLEMENT", tmpl.selector, tmpl.variation)
|
|
|
}
|
|
|
for _, _ast := range ast.children {
|
|
|
_latex, _ := m.makeLatex(_ast)
|
|
|
buf.WriteString(_latex)
|
|
|
}
|
|
|
return buf.String(), nil
|
|
|
case PILE:
|
|
|
for idx, _ast := range ast.children {
|
|
|
_latex, _ := m.makeLatex(_ast)
|
|
|
|
|
|
//多个line字符串数据以 \\ 分割
|
|
|
if idx > 0 {
|
|
|
buf.WriteString(" \\\\ ")
|
|
|
}
|
|
|
|
|
|
buf.WriteString(_latex)
|
|
|
}
|
|
|
return buf.String(), nil
|
|
|
case MATRIX:
|
|
|
matrixCol := int(ast.value.(*MtMatrix).cols)
|
|
|
for idx, _ast := range ast.children {
|
|
|
_latex, _ := m.makeLatex(_ast)
|
|
|
|
|
|
if idx == 0 {
|
|
|
buf.WriteString(" \\begin{array} {} ")
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
buf.WriteString(_latex)
|
|
|
|
|
|
if idx%matrixCol == 0 {
|
|
|
buf.WriteString(" \\\\ ")
|
|
|
} else {
|
|
|
buf.WriteString(" & ")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
buf.WriteString(" \\end{array} ")
|
|
|
return buf.String(), nil
|
|
|
case LINE:
|
|
|
for _, _ast := range ast.children {
|
|
|
_latex, _ := m.makeLatex(_ast)
|
|
|
buf.WriteString(_latex)
|
|
|
}
|
|
|
return buf.String(), nil
|
|
|
case EMBELL:
|
|
|
embellType := EmbellType(ast.value.(*MtEmbellRd).embellType)
|
|
|
var embellStr string
|
|
|
|
|
|
switch embellType {
|
|
|
case emb1DOT:
|
|
|
embellStr = " \\dot "
|
|
|
case emb1PRIME:
|
|
|
embellStr = "'"
|
|
|
case emb2PRIME:
|
|
|
embellStr = "''"
|
|
|
case emb3PRIME:
|
|
|
embellStr = "'''"
|
|
|
case embHAT:
|
|
|
embellStr = " \\hat "
|
|
|
case embOBAR:
|
|
|
embellStr = " \\bar "
|
|
|
default:
|
|
|
log.Println("not implement embell:", embellType)
|
|
|
}
|
|
|
|
|
|
buf.WriteString(embellStr)
|
|
|
return buf.String(), nil
|
|
|
}
|
|
|
|
|
|
return "", nil
|
|
|
}
|
|
|
|
|
|
//[MTEF Storage](https://docs.wiris.com/en/mathtype/mathtype_desktop/mathtype-sdk/mtefstorage)
|
|
|
func Open(reader io.ReadSeeker) (eqn *MTEFv5, err error) {
|
|
|
//parse `mtef` stream from `ole` object
|
|
|
ole, err := ole2.Open(reader, "")
|
|
|
if err != nil {
|
|
|
fmt.Println(err)
|
|
|
}
|
|
|
|
|
|
dir, err := ole.ListDir()
|
|
|
if err != nil {
|
|
|
fmt.Println(err)
|
|
|
}
|
|
|
|
|
|
for _, file := range dir {
|
|
|
if "Equation Native" == file.Name() {
|
|
|
root := dir[0]
|
|
|
reader := ole.OpenFile(file, root)
|
|
|
|
|
|
hdrBuffer := make([]byte, oleCbHdr)
|
|
|
if _, err := reader.Read(hdrBuffer); err == nil {
|
|
|
hdrReader := bytes.NewReader(hdrBuffer)
|
|
|
var cbHdr = uint16(0)
|
|
|
var cbSize = uint32(0)
|
|
|
|
|
|
_ = binary.Read(hdrReader, binary.LittleEndian, &cbHdr)
|
|
|
if cbHdr != oleCbHdr {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
//ignore `version: u32` and `cf: u16`
|
|
|
_, _ = hdrReader.Seek(4+2, io.SeekCurrent)
|
|
|
_ = binary.Read(hdrReader, binary.LittleEndian, &cbSize)
|
|
|
|
|
|
//body from `cbHdr` to `cbHdr + cbSize`
|
|
|
eqnBody := make([]byte, cbSize)
|
|
|
_, _ = reader.Seek(int64(cbHdr), io.SeekStart)
|
|
|
_, _ = reader.Read(eqnBody)
|
|
|
|
|
|
eqn = new(MTEFv5)
|
|
|
eqn.reader = bytes.NewReader(eqnBody)
|
|
|
_ = eqn.readRecord()
|
|
|
_ = eqn.makeAST()
|
|
|
return eqn, nil
|
|
|
}
|
|
|
|
|
|
return nil, err
|
|
|
}
|
|
|
}
|
|
|
return nil, err
|
|
|
}
|