func validateOrder(msg Message) MessageRejectError { inHeader := true inTrailer := false for _, field := range msg.fields { t := field.Tag switch { case inHeader && tag.IsHeader(t): case inHeader && !tag.IsHeader(t): inHeader = false case !inHeader && tag.IsHeader(t): return tagSpecifiedOutOfRequiredOrder(t) case tag.IsTrailer(t): inTrailer = true case inTrailer && !tag.IsTrailer(t): return tagSpecifiedOutOfRequiredOrder(t) } } return nil }
func validateFields(transportDD *datadictionary.DataDictionary, appDD *datadictionary.DataDictionary, msgType string, message Message) MessageRejectError { for _, field := range message.fields { switch { case tag.IsHeader(field.Tag): if err := validateField(transportDD, transportDD.Header.Tags, field); err != nil { return err } case tag.IsTrailer(field.Tag): if err := validateField(transportDD, transportDD.Trailer.Tags, field); err != nil { return err } default: if err := validateField(appDD, appDD.Messages[msgType].Tags, field); err != nil { return err } } } return nil }
//parseMessage constructs a Message from a byte slice wrapping a FIX message. func parseMessage(rawMessage []byte) (*Message, error) { var header, body, trailer fieldMap header.init(headerFieldOrder) body.init(normalFieldOrder) trailer.init(trailerFieldOrder) msg := &Message{Header: header, Body: body, Trailer: trailer, rawMessage: rawMessage} //allocate fields in one chunk fieldCount := 0 for _, b := range rawMessage { if b == '\001' { fieldCount++ } } msg.fields = make([]fieldBytes, fieldCount) fieldIndex := 0 var err error //message must start with begin string, body length, msg type if rawMessage, err = extractSpecificField(&msg.fields[fieldIndex], tag.BeginString, rawMessage); err != nil { return nil, err } header.fieldLookup[msg.fields[fieldIndex].Tag] = &msg.fields[fieldIndex] fieldIndex++ parsedFieldBytes := &msg.fields[fieldIndex] if rawMessage, err = extractSpecificField(parsedFieldBytes, tag.BodyLength, rawMessage); err != nil { return nil, err } header.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes fieldIndex++ parsedFieldBytes = &msg.fields[fieldIndex] if rawMessage, err = extractSpecificField(parsedFieldBytes, tag.MsgType, rawMessage); err != nil { return nil, err } header.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes fieldIndex++ trailerBytes := []byte{} foundBody := false for { parsedFieldBytes = &msg.fields[fieldIndex] rawMessage, err = extractField(parsedFieldBytes, rawMessage) if err != nil { return nil, err } switch { case tag.IsHeader(parsedFieldBytes.Tag): header.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes case tag.IsTrailer(parsedFieldBytes.Tag): trailer.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes default: foundBody = true trailerBytes = rawMessage body.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes } if parsedFieldBytes.Tag == tag.CheckSum { break } if !foundBody { msg.bodyBytes = rawMessage } fieldIndex++ } //body length would only be larger than trailer if fields out of order if len(msg.bodyBytes) > len(trailerBytes) { msg.bodyBytes = msg.bodyBytes[:len(msg.bodyBytes)-len(trailerBytes)] } length := 0 for _, field := range msg.fields { switch field.Tag { case tag.BeginString, tag.BodyLength, tag.CheckSum: //tags do not contribute to length default: length += field.Length() } } bodyLength := new(fix.IntValue) msg.Header.GetField(tag.BodyLength, bodyLength) if bodyLength.Value != length { return msg, parseError{OrigError: fmt.Sprintf("Incorrect Message Length, expected %d, got %d", bodyLength.Value, length)} } return msg, nil }