Blob Blame History Raw
diff --git a/decoder.go b/decoder.go
index ed81ab0..89e46a1 100644
--- a/decoder.go
+++ b/decoder.go
@@ -15,27 +15,11 @@ import (
 	"io"
 )
 
-// DecoderOptions represents message decoder options
-type DecoderOptions struct {
-	// EnableWorkarounds, if set to true, enables various workarounds
-	// for decoding IPP messages that violate IPP protocol specification
-	//
-	// Currently it includes the following workarounds:
-	// * Pantum M7300FDW violates collection encoding rules.
-	//   Instead of using TagMemberName, it uses named attributes
-	//   within the collection
-	//
-	// The list of implemented workarounds may grow in the
-	// future
-	EnableWorkarounds bool
-}
-
-// messageDecoder represents Message decoder
+// Type messageDecoder represents Message decoder
 type messageDecoder struct {
-	in  io.Reader      // Input stream
-	off int            // Offset of last read
-	cnt int            // Count of read bytes
-	opt DecoderOptions // Options
+	in  io.Reader // Input stream
+	off int       // Offset of last read
+	cnt int       // Count of read bytes
 }
 
 // Decode the message
@@ -166,35 +150,9 @@ func (md *messageDecoder) decode(m *Message) error {
 }
 
 // Decode a Collection
-//
-// Collection is like a nested object - an attribute which value is a sequence
-// of named attributes. Collections can be nested.
-//
-// Wire format:
-//   ATTR: Tag = TagBeginCollection,            - the outer attribute that
-//         Name = "name", value - ignored         contains the collection
-//
-//   ATTR: Tag = TagMemberName, name = "",      - member name  \
-//         value - string, name of the next                     |
-//         member                                               | repeated for
-//                                                              | each member
-//   ATTR: Tag = any attribute tag, name = "",  - repeated for  |
-//         value = member value                   multi-value  /
-//                                                members
-//
-//   ATTR: Tag = TagEndCollection, name = "",
-//         value - ignored
-//
-// The format looks a bit baroque, but please note that it was added
-// in the IPP 2.0. For IPP 1.x collection looks like a single multi-value
-// TagBeginCollection attribute (attributes without names considered
-// next value for the previously defined named attributes) and so
-// 1.x parser silently ignores collections and doesn't get confused
-// with them.
 func (md *messageDecoder) decodeCollection() (Collection, error) {
 	collection := make(Collection, 0)
-
-	memberName := ""
+	//var name string
 
 	for {
 		tag, err := md.decodeTag()
@@ -208,10 +166,16 @@ func (md *messageDecoder) decodeCollection() (Collection, error) {
 			return nil, err
 		}
 
-		// Check for TagMemberName without the subsequent value attribute
-		if (tag == TagMemberName || tag == TagEndCollection) && memberName != "" {
-			err = fmt.Errorf("Collection: unexpected %s, expected value tag", tag)
-			return nil, err
+		// We are about to finish with current attribute (if any),
+		// either because we've got an end of collection, or a next
+		// attribute name. Check that we are leaving the current
+		// attribute in a consistent state (i.e., with at least one value)
+		if tag == TagMemberName || tag == TagEndCollection {
+			l := len(collection)
+			if l > 0 && len(collection[l-1].Values) == 0 {
+				err = fmt.Errorf("collection: unexpected %s, expected value tag", tag)
+				return nil, err
+			}
 		}
 
 		// Fetch next attribute
@@ -221,48 +185,36 @@ func (md *messageDecoder) decodeCollection() (Collection, error) {
 		}
 
 		// Process next attribute
-		switch tag {
-		case TagEndCollection:
+		switch {
+		case tag == TagEndCollection:
 			return collection, nil
 
-		case TagMemberName:
-			memberName = string(attr.Values[0].V.(String))
-			if memberName == "" {
-				err = fmt.Errorf("Collection: %s value is empty", tag)
-				return nil, err
-			}
+		case tag == TagMemberName:
+			attr.Name = string(attr.Values[0].V.(String))
+			attr.Values = nil
 
-		case TagBeginCollection:
-			// Decode nested collection
-			attr.Values[0].V, err = md.decodeCollection()
-			if err != nil {
+			if attr.Name == "" {
+				err = fmt.Errorf("collection: %s contains empty attribute name", tag)
 				return nil, err
 			}
-			fallthrough
+
+			collection = append(collection, attr)
+
+		case len(collection) == 0:
+			// We've got a value without preceding TagMemberName
+			err = fmt.Errorf("collection: unexpected %s, expected %s", tag, TagMemberName)
+			return nil, err
 
 		default:
-			if md.opt.EnableWorkarounds &&
-				memberName == "" && attr.Name != "" {
-				// Workaround for: Pantum M7300FDW
-				//
-				// This device violates collection encoding rules.
-				// Instead of using TagMemberName, it uses named
-				// attributes within the collection
-				memberName = attr.Name
+			if tag == TagBeginCollection {
+				attr.Values[0].V, err = md.decodeCollection()
+				if err != nil {
+					return nil, err
+				}
 			}
 
-			if memberName != "" {
-				attr.Name = memberName
-				collection = append(collection, attr)
-				memberName = ""
-			} else if len(collection) > 0 {
-				l := len(collection)
-				collection[l-1].Values.Add(tag, attr.Values[0].V)
-			} else {
-				// We've got a value without preceding TagMemberName
-				err = fmt.Errorf("Collection: unexpected %s, expected %s", tag, TagMemberName)
-				return nil, err
-			}
+			l := len(collection)
+			collection[l-1].Values.Add(tag, attr.Values[0].V)
 		}
 	}
 }
@@ -270,7 +222,6 @@ func (md *messageDecoder) decodeCollection() (Collection, error) {
 // Decode a tag
 func (md *messageDecoder) decodeTag() (Tag, error) {
 	t, err := md.decodeU8()
-
 	return Tag(t), err
 }
 
@@ -287,14 +238,6 @@ func (md *messageDecoder) decodeCode() (Code, error) {
 }
 
 // Decode a single attribute
-//
-// Wire format:
-//   1   byte:   Tag
-//   2+N bytes:  Name length (2 bytes) + name string
-//   2+N bytes:  Value length (2 bytes) + value bytes
-//
-// For the extended tag format, Tag is encoded as TagExtension and
-// 4 bytes of the actual tag value prepended to the value bytes
 func (md *messageDecoder) decodeAttribute(tag Tag) (Attribute, error) {
 	var attr Attribute
 	var value []byte
diff --git a/goipp_test.go b/goipp_test.go
index 89a4e91..06800e8 100644
--- a/goipp_test.go
+++ b/goipp_test.go
@@ -562,7 +562,7 @@ func TestDecodeErrors(t *testing.T) {
 		assertErrorIs(t, err, "Message truncated at")
 	}
 
-	d = goodMessage1
+	d = good_message_1
 	for i := 0; i < len(d); i++ {
 		err = m.DecodeBytes(d[:i])
 		assertErrorIs(t, err, "Message truncated at")
@@ -678,7 +678,7 @@ func TestDecodeErrors(t *testing.T) {
 
 	d = append(hdr, body...)
 	err = m.DecodeBytes(d)
-	assertErrorIs(t, err, "Collection: unexpected endCollection, expected value tag")
+	assertErrorIs(t, err, "collection: unexpected endCollection, expected value tag at 0x23")
 
 	// Collection: unexpected memberAttrName, expected value tag
 	body = []byte{
@@ -713,7 +713,7 @@ func TestDecodeErrors(t *testing.T) {
 
 	d = append(hdr, body...)
 	err = m.DecodeBytes(d)
-	assertErrorIs(t, err, "Collection: unexpected memberAttrName, expected value tag")
+	assertErrorIs(t, err, "collection: unexpected memberAttrName, expected value tag at 0x24")
 
 	// Collection: memberAttrName value is empty
 	body = []byte{
@@ -742,7 +742,7 @@ func TestDecodeErrors(t *testing.T) {
 
 	d = append(hdr, body...)
 	err = m.DecodeBytes(d)
-	assertErrorIs(t, err, "Collection: memberAttrName value is empty")
+	assertErrorIs(t, err, "collection: memberAttrName contains empty attribute name at 0x1d")
 
 	// Collection: unexpected integer, expected memberAttrName
 	body = []byte{
@@ -772,7 +772,7 @@ func TestDecodeErrors(t *testing.T) {
 
 	d = append(hdr, body...)
 	err = m.DecodeBytes(d)
-	assertErrorIs(t, err, "Collection: unexpected integer, expected memberAttrName")
+	assertErrorIs(t, err, "collection: unexpected integer, expected memberAttrName at 0x1d")
 }
 
 // Test errors in decoding values
@@ -1066,11 +1066,9 @@ func TestTagExtension(t *testing.T) {
 }
 
 // Test message decoding
-func testDecode(t *testing.T, data []byte, opt DecoderOptions,
-	mustFail, mustEncode bool) {
-
+func testDecode(t *testing.T, data []byte, mustFail bool) {
 	var m Message
-	err := m.DecodeEx(bytes.NewBuffer(data), opt)
+	err := m.Decode(bytes.NewBuffer(data))
 
 	if mustFail {
 		assertWithError(t, err)
@@ -1082,19 +1080,15 @@ func testDecode(t *testing.T, data []byte, opt DecoderOptions,
 		return
 	}
 
-	//m.Print(os.Stdout, true)
-
 	if !m.Equal(m) {
 		t.Errorf("Message is not equal to itself")
 	}
 
-	if mustEncode {
-		buf, err := m.EncodeBytes()
-		assertNoError(t, err)
+	buf, err := m.EncodeBytes()
+	assertNoError(t, err)
 
-		if !bytes.Equal(buf, data) {
-			t.Errorf("Message is not the same after decoding and encoding")
-		}
+	if !bytes.Equal(buf, data) {
+		t.Errorf("Message is not the same after decoding and encoding")
 	}
 
 	// We can't test a lot of (*Message) Print(), so lets test
@@ -1103,34 +1097,24 @@ func testDecode(t *testing.T, data []byte, opt DecoderOptions,
 }
 
 func TestDecodeGoodMessage1(t *testing.T) {
-	testDecode(t, goodMessage1, DecoderOptions{}, false, true)
+	testDecode(t, good_message_1, false)
 }
 
 func TestDecodeGoodMessage2(t *testing.T) {
-	testDecode(t, goodMessage2, DecoderOptions{}, false, true)
+	testDecode(t, good_message_2, false)
 }
 
 func TestDecodeBadMessage1(t *testing.T) {
-	testDecode(t, badMessage1, DecoderOptions{}, true, false)
-	testDecode(t, badMessage1,
-		DecoderOptions{EnableWorkarounds: true}, false, false)
-}
-
-func TestDecodeHPOfficeJetPro8730(t *testing.T) {
-	testDecode(t, attrsHPOfficeJetPro8730, DecoderOptions{}, false, true)
+	testDecode(t, bad_message_1, true)
 }
 
-func TestDecodePantumM7300FDW(t *testing.T) {
-	testDecode(t, attrsPantumM7300FDW,
-		DecoderOptions{EnableWorkarounds: false}, true, false)
-
-	testDecode(t, attrsPantumM7300FDW,
-		DecoderOptions{EnableWorkarounds: true}, false, false)
+func TestDecodeBigMessage(t *testing.T) {
+	testDecode(t, big_message, false)
 }
 
 // ------------------------ Test Data ------------------------
 // The good message - 1
-var goodMessage1 = []byte{
+var good_message_1 = []byte{
 	0x01, 0x01, // IPP version
 	0x00, 0x02, // Print-Job operation
 	0x00, 0x00, 0x00, 0x01, // Request ID
@@ -1289,7 +1273,7 @@ var goodMessage1 = []byte{
 }
 
 // The good message - 2
-var goodMessage2 = []byte{
+var good_message_2 = []byte{
 	0x01, 0x01, // IPP version
 	0x00, 0x02, // Print-Job operation
 	0x00, 0x00, 0x00, 0x01, // Request ID
@@ -1314,12 +1298,7 @@ var goodMessage2 = []byte{
 }
 
 // The bad message - 1
-//
-// This message violates IPP encoding rules: instead of
-// using TagMemberName it uses named attributes
-//
-// It must not decode normally, but must decode with workarounds
-var badMessage1 = []byte{
+var bad_message_1 = []byte{
 	0x01, 0x01, // IPP version */
 	0x00, 0x02, // Print-Job operation */
 	0x00, 0x00, 0x00, 0x01, // Request ID */
@@ -1387,7 +1366,7 @@ var badMessage1 = []byte{
 
 // The big real example, Get-Printer-Attributes output
 // from the HP OfficeJet Pro 8730
-var attrsHPOfficeJetPro8730 = []byte{
+var big_message = []byte{
 	0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x47, 0x00, 0x12, 0x61, 0x74, 0x74, 0x72,
 	0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x00, 0x05,
 	0x75, 0x74, 0x66, 0x2d, 0x38, 0x48, 0x00, 0x1b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
@@ -2355,133 +2334,3 @@ var attrsHPOfficeJetPro8730 = []byte{
 	0x69, 0x70, 0x6c, 0x65, 0x2d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x6a, 0x6f,
 	0x62, 0x73, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x00, 0x01, 0x00, 0x03,
 }
-
-// Get-Printer-Attributes output from Pantum M7300FDW
-var attrsPantumM7300FDW = []byte{
-	0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x47, 0x00, 0x12,
-	0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2d, 0x63,
-	0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x00, 0x05, 0x75, 0x74, 0x66, 0x2d,
-	0x38, 0x48, 0x00, 0x1b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
-	0x65, 0x73, 0x2d, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x61, 0x6c, 0x2d, 0x6c,
-	0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, 0x05, 0x65, 0x6e, 0x2d,
-	0x55, 0x53, 0x04, 0x22, 0x00, 0x0f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x2d,
-	0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x00, 0x01, 0x00,
-	0x49, 0x00, 0x19, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2d,
-	0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f,
-	0x72, 0x74, 0x65, 0x64, 0x00, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f,
-	0x75, 0x72, 0x66, 0x49, 0x00, 0x00, 0x00, 0x10, 0x69, 0x6d, 0x61, 0x67,
-	0x65, 0x2f, 0x70, 0x77, 0x67, 0x2d, 0x72, 0x61, 0x73, 0x74, 0x65, 0x72,
-	0x49, 0x00, 0x00, 0x00, 0x18, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
-	0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73,
-	0x74, 0x72, 0x65, 0x61, 0x6d, 0x41, 0x00, 0x10, 0x6d, 0x6f, 0x70, 0x72,
-	0x69, 0x61, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64,
-	0x00, 0x03, 0x31, 0x2e, 0x33, 0x41, 0x00, 0x10, 0x70, 0x72, 0x69, 0x6e,
-	0x74, 0x65, 0x72, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
-	0x00, 0x0e, 0x70, 0x61, 0x6e, 0x74, 0x75, 0x6d, 0x20, 0x70, 0x72, 0x69,
-	0x6e, 0x74, 0x65, 0x72, 0x41, 0x00, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x74,
-	0x65, 0x72, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x12, 0x50, 0x61, 0x6e,
-	0x74, 0x75, 0x6d, 0x20, 0x49, 0x50, 0x50, 0x20, 0x70, 0x72, 0x69, 0x6e,
-	0x74, 0x65, 0x72, 0x45, 0x00, 0x11, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65,
-	0x72, 0x2d, 0x6d, 0x6f, 0x72, 0x65, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x00,
-	0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61,
-	0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a, 0x36, 0x30, 0x30, 0x30, 0x30, 0x2f,
-	0x69, 0x6e, 0x64, 0x65, 0x78, 0x2d, 0x6a, 0x75, 0x6d, 0x70, 0x2e, 0x68,
-	0x74, 0x6d, 0x6c, 0x41, 0x00, 0x16, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65,
-	0x72, 0x2d, 0x6d, 0x61, 0x6b, 0x65, 0x2d, 0x61, 0x6e, 0x64, 0x2d, 0x6d,
-	0x6f, 0x64, 0x65, 0x6c, 0x00, 0x16, 0x50, 0x61, 0x6e, 0x74, 0x75, 0x6d,
-	0x20, 0x4d, 0x37, 0x33, 0x30, 0x30, 0x46, 0x44, 0x57, 0x20, 0x53, 0x65,
-	0x72, 0x69, 0x65, 0x73, 0x41, 0x00, 0x11, 0x70, 0x72, 0x69, 0x6e, 0x74,
-	0x65, 0x72, 0x2d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x69, 0x64,
-	0x00, 0x45, 0x4d, 0x46, 0x47, 0x3a, 0x50, 0x61, 0x6e, 0x74, 0x75, 0x6d,
-	0x3b, 0x43, 0x4d, 0x44, 0x3a, 0x3a, 0x44, 0x57, 0x2d, 0x50, 0x53, 0x2c,
-	0x44, 0x57, 0x2d, 0x50, 0x43, 0x4c, 0x2c, 0x55, 0x52, 0x46, 0x3b, 0x4d,
-	0x44, 0x4c, 0x3a, 0x2d, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x3b,
-	0x43, 0x4c, 0x53, 0x3a, 0x50, 0x52, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x3b,
-	0x44, 0x45, 0x53, 0x3a, 0x50, 0x61, 0x6e, 0x74, 0x75, 0x6d, 0x3b, 0x45,
-	0x00, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x75, 0x75,
-	0x69, 0x64, 0x00, 0x2d, 0x75, 0x72, 0x6e, 0x3a, 0x75, 0x75, 0x69, 0x64,
-	0x3a, 0x30, 0x37, 0x62, 0x63, 0x35, 0x61, 0x34, 0x37, 0x2d, 0x65, 0x64,
-	0x66, 0x32, 0x2d, 0x34, 0x36, 0x36, 0x31, 0x2d, 0x38, 0x37, 0x34, 0x38,
-	0x2d, 0x38, 0x36, 0x32, 0x30, 0x66, 0x37, 0x39, 0x64, 0x34, 0x61, 0x63,
-	0x34, 0x45, 0x00, 0x0d, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d,
-	0x69, 0x63, 0x6f, 0x6e, 0x73, 0x00, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a,
-	0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a,
-	0x36, 0x30, 0x30, 0x30, 0x30, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x68,
-	0x69, 0x70, 0x34, 0x38, 0x2e, 0x70, 0x6e, 0x67, 0x45, 0x00, 0x00, 0x00,
-	0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61,
-	0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a, 0x36, 0x30, 0x30, 0x30, 0x30, 0x2f,
-	0x66, 0x6c, 0x61, 0x67, 0x73, 0x68, 0x69, 0x70, 0x31, 0x32, 0x38, 0x2e,
-	0x70, 0x6e, 0x67, 0x45, 0x00, 0x00, 0x00, 0x26, 0x68, 0x74, 0x74, 0x70,
-	0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
-	0x3a, 0x36, 0x30, 0x30, 0x30, 0x30, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73,
-	0x68, 0x69, 0x70, 0x35, 0x31, 0x32, 0x2e, 0x70, 0x6e, 0x67, 0x42, 0x00,
-	0x13, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x64, 0x6e, 0x73,
-	0x2d, 0x73, 0x64, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x1d, 0x50, 0x61,
-	0x6e, 0x74, 0x75, 0x6d, 0x20, 0x4d, 0x37, 0x33, 0x30, 0x30, 0x46, 0x44,
-	0x57, 0x20, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x20, 0x31, 0x43, 0x36,
-	0x46, 0x43, 0x44, 0x44, 0x00, 0x0d, 0x75, 0x72, 0x66, 0x2d, 0x73, 0x75,
-	0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x00, 0x04, 0x56, 0x31, 0x2e,
-	0x34, 0x44, 0x00, 0x00, 0x00, 0x02, 0x57, 0x38, 0x44, 0x00, 0x00, 0x00,
-	0x03, 0x49, 0x53, 0x31, 0x44, 0x00, 0x00, 0x00, 0x04, 0x43, 0x50, 0x39,
-	0x39, 0x44, 0x00, 0x00, 0x00, 0x03, 0x50, 0x51, 0x34, 0x44, 0x00, 0x00,
-	0x00, 0x04, 0x4f, 0x42, 0x31, 0x30, 0x44, 0x00, 0x00, 0x00, 0x05, 0x52,
-	0x53, 0x36, 0x30, 0x30, 0x44, 0x00, 0x00, 0x00, 0x03, 0x44, 0x4d, 0x31,
-	0x44, 0x00, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x6b,
-	0x69, 0x6e, 0x64, 0x00, 0x08, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e,
-	0x74, 0x44, 0x00, 0x00, 0x00, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f,
-	0x70, 0x65, 0x34, 0x00, 0x14, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2d, 0x73,
-	0x69, 0x7a, 0x65, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65,
-	0x64, 0x00, 0x00, 0x21, 0x00, 0x0b, 0x78, 0x2d, 0x64, 0x69, 0x6d, 0x65,
-	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x54, 0x56, 0x21,
-	0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x00, 0x04, 0x00, 0x00, 0x6d, 0x24, 0x37, 0x00, 0x00, 0x00, 0x00,
-	0x34, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0b, 0x78, 0x2d, 0x64, 0x69,
-	0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x52,
-	0x08, 0x21, 0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x74, 0x04, 0x37, 0x00, 0x00,
-	0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0b, 0x78, 0x2d,
-	0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00,
-	0x00, 0x39, 0xd0, 0x21, 0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69, 0x6d, 0x65,
-	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x52, 0x08, 0x37,
-	0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0b,
-	0x78, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00,
-	0x04, 0x00, 0x00, 0x29, 0x04, 0x21, 0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69,
-	0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x39,
-	0xd0, 0x37, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x21,
-	0x00, 0x0b, 0x78, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x00, 0x04, 0x00, 0x00, 0x2c, 0x88, 0x21, 0x00, 0x0b, 0x79, 0x2d,
-	0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00,
-	0x00, 0x3f, 0x48, 0x37, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
-	0x00, 0x21, 0x00, 0x0b, 0x78, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x2a, 0xf8, 0x21, 0x00, 0x0b,
-	0x79, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00,
-	0x04, 0x00, 0x00, 0x55, 0xf0, 0x37, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00,
-	0x00, 0x00, 0x00, 0x21, 0x00, 0x0b, 0x78, 0x2d, 0x64, 0x69, 0x6d, 0x65,
-	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x27, 0x10, 0x21,
-	0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x00, 0x04, 0x00, 0x00, 0x39, 0xd0, 0x37, 0x00, 0x00, 0x00, 0x00,
-	0x34, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0b, 0x78, 0x2d, 0x64, 0x69,
-	0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x2e,
-	0xe0, 0x21, 0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73,
-	0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x5b, 0xcc, 0x37, 0x00, 0x00,
-	0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0b, 0x78, 0x2d,
-	0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00,
-	0x00, 0x28, 0xed, 0x21, 0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69, 0x6d, 0x65,
-	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x5e, 0x42, 0x37,
-	0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0b,
-	0x78, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00,
-	0x04, 0x00, 0x00, 0x54, 0x56, 0x21, 0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69,
-	0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x04, 0x00, 0x00, 0x8a,
-	0xe8, 0x37, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x33,
-	0x00, 0x0b, 0x78, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x00, 0x08, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x39, 0xd0, 0x33,
-	0x00, 0x0b, 0x79, 0x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x00, 0x08, 0x00, 0x00, 0x54, 0x60, 0x00, 0x00, 0x8b, 0x10, 0x37,
-	0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x0f, 0x73, 0x69, 0x64, 0x65, 0x73,
-	0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x00, 0x09,
-	0x6f, 0x6e, 0x65, 0x2d, 0x73, 0x69, 0x64, 0x65, 0x64, 0x44, 0x00, 0x00,
-	0x00, 0x14, 0x74, 0x77, 0x6f, 0x2d, 0x73, 0x69, 0x64, 0x65, 0x64, 0x2d,
-	0x73, 0x68, 0x6f, 0x72, 0x74, 0x2d, 0x65, 0x64, 0x67, 0x65, 0x44, 0x00,
-	0x00, 0x00, 0x13, 0x74, 0x77, 0x6f, 0x2d, 0x73, 0x69, 0x64, 0x65, 0x64,
-	0x2d, 0x6c, 0x6f, 0x6e, 0x67, 0x2d, 0x65, 0x64, 0x67, 0x65, 0x03,
-}
diff --git a/message.go b/message.go
index 4a7229a..7a4d2db 100644
--- a/message.go
+++ b/message.go
@@ -157,19 +157,10 @@ func (m *Message) EncodeBytes() ([]byte, error) {
 	return buf.Bytes(), err
 }
 
-// Decode reads message from io.Reader
+// Decode message
 func (m *Message) Decode(in io.Reader) error {
-	return m.DecodeEx(in, DecoderOptions{})
-}
-
-// DecodeEx reads message from io.Reader
-//
-// It is extended version of the Decode method, with additional
-// DecoderOptions parameter
-func (m *Message) DecodeEx(in io.Reader, opt DecoderOptions) error {
 	md := messageDecoder{
-		in:  in,
-		opt: opt,
+		in: in,
 	}
 
 	m.Reset()
@@ -181,14 +172,6 @@ func (m *Message) DecodeBytes(data []byte) error {
 	return m.Decode(bytes.NewBuffer(data))
 }
 
-// DecodeBytesEx decodes message from byte slice
-//
-// It is extended version of the DecodeBytes method, with additional
-// DecoderOptions parameter
-func (m *Message) DecodeBytesEx(data []byte, opt DecoderOptions) error {
-	return m.DecodeEx(bytes.NewBuffer(data), opt)
-}
-
 // Print pretty-prints the message. The 'request' parameter affects
 // interpretation of Message.Code: it is interpreted either
 // as Op or as Status