jspurefix
Version:
pure node js fix engine
193 lines (173 loc) • 5.54 kB
text/typescript
import { Tags } from '../tags'
import { MessageDefinition } from '../../dictionary/definition'
import { ElasticBuffer } from '../elastic-buffer'
export enum ParseState {
BeginField = 1,
ParsingTag = 2,
ParsingValue = 3,
ParsingRawDataLength = 4,
ParsingRawData = 5,
MsgComplete = 6
}
export class AsciiParserState {
public message: MessageDefinition
public locations: Tags
public parseState: ParseState
public bodyLen: number
public checksumExpectedPos: number
public tagStartPos: number
public equalPos: number
public valueEndPos: number
public count: number
public currentTag: number
public rawDataLen: number
public rawDataRead: number
public msgType: string
constructor (public readonly elasticBuffer: ElasticBuffer) {
}
public beginTag (pos: number) {
this.parseState = ParseState.ParsingTag
this.tagStartPos = pos
this.equalPos = this.valueEndPos = -1
this.currentTag = 0
}
public endTag (pos: number): void {
this.equalPos = pos
const state = this.parseState
switch (state) {
case ParseState.ParsingTag: {
this.currentTag = this.elasticBuffer.getWholeNumber(this.tagStartPos, pos - 1)
break
}
default:
throw new Error(`EndTag: unexpected state ${state}`)
}
// if a raw tag, then need length to skip that many bytes
this.checkRawTag()
}
public incRaw (): boolean {
++this.rawDataRead
return this.rawDataRead === this.rawDataLen + 1
}
public checkRawTag (): void {
const msg = this.message
if (!msg || !msg.containsRaw) {
// optimisation as will never hit raw data
this.parseState = ParseState.ParsingValue
return
}
// if this is a raw data tag then need to keep track of the length
// on this field to skip that many bytes.
const isDataLength: boolean = msg.containedLength[this.currentTag]
if (isDataLength) {
this.parseState = ParseState.ParsingRawDataLength
} else {
this.rawDataRead = 0
const isData: boolean = this.rawDataLen > 0
if (isData) {
this.parseState = ParseState.ParsingRawData
} else {
this.parseState = ParseState.ParsingValue
}
}
}
public store (): void {
const valueEndPos: number = this.elasticBuffer.getPos() - 1
this.valueEndPos = valueEndPos
const equalPos: number = this.equalPos
const tag: number = this.currentTag
const locations: Tags = this.locations
const buffer = this.elasticBuffer
const terminates = this.checksumExpectedPos
switch (this.parseState) {
case ParseState.ParsingValue:
case ParseState.ParsingRawData: {
this.rawDataLen = 0
locations.store(equalPos + 1, valueEndPos - equalPos - 1, tag)
break
}
case ParseState.ParsingRawDataLength: {
this.rawDataLen = buffer.getWholeNumber(equalPos + 1, valueEndPos - 1)
locations.store(equalPos + 1, valueEndPos - equalPos - 1, tag)
break
}
}
this.parseState = ParseState.BeginField
this.count++
const nextTagPos = locations.nextTagPos
switch (tag) {
case Tags.BeginString: {
if (nextTagPos !== 1) {
throw new Error(`BeginString: not expected at position [${nextTagPos}]`)
}
break
}
case Tags.BodyLengthTag: {
if (nextTagPos !== 2) {
throw new Error(`BodyLengthTag: not expected at position [${nextTagPos}]`)
}
this.bodyLen = buffer.getWholeNumber(equalPos + 1, valueEndPos - 1)
this.checksumExpectedPos = this.bodyLen + valueEndPos
this.elasticBuffer.checkGrowBuffer(this.bodyLen)
break
}
case Tags.MsgTag: {
if (nextTagPos !== 3) {
throw new Error(`MsgTag: not expected at position [${nextTagPos}]`)
}
this.msgType = buffer.getString(equalPos + 1, valueEndPos)
this.message = locations.definitions.message.get(this.msgType)
break
}
case Tags.CheckSumTag: {
if (valueEndPos < this.bodyLen) {
throw new Error(`CheckSumTag: [${valueEndPos}] expected after ${this.bodyLen}`)
}
this.parseState = ParseState.MsgComplete
break
}
default: {
if (terminates && valueEndPos > terminates) {
throw new Error(`Tag: [${tag}] cant be after ${terminates}`)
}
break
}
}
switch (nextTagPos) {
case 1: {
if (tag !== Tags.BeginString) {
throw new Error(`position 1 [${tag}] must be BeginString: 8=`)
}
break
}
case 2: {
if (tag !== Tags.BodyLengthTag) {
throw new Error(`position 2 [${tag}] must be BodyLengthTag: 9=`)
}
break
}
case 3: {
if (tag !== Tags.MsgTag) {
throw new Error(`position 3 [${tag}] must be MsgTag: 35=`)
}
break
}
}
}
public beginMessage (): void {
this.elasticBuffer.reset()
this.locations.reset()
this.checksumExpectedPos = 0
this.parseState = ParseState.BeginField
this.count = 0
this.currentTag = 0
this.tagStartPos = 0
this.valueEndPos = 0
this.equalPos = 0
this.rawDataRead = 0
this.rawDataLen = 0
this.bodyLen = 0
this.message = null
this.msgType = null
}
}