### Install moov-io/iso8583 Package Source: https://github.com/moov-io/iso8583/blob/master/README.md Use 'go get' to install the ISO8583 package. This command fetches and installs the package, making it available for use in your Go projects. ```go go get github.com/moov-io/iso8583 ``` -------------------------------- ### Run ISO 8583 CLI Source: https://github.com/moov-io/iso8583/blob/master/README.md Execute the installed ISO 8583 CLI to view available commands and usage information. This is the basic command to start the CLI. ```bash ./iso8583 ``` -------------------------------- ### Install ISO 8583 CLI for MacOS Source: https://github.com/moov-io/iso8583/blob/master/README.md Download the latest release binary for MacOS and make it executable. This command fetches the binary and sets execute permissions. ```bash wget -O ./iso8583 https://github.com/moov-io/iso8583/releases/download/v0.4.6/iso8583_0.4.6_darwin_amd64 && chmod +x ./iso8583 ``` -------------------------------- ### Read Network Header and Message in Go Source: https://github.com/moov-io/iso8583/blob/master/README.md Example of reading a network header (BCD2Bytes) and then the ISO message into a buffer. Assumes a network.Header implementation is used. ```go header := network.NewBCD2BytesHeader() _, err := header.ReadFrom(conn) if err != nil { // handle error } // Make a buffer to hold message buf := make([]byte, header.Length()) // Read the incoming message into the buffer. read, err := io.ReadFull(conn, buf) if err != nil { // handle error } if reqLen != header.Length() { // handle error } message := iso8583.NewMessage(specs.Spec87ASCII) message.Unpack(buf) ``` -------------------------------- ### Get moov-io/iso8583 Source Code Source: https://github.com/moov-io/iso8583/blob/master/CONTRIBUTING.md Use the 'go get' command to download the source code. Ensure your GOPATH is set correctly. ```bash $ go get github.com/moov-io/iso8583 ``` -------------------------------- ### Fuzzit Integration for OSS Projects Source: https://github.com/moov-io/iso8583/blob/master/test/fuzz-reader/README.md Steps to integrate the ISO8583 fuzzing setup with Fuzzit, a SaaS for automated fuzzing, including corpus preparation and job creation. ```bash # In test/fuzz-reader/ $ fuzzit create job --type=fuzzing iso8583fuzz fuzzit.sh 2019/08/19 10:38:59 Creating job... 2019/08/19 10:38:59 Uploading fuzzer... 2019/08/19 10:39:01 Starting job 2019/08/19 10:39:02 Job p55FXmV2MsHSsBsNLGrT started succesfully 2019/08/19 10:39:02 Job created successfully ``` -------------------------------- ### Write Network Header and Message in Go Source: https://github.com/moov-io/iso8583/blob/master/README.md Example of packing an ISO message, setting its length on a network header, and writing both to a connection. Uses a BCD2Bytes header implementation. ```go header := network.NewBCD2BytesHeader() packed, err := message.Pack() if err != nil { // handle error } header.SetLength(len(packed)) _, err = header.WriteTo(conn) if err != nil { // handle error } n, err := conn.Write(packed) if err != nil { // handle error } ``` -------------------------------- ### Retrieve Unknown Tags from ISO Message in Go Source: https://github.com/moov-io/iso8583/blob/master/README.md Use the UnknownTags helper to get a map of unknown fields keyed by their dot-separated path after unpacking a message. Requires StoreUnknownTLVTags to be enabled. ```go msg := iso8583.NewMessage(spec) err := msg.Unpack(rawData) if err != nil { // handle error } unknownTags := iso8583.UnknownTags(msg) for path, f := range unknownTags { val, _ := f.Bytes() fmt.Printf("Unknown tag at %s: %X\n", path, val) } ``` -------------------------------- ### Retrieve All Unknown Tags from a Message Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Use the `UnknownTags` helper function to get a map of all unknown tags present in a parsed message. The map is keyed by dot-separated paths to the unknown tags. ```go unknownTags := iso8583.UnknownTags(msg) for path, f := range unknownTags { val, _ := f.Bytes() fmt.Printf("Unknown tag at %s: %X\n", path, val) } ``` -------------------------------- ### Custom Field Filtering for Description Source: https://github.com/moov-io/iso8583/blob/master/README.md Define custom filter functions to redact specific fields when describing a message. The example shows how to mask the value of field 2. ```go filterAll = func(in string, data field.Field) string { runesInString := utf8.RuneCountInString(in) return strings.Repeat("*", runesInString) } // filter only value of the field 2 isо8583.Describe(message, os.Stdout, filterAll(2, filterAll)) ``` -------------------------------- ### Print Message Fields to Stdout Source: https://github.com/moov-io/iso8583/blob/master/README.md Use the Describe function to print all message fields and their values to standard output. By default, sensitive data is masked. ```go // print message to os.Stdout isо8583.Describe(message, os.Stdout) ``` -------------------------------- ### Define, Pack, and Unpack ISO 8583 Message in Go Source: https://github.com/moov-io/iso8583/blob/master/README.md Demonstrates defining message structure using Go types, packing a message for transmission, and unpacking/parsing a received message. Requires the 'github.com/moov-io/iso8583' library and a message spec. ```go package main import ( "fmt" "os" "github.com/moov/iso8583" "github.com/moov/iso8583/examples" ) // Define types for the message fields type Authorization struct { MTI string `iso8583:"0"` // Message Type Indicator PrimaryAccountNumber string `iso8583:"2"` // PAN ProcessingCode string `iso8583:"3"` // Processing code Amount int64 `iso8583:"4"` // Transaction amount STAN string `iso8583:"11"` // System Trace Audit Number ExpirationDate string `iso8583:"14"` // YYMM AcceptorInformation *AcceptorInformation `iso8583:"43"` // Merchant details } type AcceptorInformation struct { Name string `iso8583:"1"` City string `iso8583:"2"` Country string `iso8583:"3"` } func main() { // Pack the message msg := iso8583.NewMessage(examples.Spec) authData := &Authorization{ MTI: "0100", PrimaryAccountNumber: "4242424242424242", ProcessingCode: "000000", Amount: 2599, ExpirationDate: "2201", AcceptorInformation: &AcceptorInformation{ Name: "Merchant Name", City: "Denver", Country: "US", }, } // Set the field values err := msg.Marshal(authData) if err != nil { panic(err) } // Pack the message packed, err := msg.Pack() if err != nil { panic(err) } // send packed message to the server // ... // Unpack the message msg = iso8583.NewMessage(examples.Spec) err = msg.Unpack(packed) if err != nil { panic(err) } // get individual field values var amount int64 err = msg.UnmarshalPath("4", &amount) if err != nil { panic(err) } fmt.Printf("Amount: %d\n", amount) // get value of composite subfield var acceptorName string err = msg.UnmarshalPath("43.1", &acceptorName) if err != nil { panic(err) } fmt.Printf("Acceptor Name: %s\n", acceptorName) // Get the field values into data structure authData = &Authorization{} err = msg.Unmarshal(authData) if err != nil { panic(err) } // Print the entire message iso8583.Describe(msg, os.Stdout) } ``` -------------------------------- ### Building ISO 8583 Messages Source: https://github.com/moov-io/iso8583/blob/master/README.md Illustrates the process of building an ISO 8583 message. The typical workflow involves setting message data, packing it into bytes, and then sending it over the network. ```Go Set Data → Pack → Network → ``` -------------------------------- ### Run Local Checks Source: https://github.com/moov-io/iso8583/blob/master/CONTRIBUTING.md Execute 'make check' to run Go tests and linters before submitting changes. This ensures code quality and adherence to project standards. ```bash make check ``` -------------------------------- ### Test Composite Field Specification and Data Handling in Go Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Demonstrates defining a composite field specification with nested subfields, marshaling data into it, packing it into binary, and then unpacking and unmarshaling to verify data integrity. This approach is useful for testing complex field structures independently. ```go type TestData struct { MerchantData *MerchantData `index:"56"` } type MerchantData struct { MerchantID *field.String `index:"01"` } func TestDataSetCompositeField(t *testing.T) { // Define the specification for a composite field with Data Set IDs spec := &field.Spec{ Length: 255, Description: "Test Data Set Field", Pref: prefix.Binary.L, Tag: &field.TagSpec{ Length: 1, Enc: encoding.ASCIIHexToBytes, Sort: sort.StringsByHex, SkipUnknownTLVTags: true, PrefUnknownTLV: prefix.Binary.LL, }, Subfields: map[string]field.Field{ "56": field.NewComposite(&field.Spec{ Length: 255, Description: "Merchant Data", Pref: prefix.Binary.LL, Tag: &field.TagSpec{ Enc: encoding.BerTLVTag, Sort: sort.StringsByHex, }, Subfields: map[string]field.Field{ "01": field.NewString(&field.Spec{ Length: 11, Description: "Merchant ID", Enc: encoding.EBCDIC, Pref: prefix.BerTLV, }), }, }), }, } // Create a new composite field with our spec composite := field.NewComposite(spec) data := &TestData{ MerchantData: &MerchantData{ MerchantID: field.NewStringValue("12345ABCDE"), }, } // Marshal the data into the field err := composite.Marshal(data) require.NoError(t, err) // Pack the field to binary packed, err := composite.Pack() require.NoError(t, err) // Optional: Inspect the packed data for debugging t.Logf("Packed data (hex): %X", packed) // Create a new field for unpacking unpackedField := field.NewComposite(spec) // Unpack the binary data read, err := unpackedField.Unpack(packed) require.NoError(t, err) require.Equal(t, len(packed), read, "Should read all bytes") // Unmarshal into a new struct to verify data unpacked := &TestData{} err = unpackedField.Unmarshal(unpacked) require.NoError(t, err) // Verify the data matches require.NotNil(t, unpacked.MerchantData) require.NotNil(t, unpacked.MerchantData.MerchantID) require.Equal(t, "12345ABCDE", unpacked.MerchantData.MerchantID.Value()) } ``` -------------------------------- ### Configure Skipping Unknown Tags and Data Sets Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Enable skipping of unknown tags and Data Set IDs during parsing by setting `SkipUnknownTLVTags` to true. Configure the length prefix for unknown tags using `PrefUnknownTLV`. ```go spec := &field.Spec{ // ... other settings ... Tag: &field.TagSpec{ SkipUnknownTLVTags: true, // Enable skipping unknown tags PrefUnknownTLV: prefix.ASCII.L, // Format for unknown tag length }, } ``` -------------------------------- ### Display ISO 8583 Message with Spec Source: https://github.com/moov-io/iso8583/blob/master/README.md Display an ISO 8583 message using a specific built-in specification. Use the '-spec' flag to select the desired spec. ```bash ./bin/iso8583 describe -spec spec87ascii msg.bin ``` -------------------------------- ### Download Crashers from Kubernetes Source: https://github.com/moov-io/iso8583/blob/master/test/fuzz-reader/README.md Commands to retrieve crash files from a running `moov/iso8583fuzz` Docker container in a Kubernetes cluster. ```bash # Get current pod name $ kubectl get pods -n apps | grep iso8583fuzz iso8583fuzz-6bbdc574f5-pl2zm 1/1 Running 0 1h ``` ```bash $ kubectl exec -n apps iso8583fuzz-6bbdc574f5-pl2zm -- ls -la /go/src/github.com/moov-io/iso8583/test/fuzz-reader/crashers/ total 28 drwxr-xr-x 3 root root 4096 Jan 30 00:26 . drwxr-xr-x 1 root root 4096 Jan 14 17:30 .. # Download files, replace with a crasher file $ kubectl cp 'apps/iso8583fuzz-6bbdc574f5-pl2zm:/go/src/github.com/moov-io/iso8583/test/fuzz-reader/crashers/' ./ ``` -------------------------------- ### Create and Marshal ISO 8583 Message with Go Structs Source: https://github.com/moov-io/iso8583/blob/master/README.md Create a new ISO 8583 message, populate a struct with transaction data, and marshal it into the message object. Ensure error handling for marshaling and packing. ```go // Create new message msg := iso8583.NewMessage(Spec) // Prepare transaction data auth := &Authorization{ MTI: "0100", PrimaryAccountNumber: "4242424242424242", ProcessingCode: "000000", Amount: 9999, STAN: "000123", LocalTime: "152059", LocalDate: "0205", MerchantType: "5411", AcceptorInfo: &Acceptor{ Name: "ACME Store", City: "New York", Country: "US", }, } // Marshal data into message err := msg.Marshal(auth) if err != nil { panic(err) } // Pack for transmission data, err := msg.Pack() if err != nil { panic(err) } // data is ready to be sent ``` -------------------------------- ### Legacy: Use Package-Specific Field Types Source: https://github.com/moov-io/iso8583/blob/master/README.md Utilize legacy field types like `field.String` and `field.Numeric` for message definition. While supported, native Go types are recommended for new development. ```go type LegacyAuthorization struct { MTI *field.String `iso8583:"0"` PAN *field.String `iso8583:"2"` Amount *field.Numeric `iso8583:"4"` LocalTime *field.String `iso8583:"12"` } var auth LegacyAuthorization msg.Unmarshal(&auth) fmt.Println(auth.MTI.Value()) fmt.Println(auth.Amount.Value()) ``` -------------------------------- ### Default Numeric Field Packing (BCD) Source: https://github.com/moov-io/iso8583/blob/master/docs/howtos.md Demonstrates the default behavior of a Numeric field with BCD encoding and a binary length prefix. The length prefix indicates the number of digits in the field value. ```go f := field.NewNumeric(&field.Spec{ Length: 9, // The max length of the field is 9 digits Description: "Amount", Enc: encoding.BCD, Pref: prefix.Binary.L, }) f.SetValue(123) packed, err := f.Pack() require.NoError(t, err) require.Equal(t, []byte{0x03, 0x01, 0x23}, packed) ``` -------------------------------- ### Legacy: Use Package-Specific Field Types Source: https://github.com/moov-io/iso8583/blob/master/README.md Legacy method for defining ISO 8583 fields using package-specific types like `field.String` and `field.Numeric`. While supported, using native Go types is recommended for new development. ```go type Authorization struct { MTI *field.String `iso8583:"0"` PAN *field.String `iso8583:"2"` Amount *field.Numeric `iso8583:"4"` LocalTime *field.String `iso8583:"12"` } auth := &Authorization{ MTI: field.NewStringValue("0100"), PAN: field.NewStringValue("4242424242424242"), Amount: field.NewNumericValue(9999), LocalTime: field.NewStringValue("152059"), } msg.Marshal(auth) ``` -------------------------------- ### Include Empty Values with `keepzero` Tag Option Source: https://github.com/moov-io/iso8583/blob/master/README.md Use the `keepzero` option in the `iso8583` field tag to include empty values in the message. This sets the field bit in the bitmap but leaves the value empty. Ensure correct padding for such fields. ```go type Authorization struct { // ... AdditionalData string `iso8583:"48,keepzero"` // Additional data } ``` -------------------------------- ### Define Go Structs for ISO 8583 Messages Source: https://github.com/moov-io/iso8583/blob/master/README.md Define Go structs with `iso8583` tags to map business data to ISO 8583 fields. Use native Go types for recommended usage. ```go type Authorization struct { MTI string `iso8583:"0"` // Message Type Indicator PrimaryAccountNumber string `iso8583:"2"` // PAN ProcessingCode string `iso8583:"3"` // Processing code Amount int64 `iso8583:"4"` // Transaction amount STAN string `iso8583:"11"` // System Trace Audit Number LocalTime string `iso8583:"12"` // HHmmss LocalDate string `iso8583:"13"` // MMDD MerchantType string `iso8583:"18"` // Merchant category code AcceptorInfo *Acceptor `iso8583:"43"` // Merchant details } type Acceptor struct { Name string `iso8583:"1"` City string `iso8583:"2"` Country string `iso8583:"3"` } ``` -------------------------------- ### Display ISO 8583 Message with Spec File Source: https://github.com/moov-io/iso8583/blob/master/README.md Display an ISO 8583 message using a custom specification defined in a JSON file. Use the '-spec-file' flag to provide the path to your spec file. ```bash ./bin/iso8583 describe -spec-file ./examples/specs/spec87ascii.json msg.bin ``` -------------------------------- ### Define ISO 8583 Message Structure with Go Structs Source: https://github.com/moov-io/iso8583/blob/master/README.md Define message structures using native Go types and `iso8583` tags for field mapping. This is the recommended approach for clarity and type safety. ```go type Authorization struct { MTI string `iso8583:"0"` // Message Type Indicator PrimaryAccountNumber string `iso8583:"2"` // PAN ProcessingCode string `iso8583:"3"` // Processing code Amount int64 `iso8583:"4"` // Transaction amount STAN string `iso8583:"11"` // System Trace Audit Number LocalTime string `iso8583:"12"` // HHmmss LocalDate string `iso8583:"13"` // MMDD MerchantType string `iso8583:"18"` // Merchant category code AcceptorInfo *Acceptor `iso8583:"43"` // Merchant details } type Acceptor struct { Name string `iso8583:"1"` City string `iso8583:"2"` Country string `iso8583:"3"` } ``` -------------------------------- ### Display ISO 8583 Message Source: https://github.com/moov-io/iso8583/blob/master/README.md Display the contents of an ISO 8583 message file in a human-readable format. This command uses the default specification. ```bash ./bin/iso8583 describe msg.bin ``` -------------------------------- ### Add User Fork as Git Remote Source: https://github.com/moov-io/iso8583/blob/master/CONTRIBUTING.md After cloning the repository, add your fork as a remote git repository for pushing and pulling changes. Fetch updates from your remote. ```bash cd $GOPATH/src/github.com/moov-io/iso8583 git remote add $user git@github.com:$user/iso8583.git git fetch $user ``` -------------------------------- ### Skip Unknown Non-BER TLV Tags Source: https://github.com/moov-io/iso8583/blob/master/README.md For non-BER TLV fields, set `SkipUnknownTLVTags: true` and specify `PrefUnknownTLV` to define how the parser should read the length of unknown tags. This requires a consistent tag length and length prefix format. ```go Tag: &field.TagSpec{ Length: 2, // tag length in bytes Enc: encoding.ASCII, Sort: sort.Strings, SkipUnknownTLVTags: true, PrefUnknownTLV: prefix.ASCII.L, // length prefix format for unknown tags }, ``` -------------------------------- ### Set Individual ISO 8583 Fields Directly Source: https://github.com/moov-io/iso8583/blob/master/README.md For simple operations, set individual ISO 8583 fields directly on the message object using string or byte slice values. The library handles underlying type conversions. Error handling is required for field setting and packing. ```go msg := iso8583.NewMessage(spec) // Set MTI msg.MTI("0100") // Set field values as strings err := msg.Field(2, "4242424242424242") err = msg.Field(3, "000000") err = msg.Field(4, "9999") // For binary fields err = msg.BinaryField(52, []byte{0x1A, 0x2B, 0x3C, 0x4D}) // Pack for transmission data, err := msg.Pack() ``` -------------------------------- ### Processing ISO 8583 Messages Source: https://github.com/moov-io/iso8583/blob/master/README.md Outlines the steps for processing an incoming ISO 8583 message. This involves unpacking the received bytes, retrieving the message data, and then processing it within the application. ```Go → Network → Unpack → Get Data ``` -------------------------------- ### Partial ISO 8583 Message Parsing with MessageScanner Source: https://github.com/moov-io/iso8583/blob/master/README.md Use `MessageScanner` for efficient, forward-only parsing of specific fields without unpacking the entire message. This is ideal for proxies and routers needing to inspect fields like MTI or STAN. ```go s := iso8583.NewMessageScanner(spec, rawBytes) // Scan MTI to decide how to handle the message f, err := s.ScanField(0) if err != nil { // handle error } mti, err := f.String() if err != nil { // handle error } if mti == "0800" { // Network management message — forward raw bytes to a // dedicated handler without further parsing handleNetworkMessage(rawBytes) return } // For other messages, continue scanning to get STAN f, err = s.ScanField(11) if err != nil { // handle error } stan, err := f.String() if err != nil { // handle error } // Route or log based on MTI and STAN fmt.Printf("MTI: %s, STAN: %s\n", mti, stan) ``` -------------------------------- ### Store Unknown Tags for Later Retrieval Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Preserve unknown tags during parsing by enabling `StoreUnknownTLVTags`. This allows for re-packing messages with all original data, including unknown fields. ```go spec := &field.Spec{ // ... other settings ... Tag: &field.TagSpec{ Enc: encoding.BerTLVTag, Sort: sort.StringsByHex, SkipUnknownTLVTags: true, StoreUnknownTLVTags: true, // keep unknown tags in the message }, } ``` -------------------------------- ### Manually Set Unknown Tag on Composite Field in Go Source: https://github.com/moov-io/iso8583/blob/master/README.md Use MarshalPath to set an unknown, packable tag on a composite field. Requires SkipUnknownTLVTags and StoreUnknownTLVTags to be enabled, and the value to implement field.Field. ```go // Set an unknown tag on field 55 err := msg.MarshalPath("55.9F36", &field.Binary{...}) ``` -------------------------------- ### Define TLV Field Specification Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Configure a TLV field with explicit tag and value length encoding. Use this when the tag length and value length are fixed and defined by the specification. ```go spec := &field.Spec{ Length: 999, Description: "TLV Data Field", Pref: prefix.ASCII.LLL, Tag: &field.TagSpec{ Length: 2, Enc: encoding.ASCII, Sort: sort.StringsByInt, }, Subfields: map[string]field.Field{ "01": field.NewString(&field.Spec{ Length: 10, Description: "Name", Enc: encoding.ASCII, Pref: prefix.ASCII.LL, }), "02": field.NewString(&field.Spec{ Length: 20, Description: "Address", Enc: encoding.ASCII, Pref: prefix.ASCII.LL, }), }, } ``` -------------------------------- ### Unpack and Parse ISO 8583 Message into Go Struct Source: https://github.com/moov-io/iso8583/blob/master/README.md Unpack raw message bytes into a Go struct using a specified message spec. Ensure to handle potential errors during unpacking and unmarshalling. ```go // Create message with appropriate spec msg := iso8583.NewMessage(specs.Spec87ASCII) // Unpack received bytes err := msg.Unpack(receivedData) if err != nil { panic(err) } // Parse into struct var auth Authorization err = msg.Unmarshal(&auth) if err != nil { panic(err) } // Work with parsed data fmt.Printf("Transaction amount: %d\n", auth.Amount) fmt.Printf("Merchant: %s, %s\n", auth.AcceptorInfo.Name, auth.AcceptorInfo.City) // Print full message contents (with sensitive data masked) iso8583.Describe(msg, os.Stdout) ``` -------------------------------- ### Enable Storing Unknown TLV Tags in Go Source: https://github.com/moov-io/iso8583/blob/master/README.md Configure a TagSpec to store unknown TLV tags instead of discarding them. This preserves all original data when repacking messages. ```go Tag: &field.TagSpec{ Enc: encoding.BerTLVTag, Sort: sort.StringsByHex, SkipUnknownTLVTags: true, StoreUnknownTLVTags: true, // keep unknown tags in the message }, ``` -------------------------------- ### Retrieve Unknown Tags from Composite Field in Go Source: https://github.com/moov-io/iso8583/blob/master/README.md Use UnknownCompositeTags to retrieve unknown fields from a standalone *field.Composite. This function only returns results if StoreUnknownTLVTags is enabled in the field specs. ```go composite := field.NewComposite(spec) _, err := composite.Unpack(rawData) if err != nil { // handle error } unknownTags := iso8583.UnknownCompositeTags(composite) for path, f := range unknownTags { val, _ := f.Bytes() fmt.Printf("Unknown tag at %s: %X\n", path, val) } ``` -------------------------------- ### Serialize Message to JSON Source: https://github.com/moov-io/iso8583/blob/master/README.md Convert an ISO 8583 message object into its JSON representation using `json.Marshal`. The bitmap is excluded from the JSON output. ```go jsonMessage, err := json.Marshal(message) ``` -------------------------------- ### Skip Unknown BER-TLV Tags Source: https://github.com/moov-io/iso8583/blob/master/README.md Configure a `TagSpec` to skip unknown BER-TLV tags during parsing by setting `SkipUnknownTLVTags: true`. This is useful when the specification includes tags not defined in your `Subfields`. ```go Tag: &field.TagSpec{ Enc: encoding.BerTLVTag, Sort: sort.StringsByHex, SkipUnknownTLVTags: true, // skip tags not in Subfields }, ``` -------------------------------- ### Custom Numeric Field Packing (BCD) with Encoded Length Prefix Source: https://github.com/moov-io/iso8583/blob/master/docs/howtos.md Implements custom packer and unpacker functions for a Numeric field. The custom packer encodes the length of the BCD-encoded data in the length prefix, not the number of digits. This is useful when the encoded data length differs from the value length. ```go f := field.NewNumeric(&field.Spec{ Length: 9, // max length of the field value (9 digits) Description: "Amount", Enc: encoding.BCD, Pref: prefix.Binary.L, // Define a custom packer to encode the length of the packed data Packer: field.PackerFunc(func(value []byte, spec *field.Spec) ([]byte, error) { if spec.Pad != nil { value = spec.Pad.Pad(value, spec.Length) } encodedValue, err := spec.Enc.Encode(value) if err != nil { return nil, fmt.Errorf("failed to encode content: %w", err) } // Encode the length of the packed data, not the length of the value maxLength := spec.Length/2 + 1 // Encode the length of the encoded value lengthPrefix, err := spec.Pref.EncodeLength(maxLength, len(encodedValue)) if err != nil { return nil, fmt.Errorf("failed to encode length: %w", err) } return append(lengthPrefix, encodedValue...), }), // Define a custom unpacker to decode the length of the packed data Unpacker: field.UnpackerFunc(func(packedFieldValue []byte, spec *field.Spec) ([]byte, int, error) { maxEncodedValueLength := spec.Length/2 + 1 encodedValueLength, prefBytes, err := spec.Pref.DecodeLength(maxEncodedValueLength, packedFieldValue) if err != nil { return nil, 0, fmt.Errorf("failed to decode length: %w", err) } // for BCD encoding, the length of the packed data is twice the length of the encoded value valueLength := encodedValueLength * 2 // Decode the packed data length value, read, err := spec.Enc.Decode(packedFieldValue[prefBytes:], valueLength) if err != nil { return nil, 0, fmt.Errorf("failed to decode content: %w", err) } if spec.Pad != nil { value = spec.Pad.Unpad(value) } return value, read + prefBytes, nil }), }) f.SetValue(123) packed, err = f.Pack() require.NoError(t, err) require.Equal(t, []byte{0x02, 0x01, 0x23}, packed) ``` -------------------------------- ### Define BER-TLV Field Specification Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Configure a BER-TLV field where tag and value length are dynamically encoded. Use this for EMV data or other specifications following BER-TLV rules. ```go spec := &field.Spec{ Length: 999, Description: "EMV Data", Pref: prefix.ASCII.LLL, Tag: &field.TagSpec{ Enc: encoding.BerTLVTag, Sort: sort.StringsByHex, }, Subfields: map[string]field.Field{ "9F02": field.NewHex(&field.Spec{ Description: "Amount, Authorized", Enc: encoding.Binary, Pref: prefix.BerTLV, }), }, } ``` -------------------------------- ### Define Nested Composite Field with Data Set IDs Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Configure a composite field with Data Set IDs as tags, where each Data Set ID maps to another composite field. This structure is useful for organizing hierarchical data within a message. ```go spec := &field.Spec{ Length: 255, Description: "Extended Transaction Data", Pref: prefix.Binary.L, Tag: &field.TagSpec{ Length: 1, // Data Set ID length Enc: encoding.ASCIIHexToBytes, Sort: sort.StringsByHex, // Configure handling of unknown Data Set IDs SkipUnknownTLVTags: true, // Data Set length prefix (2 bytes) // It matches the Pref of the inner subfield PrefUnknownTLV: prefix.Binary.LL, }, Subfields: map[string]field.Field{ "56": field.NewComposite(&field.Spec{ // Data Set ID "56" Length: 1535, Description: "Merchant Information Data", Pref: prefix.Binary.LL, // Data Set length prefix Tag: &field.TagSpec{ Enc: encoding.BerTLVTag, Sort: sort.StringsByHex, SkipUnknownTLVTags: true, }, Subfields: map[string]field.Field{ "9F": field.NewString(&field.Spec{ Length: 11, Description: "Merchant Identifier", Enc: encoding.EBCDIC, Pref: prefix.BerTLV, }), "80": field.NewString(&field.Spec{ Length: 15, Description: "Terminal Identifier", Enc: encoding.EBCDIC, Pref: prefix.BerTLV, }), }, }), }, } ``` -------------------------------- ### Display Unfiltered Field Values Source: https://github.com/moov-io/iso8583/blob/master/README.md Use the predefined `DoNotFilterFields` to display all message field values without any masking. ```go // display unfiltered field values isо8583.Describe(message, os.Stdout, DoNotFilterFields()...) ``` -------------------------------- ### Access Individual ISO 8583 Fields Source: https://github.com/moov-io/iso8583/blob/master/README.md Access individual fields of an ISO 8583 message by their number. Note that individual field access is limited to string or byte slice values. ```go msg := iso8583.NewMessage(spec) err := msg.Unpack(receivedData) // Get MTI mti, err := msg.GetMTI() // Get field values as strings pan, err := msg.GetString(2) proc, err := msg.GetString(3) amount, err := msg.GetString(4) // Get binary field values pinData, err := msg.GetBytes(52) ``` -------------------------------- ### Define Data Structures for Composite Field Data Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Defines Go structs that correspond to the composite field specifications. These structs are used for marshaling and unmarshaling data, mapping field indices to struct fields. ```go // Corresponding data struct definitions that can be used to marshal/unmarshal type Field125Data struct { MerchantData *MerchantDataSet `index:"56"` TerminalData *TerminalDataSet `index:"65"` } type MerchantDataSet struct { MerchantId *field.String `index:"01"` TerminalId *field.String `index:"02"` LegalName *field.String `index:"81"` DBAName *field.String `index:"82"` } type TerminalDataSet struct { Capabilities *field.Hex `index:"03"` Type *field.Hex `index:"04"` SerialNumber *field.String `index:"87"` } ``` -------------------------------- ### Define Positional Subfields in Go Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Defines a composite field with multiple positional subfields. Ensure the total length matches the sum of subfield lengths for fixed-length subfields. The `Sort` function dictates subfield order during packing/unpacking. ```go spec := &field.Spec{ Length: 30, // Total length of all subfields combined Description: "Structured Field", Pref: prefix.ASCII.Fixed, Tag: &field.TagSpec{ Sort: sort.StringsByInt, // Only sorting is needed, no encoding }, Subfields: map[string]field.Field{ "01": field.NewString(&field.Spec{ // First subfield Length: 2, Description: "Type", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, }), "02": field.NewString(&field.Spec{ // Second subfield Length: 18, Description: "Name", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, }), "03": field.NewString(&field.Spec{ // Third subfield Length: 10, Description: "Account Number", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, }), }, } ``` -------------------------------- ### Unmarshal JSON into Message Object Source: https://github.com/moov-io/iso8583/blob/master/README.md Parse a JSON string into an `iso8583.Message` object. Ensure to handle potential errors during the unmarshalling process. ```go input := `{"0":"0100","2":"4242424242424242","4":"100"}` message := NewMessage(spec) if err := json.Unmarshal([]byte(input), message); err != nil { // handle err } // access indidual fields or using struct ``` -------------------------------- ### Define Composite Field with Data Set IDs and BER-TLV Source: https://github.com/moov-io/iso8583/blob/master/docs/composite-fields.md Defines a complex composite field (Field 125) that includes nested Data Set IDs and BER-TLV encoded subfields. This is useful for representing hierarchical or structured data within a single ISO 8583 field. ```go // Field 125 specification field125Spec := &field.Spec{ Length: 255, Description: "Extended Transaction Data", Pref: prefix.Binary.L, Tag: &field.TagSpec{ Length: 1, // Data Set ID length in bytes Enc: encoding.ASCIIHexToBytes, // Data Set ID below is ASCII hex and will be converted to bytes (1 byte) Sort: sort.StringsByHex, // Handle unknown Data Set IDs SkipUnknownTLVTags: true, PrefUnknownTLV: prefix.Binary.LL, // Data Set length format }, Subfields: map[string]field.Field{ "56": field.NewComposite(&field.Spec{ // Data Set ID Length: 1535, Description: "Merchant Information Data", Pref: prefix.Binary.LL, // Length of the entire Data Set value Tag: &field.TagSpec{ Enc: encoding.BerTLVTag, Sort: sort.StringsByHex, SkipUnknownTLVTags: true, }, Subfields: map[string]field.Field{ "01": field.NewString(&field.Spec{ Length: 11, Description: "Merchant Identifier", Enc: encoding.EBCDIC, Pref: prefix.BerTLV, }), "02": field.NewString(&field.Spec{ Length: 15, Description: "Terminal Identifier", Enc: encoding.EBCDIC, Pref: prefix.BerTLV, }), "81": field.NewString(&field.Spec{ Length: 25, Description: "Merchant Legal Name", Enc: encoding.EBCDIC, Pref: prefix.BerTLV, }), "82": field.NewString(&field.Spec{ Length: 25, Description: "Merchant DBA Name", Enc: encoding.EBCDIC, Pref: prefix.BerTLV, }), }, }), // Data Set ID "65" - Terminal Information "65": field.NewComposite(&field.Spec{ Length: 1535, Description: "Terminal Information Data", Pref: prefix.Binary.LL, Tag: &field.TagSpec{ Enc: encoding.BerTLVTag, Sort: sort.StringsByHex, SkipUnknownTLVTags: true, }, Subfields: map[string]field.Field{ "03": field.NewHex(&field.Spec{ Description: "Terminal Capabilities", Enc: encoding.Binary, Pref: prefix.BerTLV, }), "04": field.NewHex(&field.Spec{ Description: "Terminal Type", Enc: encoding.Binary, Pref: prefix.BerTLV, }), "87": field.NewString(&field.Spec{ Length: 8, Description: "Terminal Serial Number", Enc: encoding.EBCDIC, Pref: prefix.BerTLV, }), }, }), }, } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.