VOL-4337: Code upgrade for 3/2020 G.988 support and remaining Extended Message Set support

Change-Id: I6c5e1a167216ad9b51e9da89460e9909465ae1bc
diff --git a/generated/attribute.go b/generated/attribute.go
index 58bd6cf..de20130 100644
--- a/generated/attribute.go
+++ b/generated/attribute.go
@@ -52,7 +52,7 @@
 	CounterAttributeType                              // Incrementing counter
 )
 
-// AttributeDefinitionMap is a map of attribute definitions with the attribute index (0..15)
+// AttributeDefinitionMap is a map of attribute definitions with the attribute index (0..16)
 // as the key
 type AttributeDefinitionMap map[uint]AttributeDefinition
 
@@ -72,6 +72,12 @@
 	Deprecated    bool // If true, attribute is deprecated
 }
 
+// TableRows is used by the SetTable request/response
+type TableRows struct {
+	NumRows int    // Number of rows of 'AttributeDefinition.Size' length
+	Rows    []byte // 0..NumRows rows of attribute data of size 'AttributeDefinition.Size'
+}
+
 func (attr *AttributeDefinition) String() string {
 	return fmt.Sprintf("AttributeDefinition: %v (%v/%v): Size: %v, Default: %v, Access: %v",
 		attr.GetName(), attr.AttributeType, attr.GetIndex(), attr.GetSize(), attr.GetDefault(), attr.GetAccess())
@@ -80,7 +86,7 @@
 // GetName returns the attribute's name
 func (attr AttributeDefinition) GetName() string { return attr.Name }
 
-// GetIndex returns the attribute index )0..15)
+// GetIndex returns the attribute index )0..16)
 func (attr AttributeDefinition) GetIndex() uint { return attr.Index }
 
 // GetDefault provides the default value for an attribute if not specified
@@ -392,14 +398,32 @@
 		if size != 0 && len(data) < attr.GetSize() {
 			df.SetTruncated()
 			return nil, NewMessageTruncatedError("packet too small for field")
-		} else if size == 0 {
+		}
+		if size == 0 {
 			return nil, NewProcessingError("table attributes with no size are not supported: %v", attr.Name)
 		}
 		return data, nil
 
 	case byte(SetTable) | AR: // Set Table Request
-		// TODO: Only baseline supported at this time
-		return nil, errors.New("attribute encode for set-table-request not yet supported")
+		// SetTableRequestType will be composed of zero or more row of a fixed size (based on ME)
+		// and will be saved to a TableRow struct for the consumer's use
+		size := attr.GetSize()
+		if size == 0 {
+			return nil, NewProcessingError("table attributes with no size are not supported: %v", attr.Name)
+		}
+		if len(data)%size != 0 {
+			df.SetTruncated()
+			return nil, NewMessageTruncatedError("packet does not contain an integral number of rows")
+		}
+		if len(data) == 0 {
+			return TableRows{}, nil
+		}
+		rows := TableRows{
+			NumRows: len(data) / size,
+			Rows:    make([]byte, len(data)),
+		}
+		copy(rows.Rows, data)
+		return rows, nil
 	}
 }
 
@@ -449,8 +473,22 @@
 		break
 
 	case byte(SetTable) | AR: // Set Table Request
-		// TODO: Only baseline supported at this time
-		return 0, errors.New("attribute encode for set-table-request not yet supported")
+		if rows, ok := value.(TableRows); ok {
+			size := attr.GetSize()
+			if size != 0 && len(rows.Rows)%size != 0 {
+				return 0, NewMessageTruncatedError("packet does not contain an integral number of rows")
+			}
+			if bytesAvailable < len(rows.Rows) {
+				return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
+			}
+			bytes, err := b.AppendBytes(len(rows.Rows))
+			if err != nil {
+				return 0, err
+			}
+			copy(bytes, rows.Rows)
+			return len(rows.Rows), nil
+		}
+		return 0, errors.New("unexpected type for table serialization")
 	}
 	size := attr.GetSize()
 	if bytesAvailable < size {
@@ -774,3 +812,25 @@
 	}
 	return err
 }
+
+// AttributeValueMapBufferSize will determine how much space is needed to encode all
+// of the attributes
+func AttributeValueMapBufferSize(classID ClassID, attributes AttributeValueMap, msgType uint8) (int, error) {
+	attrDefs, err := GetAttributesDefinitions(classID)
+	if err.StatusCode() != Success {
+		return 0, err
+	} else if attributes == nil {
+		return 0, NewProcessingError("Invalid (nil) Attribute Value Map referenced")
+	}
+	bufferSize := 0
+	isGetResponse := msgType == 0x29
+
+	for _, attrDef := range attrDefs {
+		if isGetResponse && attrDef.IsTableAttribute() {
+			bufferSize += 4
+		} else {
+			bufferSize += attrDef.GetSize()
+		}
+	}
+	return bufferSize, nil
+}