1337 lines
33 KiB
Go
1337 lines
33 KiB
Go
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
|
||
}
|