npn47_iso8583 0.1.5.a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4490ebe6f888fd296deba7834184d8ec4301ad49
4
+ data.tar.gz: 90f4dba0b5e7f3272dbac6e82472d3067223661c
5
+ SHA512:
6
+ metadata.gz: 5c0880e8ae9b03c7664fca0907199e206182e07b3e64d83a1cb1333a17f7d7b306d05a769095f209aa7ffb8809bcd3b3a371ec4a941e92be5108f4b8d8e9a492
7
+ data.tar.gz: 4a17f409d7eeb87e82b2c8f6a5393b7dec64a108c3139278e56612838168ffd71eb3f86fdb50d50631de8094f2007ca2002929d34aa14e76bcdafc272477931d
data/lib/8583.rb ADDED
@@ -0,0 +1,5 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ # DEPRECATED
5
+ require 'iso8583'
@@ -0,0 +1,82 @@
1
+ # Copyright 2009 by Tim Becker (tim.becker@kuriostaet.de)
2
+ # MIT License, for details, see the LICENSE file accompaning
3
+ # this distribution
4
+
5
+ require 'lib/iso8583'
6
+
7
+
8
+ # Example of a protocol specification based on:
9
+ # http://www.berlin-group.org/documents/BG_Authorisation_3.0.pdf
10
+ # The Berlin Groups Authorisation Interface specification.
11
+ # No gurantees are made that this is an accurate implemenation.
12
+ # It currently serves as an example only.
13
+
14
+ module ISO8583
15
+
16
+ class BerlinMessage < Message
17
+ mti_format N, :length => 4
18
+ mti 1100, "Authorization Request Acquirer Gateway"
19
+ mti 1110, "Authorization Request Response Issuer Gateway"
20
+ mti 1420, "Reversal Advice Acquirer Gateway"
21
+ mti 1421, "Reversal Advice Repeat Acquirer Gateway"
22
+ mti 1430, "Reversal Advice Response Issuer Gateway"
23
+ mti 1804, "Network Management Request Acquirer Gateway or Issuer Gateway"
24
+ mti 1814, "Network Management Request Response Issuer Gateway or Acquirer Gateway"
25
+
26
+ bmp 2, "Primary Account Number (PAN)", LLVAR_N, :max => 19
27
+ bmp 3, "Processing Code", N, :length => 6
28
+ bmp 4, "Amount (Transaction)", N, :length => 12
29
+ bmp 6, "Amount, Cardholder Billing" , N, :length => 12
30
+ bmp 7, "Date and Time, Transmission" , MMDDhhmmss
31
+ bmp 10, "Conversion Rate, Cardholder Billing", N, :length => 8
32
+ bmp 11, "System Trace Audit Number (STAN)", N, :length => 6
33
+ bmp 12, "Date and Time, Local Transaction", YYMMDDhhmmss
34
+ bmp 14, "Date, Expiration", YYMM
35
+ bmp 22, "POS Data Code", AN, :length => 12
36
+ bmp 23, "Card Sequence Number", N, :length => 3
37
+ bmp 24, "Function Code", N, :length => 3
38
+ bmp 25, "Message Reason Code", N, :length => 4
39
+ bmp 26, "Card Acceptor Business Code", N, :length => 4
40
+ bmp 30, "Amounts, Original", N, :length => 24
41
+ bmp 32, "Acquiring Institution Identification Code", LLVAR_N, :max => 11
42
+ bmp 35, "Track 2 Data", LLVAR_Z, :max => 37
43
+ bmp 37, "Retrieval Reference Number", ANP, :length => 12
44
+ bmp 38, "Approval Code", ANP, :length => 6
45
+ bmp 39, "Action Code", N, :length => 3
46
+ bmp 41, "Card Acceptor Terminal Identification", ANS, :length => 8
47
+ bmp 42, "Card Acceptor Identification Code", ANS, :length => 15
48
+ bmp 43, "Card Acceptor Name/Location", LLVAR_ANS, :max => 56
49
+ bmp 49, "Currency Code, Transaction", N, :length => 3
50
+ bmp 51, "Currency Code, Cardholder Billing", N, :length => 3
51
+ bmp 52, "Personal Identification Number (PIN) Data", B, :length => 8
52
+ bmp 53, "Security Related Control Information", LLVAR_B, :max => 48
53
+ bmp 54, "Amounts, Additional", LLLVAR_ANS,:max => 40
54
+
55
+ bmp 55, "Integrated Circuit Card (ICC) System Related Data", LLLVAR_B, :max => 255
56
+ bmp 56, "Original Data Elements", LLVAR_N, :max => 35
57
+ bmp 58, "Authorizing Agent Institution Identification Code", LLVAR_N, :max => 11
58
+ bmp 59, "Additional Data - Private", LLLVAR_ANS, :max => 67
59
+ bmp 64, "Message Authentication Code (MAC) Field", B, :length => 8
60
+
61
+ bmp_alias 2, :pan
62
+ bmp_alias 3, :proc_code
63
+ bmp_alias 4, :amount
64
+ bmp_alias 12, :exp_date
65
+ end
66
+
67
+ end
68
+
69
+ if __FILE__==$0
70
+ mes = ISO8583::BerlinMessage.new
71
+ mes.mti = 1110
72
+ mes[2] = 474747474747
73
+ mes["Processing Code"] = "123456"
74
+
75
+ pan = mes["Primary Account Number (PAN)"]
76
+ #mes.pan = 47474747474747
77
+
78
+ #puts mes.pan
79
+ puts mes.to_b
80
+ puts mes.to_s
81
+ #mes2 = BerlinMessage.parse input
82
+ end
@@ -0,0 +1,117 @@
1
+ # Copyright 2009 by Tim Becker (tim.becker@kuriostaet.de)
2
+ # MIT License, for details, see the LICENSE file accompaning
3
+ # this distribution
4
+
5
+ module ISO8583
6
+
7
+ # This class constructs an object for handling bitmaps
8
+ # with which ISO8583 messages typically begin.
9
+ # Bitmaps are either 8 or 16 bytes long, an extended length
10
+ # bitmap is indicated by the first bit being set.
11
+ # In all likelyhood, you won't be using this class much, it's used
12
+ # transparently by the Message class.
13
+ class Bitmap
14
+
15
+ # create a new Bitmap object. In case an iso message
16
+ # is passed in, that messages bitmap will be parsed. If
17
+ # not, this initializes and empty bitmap.
18
+ def initialize(message = nil)
19
+ @bmp = Array.new(128, false)
20
+ if !message
21
+
22
+ else
23
+ initialize_from_message message
24
+ end
25
+ end
26
+
27
+ # yield once with the number of each set field.
28
+ def each #:yields: each bit set in the bitmap.
29
+ @bmp.each_with_index {|set, i| yield i+1 if set}
30
+ end
31
+
32
+ # Returns whether the bit is set or not.
33
+ def [](i)
34
+ @bmp[i-1]
35
+ end
36
+
37
+ # Set the bit to the indicated value. Only `true` sets the
38
+ # bit, any other value unsets it.
39
+ def []=(i, value)
40
+ if i > 128
41
+ raise ISO8583Exception.new("Bits > 128 are not permitted.")
42
+ elsif i < 2
43
+ raise ISO8583Exception.new("Bits < 2 are not permitted (continutation bit is set automatically)")
44
+ end
45
+ @bmp[i-1] = (value == true)
46
+ end
47
+
48
+ # Sets bit #i
49
+ def set(i)
50
+ self[i] = true
51
+ end
52
+
53
+ # Unsets bit #i
54
+ def unset(i)
55
+ self[i] = false
56
+ end
57
+
58
+ # Generate the bytes representing this bitmap.
59
+ def to_bytes
60
+ arr = [self.to_s]
61
+ # tricky and ugly, setting bit[1] only when generating to_s...
62
+ count = self[1] ? 128 : 64
63
+ arr.pack("B#{count}")
64
+ end
65
+ alias_method :to_b, :to_bytes
66
+
67
+ # Generate a String representation of this bitmap in the form:
68
+ # 01001100110000011010110110010100100110011000001101011011001010
69
+ def to_s
70
+ #check whether any `high` bits are set
71
+ @bmp[0] = false
72
+ 65.upto(128) {|i|
73
+ if self[i]
74
+ # if so, set continuation bit
75
+ @bmp[0] = true
76
+ break
77
+ end
78
+ }
79
+ str = ""
80
+ 1.upto(self[1] ? 128 : 64) {|i|
81
+ str << (self[i] ? "1" : "0")
82
+ }
83
+ str
84
+ end
85
+
86
+
87
+ private
88
+
89
+ def initialize_from_message(message)
90
+ bmp = message.unpack("B64")[0]
91
+ if bmp[0,1] == "1"
92
+ bmp = message.unpack("B128")[0]
93
+ end
94
+
95
+ 0.upto(bmp.length-1) do |i|
96
+ @bmp[i] = (bmp[i,1] == "1")
97
+ end
98
+ end
99
+
100
+ class << self
101
+ # Parse the bytes in string and return the Bitmap and bytes remaining in `str`
102
+ # after the bitmap is taken away.
103
+ def parse(str)
104
+ bmp = Bitmap.new(str)
105
+ rest = bmp[1] ? str[16, str.length] : str[8, str.length]
106
+ [ bmp, rest ]
107
+ end
108
+ end
109
+
110
+ end
111
+ end
112
+
113
+ if __FILE__==$0
114
+ mp = ISO8583::Bitmap.new
115
+ 20.step(128,7) {|i| mp.set(i)}
116
+ print mp.to_bytes
117
+ end
@@ -0,0 +1,196 @@
1
+ # Copyright 2009 by Tim Becker (tim.becker@kuriostaet.de)
2
+ # MIT License, for details, see the LICENSE file accompaning
3
+ # this distribution
4
+
5
+ require 'date'
6
+
7
+ module ISO8583
8
+
9
+ # Codec provides functionality to encode and decode values, codecs are
10
+ # used internally by Field instances in order to do character conversions
11
+ # and checking for proper values.
12
+ # Although they are used internally, you will probably need to write
13
+ # your own Codec sooner or later. The codecs used by Field instances are
14
+ # typically instances of Codec, it may or may not be usefull to subclass
15
+ # Codec.
16
+ #
17
+ # Say, for example, a text field needs to be encoded in EBCDIC in the
18
+ # message, this is how a corresponding codec would be constructed:
19
+ #
20
+ # EBCDIC_Codec = Codec.new
21
+ # EBCDIC_Codec.encoder = lambda {|ascii_str|
22
+ # raise ISO8583Exception.new("String (#{ascii_str})not valid!") unless =~ /someregexp/
23
+ # ascii2ebcdic ascii_str # implementing ascii_str is left as an excercise
24
+ # }
25
+ # EBCDIC_Codec.decode = lambda {|ebcdic_str|
26
+ # # you may or may not want to raise exceptions at this point ....
27
+ # # strip removes any padding...
28
+ # ebcdic2ascii(ebcdic_str).strip
29
+ # }
30
+ #
31
+ # This instance of Codec would then be used be the corresponding Field
32
+ # encoder/decoder, which may look similar to this:
33
+ #
34
+ # EBCDIC = Field.new
35
+ # EBCDIC.codec = EBCDIC_Codec
36
+ # EBCDIC.padding = PADDING_LEFT_JUSTIFIED_SPACES
37
+ #
38
+ # Notice there is a bit of inconsistancy: the padding is added by the
39
+ # field, but removed by the codec. I would like to find a better
40
+ # solution to this...
41
+ #
42
+ # See also: Field, link:files/lib/fields_rb.html
43
+ #
44
+ # The following codecs are already implemented:
45
+ # [+ASCII_Number+] encodes either a Number or String representation of
46
+ # a number to the ASCII represenation of the number,
47
+ # decodes ASCII numerals to a number
48
+ # [+A_Codec+] passes through ASCII string checking they conform to [A-Za-z]
49
+ # during encoding, no validity check during decoding.
50
+ # [+AN_Codec+] passes through ASCII string checking they conform to [A-Za-z0-9]
51
+ # during encoding, no validity check during decoding.
52
+ # [+ANP_Codec+] passes through ASCII string checking they conform to [A-Za-z0-9 ]
53
+ # during encoding, no validity check during decoding.
54
+ # [+ANS_Codec+] passes through ASCII string checking they conform to [\x20-\x7E]
55
+ # during encoding, no validity check during decoding.
56
+ # [+Null_Codec+] passes anything along untouched.
57
+ # [<tt>Track2</tt>] rudimentary check that string conforms to Track2
58
+ # [+MMDDhhmmssCodec+] encodes Time, Datetime or String to the described date format, checking
59
+ # that it is a valid date. Decodes to a DateTime instance, decoding and
60
+ # encoding perform validity checks!
61
+ # [+YYMMDDhhmmssCodec+] encodes Time, Datetime or String to the described date format, checking
62
+ # that it is a valid date. Decodes to a DateTime instance, decoding and
63
+ # encoding perform validity checks!
64
+ # [+YYMMCodec+] encodes Time, Datetime or String to the described date format (exp date),
65
+ # checking that it is a valid date. Decodes to a DateTime instance, decoding
66
+ # and encoding perform validity checks!
67
+ #
68
+ class Codec
69
+ attr_accessor :encoder
70
+ attr_accessor :decoder
71
+
72
+ def decode(raw)
73
+ decoder.call(raw)
74
+ end
75
+
76
+ # length is either a fixnum or a lenth encoder.
77
+ def encode(value)
78
+ encoder.call(value)
79
+ end
80
+ end
81
+
82
+ # ASCII_Number
83
+ ASCII_Number = Codec.new
84
+ ASCII_Number.encoder= lambda{|num|
85
+ enc = num.to_s
86
+ raise ISO8583Exception.new("Invalid value: #{enc} must be numeric!") unless enc =~ /^[0-9]*$/
87
+ enc
88
+ }
89
+
90
+ ASCII_Number.decoder = lambda{|raw|
91
+ raw.to_i
92
+ }
93
+
94
+ PASS_THROUGH_DECODER = lambda{|str|
95
+ str.strip # remove padding
96
+ }
97
+
98
+ # Takes a number or str representation of a number and BCD encodes it, e.g.
99
+ # "1234" => "\x12\x34"
100
+ # 3456 => "\x34\x56"
101
+ #
102
+ # right justified with null ... (correct to do this? almost certainly not...)
103
+ Packed_Number = Codec.new
104
+ Packed_Number.encoder = lambda { |val|
105
+ val = val.to_s
106
+ val = val.length % 2 == 0 ? val : "0"+val
107
+ raise ISO8583Exception.new("Invalid value: #{val} must be numeric!") unless val =~ /^[0-9]*$/
108
+ [val].pack("H*")
109
+ }
110
+ Packed_Number.decoder = lambda{|encoded|
111
+ d = encoded.unpack("H*")[0].to_i
112
+ }
113
+
114
+ A_Codec = Codec.new
115
+ A_Codec.encoder = lambda{|str|
116
+ raise ISO8583Exception.new("Invalid value: #{str} must be [A-Za-z]") unless str =~ /^[A-Za-z]*$/
117
+ str
118
+ }
119
+ A_Codec.decoder = PASS_THROUGH_DECODER
120
+
121
+ AN_Codec = Codec.new
122
+ AN_Codec.encoder = lambda{|str|
123
+ raise ISO8583Exception.new("Invalid value: #{str} must be [A-Za-y0-9]") unless str =~ /^[A-Za-z0-9]*$/
124
+ str
125
+ }
126
+ AN_Codec.decoder = PASS_THROUGH_DECODER
127
+
128
+ ANP_Codec = Codec.new
129
+ ANP_Codec.encoder = lambda{|str|
130
+ raise ISO8583Exception.new("Invalid value: #{str} must be [A-Za-y0-9 ]") unless str =~ /^[A-Za-z0-9 ]*$/
131
+ str
132
+ }
133
+ ANP_Codec.decoder = PASS_THROUGH_DECODER
134
+
135
+ ANS_Codec = Codec.new
136
+ ANS_Codec.encoder = lambda{|str|
137
+ raise ISO8583Exception.new("Invalid value: #{str} must be [\x20-\x7E]") unless str =~ /^[\x20-\x7E]*$/
138
+ str
139
+ }
140
+ ANS_Codec.decoder = PASS_THROUGH_DECODER
141
+
142
+ Null_Codec = Codec.new
143
+ Null_Codec.encoder = lambda {|str|
144
+ str
145
+ }
146
+ Null_Codec.decoder = lambda {|str|
147
+ str.gsub(/\000*$/, '')
148
+ }
149
+
150
+ Track2 = Codec.new
151
+ Track2.encoder = lambda{|track2|
152
+ #SS | PAN | FS | Expiration Date | Service Code | Discretionary Data | ES | LRC
153
+ # SS = ;
154
+ # PAN = up to 19 digits (at least 9?)
155
+ # FS = '='
156
+ # Exp Date = YYMM
157
+ # SC: 3 digits or =
158
+ # ES = ?
159
+ # lrc : 1byte
160
+ raise ISO8583Exception.new("Invalid Track2 data: #{track2}") unless track2 =~ /^;*(\d{9,19})=(.*)\?.$/
161
+ track2
162
+ }
163
+ Track2.decoder = PASS_THROUGH_DECODER
164
+
165
+ def self._date_codec(fmt)
166
+ c = Codec.new
167
+ c.encoder = lambda {|date|
168
+ enc = case date
169
+ when DateTime, Date, Time
170
+ date.strftime(fmt)
171
+ when String
172
+ begin
173
+ dt = DateTime.strptime(date, fmt)
174
+ dt.strftime(fmt)
175
+ rescue
176
+ raise ISO8583Exception.new("Invalid format encoding: #{date}, must be #{fmt}.")
177
+ end
178
+ else
179
+ raise ISO8583Exception.new("Don't know how to encode: #{date.class} to a time.")
180
+ end
181
+ return enc
182
+ }
183
+ c.decoder = lambda {|str|
184
+ begin
185
+ DateTime.strptime(str, fmt)
186
+ rescue
187
+ raise ISO8583Exception.new("Invalid format decoding: #{str}, must be #{fmt}.")
188
+ end
189
+ }
190
+
191
+ c
192
+ end
193
+
194
+ YYYYMMDDHHcodec = _date_codec("%Y%m%d%H")
195
+ YYYYMMDDHH24MISScodec = _date_codec("YYYYMMDDHH24MISScodec")
196
+ end
@@ -0,0 +1,4 @@
1
+ module ISO8583
2
+ class ISO8583Exception < Exception; end
3
+ class ISO8583ParseException < ISO8583Exception; end
4
+ end
@@ -0,0 +1,90 @@
1
+ module ISO8583
2
+
3
+ class Field
4
+ # may either be some other Field in which the length is encoded or a Fixnum for
5
+ # fixed length fields. Length should always be the length of the *encoded* value.
6
+ # A 6 digit BCD field will require a length 3, as will a 5 digit BCD field.
7
+ # The subclass BCDField handles this to keep things consistant.
8
+ attr_accessor :length
9
+ attr_accessor :codec
10
+ attr_accessor :padding
11
+ attr_accessor :max
12
+
13
+ attr_writer :name
14
+ attr_accessor :bmp
15
+
16
+ def name
17
+ "BMP #{bmp}: #{@name}"
18
+ end
19
+
20
+ def parse(raw)
21
+ len, raw = case length
22
+ when Fixnum
23
+ [length, raw]
24
+ when Field
25
+ length.parse(raw)
26
+ else
27
+ raise ISO8583Exception.new("Cannot determine the length of '#{name}' field")
28
+ end
29
+
30
+ raw_value = raw[0,len]
31
+
32
+ # make sure we have enough data ...
33
+ if raw_value.length != len
34
+ mes = "Field has incorrect length! field: #{raw_value} len/expected: #{raw_value.length}/#{len}"
35
+ raise ISO8583ParseException.new(mes)
36
+ end
37
+
38
+ rest = raw[len, raw.length]
39
+ begin
40
+ real_value = codec.decode(raw_value)
41
+ rescue
42
+ raise ISO8583ParseException.new($!.message+" (#{name})")
43
+ end
44
+
45
+ [ real_value, rest ]
46
+ end
47
+
48
+
49
+ # Encoding needs to consider length representation, the actual encoding (such as charset or BCD)
50
+ # and padding.
51
+ # The order may be important! This impl calls codec.encode and then pads, in case you need the other
52
+ # special treatment, you may need to override this method alltogether.
53
+ # In other cases, the padding has to be implemented by the codec, such as BCD with an odd number of nibbles.
54
+ def encode(value)
55
+ encoded_value = codec.encode(value)
56
+
57
+ if padding
58
+ if padding.arity == 1
59
+ encoded_value = padding.call(encoded_value)
60
+ elsif padding.arity == 2
61
+ encoded_value = padding.call(encoded_value, length)
62
+ end
63
+ end
64
+
65
+ len_str = case length
66
+ when Fixnum
67
+ raise ISO8583Exception.new("Too long: #{value} (#{name})! length=#{length}") if encoded_value.length > length
68
+ raise ISO8583Exception.new("Too short: #{value} (#{name})! length=#{length}") if encoded_value.length < length
69
+ ""
70
+ when Field
71
+ raise ISO8583Exception.new("Max lenth exceeded: #{value}, max: #{max}") if max && encoded_value.length > max
72
+ length.encode(encoded_value.length)
73
+ else
74
+ raise ISO8583Exception.new("Invalid length (#{length}) for '#{name}' field")
75
+ end
76
+
77
+ len_str + encoded_value
78
+ end
79
+ end
80
+
81
+ class BCDField < Field
82
+ # This corrects the length for BCD fields, as their encoded length is half (+ parity) of the
83
+ # content length. E.g. 123 (length = 3) encodes to "\x01\x23" (length 2)
84
+ def length
85
+ _length = super
86
+ (_length % 2) != 0 ? (_length / 2) + 1 : _length / 2
87
+ end
88
+ end
89
+
90
+ end
@@ -0,0 +1,75 @@
1
+ module ISO8583
2
+
3
+ # This file contains a number of preinstantiated Field definitions. You
4
+ # will probably need to create own fields in your implementation, please
5
+ # see Field and Codec for further discussion on how to do this.
6
+ # The fields currently available are those necessary to implement the
7
+ # BankAway spec.
8
+ #
9
+ # The following field types are available:
10
+ #
11
+ # [LLVAR_N] two byte variable length ASCII numeral, payload ASCII numerals
12
+ # [LLVAR_ANS] two byte variable length ASCII numeral, payload ASCII
13
+ # [ANS] fixed length letters, represented in ASCII
14
+ # [N] fixed lengh numerals, repesented in ASCII, padding right justified using zeros
15
+ # [B] binary data, padding left using nulls (0x00)
16
+ # [YYYYMMDDHH] Date, formatted as described in ASCII numerals
17
+ # [YYYYMMDDHH24MISS] Date, formatted as named in ASCII numerals
18
+
19
+ # Special form to de/encode variable length indicators, two bytes ASCII numerals
20
+ LL = Field.new
21
+ LL.name = "LL"
22
+ LL.length = 2
23
+ LL.codec = ASCII_Number
24
+ LL.padding = lambda {|value|
25
+ sprintf("%02d", value)
26
+ }
27
+
28
+ # Two byte variable length ASCII numeral, payload ASCII numerals
29
+ LLVAR_N = Field.new
30
+ LLVAR_N.length = LL
31
+ LLVAR_N.codec = ASCII_Number
32
+
33
+ # Two byte variable length alpha-numeric with special characters.
34
+ LLVAR_ANS = Field.new
35
+ LLVAR_ANS.length = LL
36
+ LLVAR_ANS.codec = ANS_Codec
37
+ LLVAR_ANS.padding = PADDING_LEFT_JUSTIFIED_SPACES
38
+
39
+ # Two byte variable length ASCII letters
40
+ # Fixed lengh numerals, repesented in ASCII, padding right justified using zeros
41
+ N = Field.new
42
+ N.codec = ASCII_Number
43
+ N.padding = lambda {|val, len|
44
+ sprintf("%0#{len}d", val)
45
+ }
46
+
47
+ PADDING_LEFT_JUSTIFIED_SPACES = lambda {|val, len|
48
+ sprintf "%-#{len}s", val
49
+ }
50
+
51
+ # Fixed length ASCII letters [A-Za-z]
52
+ ANS = Field.new
53
+ ANS.codec = ANS_Codec
54
+
55
+ # Binary data, padding left using nulls (0x00)
56
+ B = Field.new
57
+ B.codec = Null_Codec
58
+ B.padding = lambda {|val, len|
59
+ while val.length < len
60
+ val = val + "\000"
61
+ end
62
+ val
63
+ }
64
+
65
+ # Date, formatted as described in Bankaway
66
+ YYYYMMDDHH = Field.new
67
+ YYYYMMDDHH.codec = YYYYMMDDHHcodec
68
+ YYYYMMDDHH.length = 8
69
+
70
+ #Date, formatted as described in Bankaway
71
+ YYYYMMDDHH24MISS = Field.new
72
+ YYYYMMDDHH24MISS.codec = YYYYMMDDHH24MISScodec
73
+ YYYYMMDDHH24MISS.length = 14
74
+
75
+ end