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
}
Exemple #3
0
//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
}