package ndrimport ()// intFromTag returns an int that is a value in a struct tag key/value pairfunc intFromTag( reflect.StructTag, string) (int, error) { := parseTags() := 1if , := .Map[]; { , := strconv.Atoi()if != nil {return , fmt.Errorf("invalid dimensions tag [%s]: %v", , ) } = }return , nil}// parseDimensions returns the a slice of the size of each dimension and type of the member at the deepest level.func parseDimensions( reflect.Value) ( []int, reflect.Type) {if .Kind() == reflect.Ptr { = .Elem() } := .Type()if .Kind() == reflect.Ptr { = .Elem() }if .Kind() != reflect.Array && .Kind() != reflect.Slice {return } = append(, .Len())if .Elem().Kind() == reflect.Array || .Elem().Kind() == reflect.Slice {// contains array or slicevar []int , = (.Index(0)) = append(, ...) } else { = .Elem() }return}// sliceDimensions returns the count of dimensions a slice has.func sliceDimensions( reflect.Type) ( int, reflect.Type) {if .Kind() == reflect.Ptr { = .Elem() }if .Kind() == reflect.Slice { ++varint , = (.Elem()) += } else { = }return}// makeSubSlices is a deep recursive creation/initialisation of multi-dimensional slices.// Takes the reflect.Value of the 1st dimension and a slice of the lengths of the sub dimensionsfunc makeSubSlices( reflect.Value, []int) { := .Type().Elem()if .Kind() != reflect.Slice {return }for := 0; < .Len(); ++ { := reflect.MakeSlice(, [0], [0]) .Index().Set()// Are there more sub dimensions?iflen() > 1 { (.Index(), [1:]) } }return}// multiDimensionalIndexPermutations returns all the permutations of the indexes of a multi-dimensional slice.// The input is a slice of integers that indicates the max size/length of each dimensionfunc multiDimensionalIndexPermutations( []int) ( [][]int) { := make([]int, len(), len()) // The zeros permutation = append(, )// for each dimension, in reversefor := len() - 1; >= 0; -- { := make([][]int, len())copy(, )//create a permutation for each of the iterations of the current dimensionfor := 1; <= []-1; ++ {// For each existing permutationfor , := range { := make([]int, len(), len())copy(, ) [] = = append(, ) } } }return}// precedingMax reads off the next conformant max valuefunc ( *Decoder) () uint32 { := .conformantMax[0] .conformantMax = .conformantMax[1:]return}// fillFixedArray establishes if the fixed array is uni or multi dimensional and then fills it.func ( *Decoder) ( reflect.Value, reflect.StructTag, *[]deferedPtr) error { , := parseDimensions()if .Kind() == reflect.String { = reflect.StructTag(subStringArrayTag) }iflen() < 1 {returnerrors.New("could not establish dimensions of fixed array") }iflen() == 1 { := .fillUniDimensionalFixedArray(, , )if != nil {returnfmt.Errorf("could not fill uni-dimensional fixed array: %v", ) }returnnil }// Fixed array is multidimensional := multiDimensionalIndexPermutations([:len()-1])for , := range {// Get current multi-dimensional index to fill := for , := range { = .Index() }// fill with the last dimension array := .fillUniDimensionalFixedArray(, , )if != nil {returnfmt.Errorf("could not fill dimension %v of multi-dimensional fixed array: %v", , ) } }returnnil}// readUniDimensionalFixedArray reads an array (not slice) from the byte stream.func ( *Decoder) ( reflect.Value, reflect.StructTag, *[]deferedPtr) error {for := 0; < .Len(); ++ { := .fill(.Index(), , )if != nil {returnfmt.Errorf("could not fill index %d of fixed array: %v", , ) } }returnnil}// fillConformantArray establishes if the conformant array is uni or multi dimensional and then fills the slice.func ( *Decoder) ( reflect.Value, reflect.StructTag, *[]deferedPtr) error { , := sliceDimensions(.Type())if > 1 { := .fillMultiDimensionalConformantArray(, , , )if != nil {return } } else { := .fillUniDimensionalConformantArray(, , )if != nil {return } }returnnil}// fillUniDimensionalConformantArray fills the uni-dimensional slice value.func ( *Decoder) ( reflect.Value, reflect.StructTag, *[]deferedPtr) error { := .precedingMax() := int() := reflect.MakeSlice(.Type(), , )for := 0; < ; ++ { := .fill(.Index(), , )if != nil {returnfmt.Errorf("could not fill index %d of uni-dimensional conformant array: %v", , ) } } .Set()returnnil}// fillMultiDimensionalConformantArray fills the multi-dimensional slice value provided from conformant array data.// The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this// method not to panic.func ( *Decoder) ( reflect.Value, int, reflect.StructTag, *[]deferedPtr) error {// Read the max size of each dimensions from the ndr stream := make([]int, , )for := range { [] = int(.precedingMax()) }// Initialise size of slices // Initialise the size of the 1st dimension := .Type() .Set(reflect.MakeSlice(, [0], [0]))// Initialise the size of the other dimensions recursivelymakeSubSlices(, [1:])// Get all permutations of the indexes and go through each and fill := multiDimensionalIndexPermutations()for , := range {// Get current multi-dimensional index to fill := for , := range { = .Index() } := .fill(, , )if != nil {returnfmt.Errorf("could not fill index %v of slice: %v", , ) } }returnnil}// fillVaryingArray establishes if the varying array is uni or multi dimensional and then fills the slice.func ( *Decoder) ( reflect.Value, reflect.StructTag, *[]deferedPtr) error { , := sliceDimensions(.Type())if > 1 { := .fillMultiDimensionalVaryingArray(, , , , )if != nil {return } } else { := .fillUniDimensionalVaryingArray(, , )if != nil {return } }returnnil}// fillUniDimensionalVaryingArray fills the uni-dimensional slice value.func ( *Decoder) ( reflect.Value, reflect.StructTag, *[]deferedPtr) error { , := .readUint32()if != nil {returnfmt.Errorf("could not read offset of uni-dimensional varying array: %v", ) } , := .readUint32()if != nil {returnfmt.Errorf("could not establish actual count of uni-dimensional varying array: %v", ) } := .Type()// Total size of the array is the offset in the index being passed plus the actual count of elements being passed. := int( + ) := reflect.MakeSlice(, , )// Populate the array starting at the offset specifiedfor := int(); < ; ++ { := .fill(.Index(), , )if != nil {returnfmt.Errorf("could not fill index %d of uni-dimensional varying array: %v", , ) } } .Set()returnnil}// fillMultiDimensionalVaryingArray fills the multi-dimensional slice value provided from varying array data.// The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this// method not to panic.func ( *Decoder) ( reflect.Value, reflect.Type, int, reflect.StructTag, *[]deferedPtr) error {// Read the offset and actual count of each dimensions from the ndr stream := make([]int, , ) := make([]int, , )for := range { , := .readUint32()if != nil {returnfmt.Errorf("could not read offset of dimension %d: %v", +1, ) } [] = int() , := .readUint32()if != nil {returnfmt.Errorf("could not read size of dimension %d: %v", +1, ) } [] = int() + int() }// Initialise size of slices // Initialise the size of the 1st dimension := .Type() .Set(reflect.MakeSlice(, [0], [0]))// Initialise the size of the other dimensions recursivelymakeSubSlices(, [1:])// Get all permutations of the indexes and go through each and fill := multiDimensionalIndexPermutations()for , := range {// Get current multi-dimensional index to fill := varbool// should this permutation be skipped due to the offset of any of the dimensions?for , := range {if < [] { = truebreak } = .Index() }if {// This permutation should be skipped as it is less than the offset for one of the dimensions.continue } := .fill(, , )if != nil {returnfmt.Errorf("could not fill index %v of slice: %v", , ) } }returnnil}// fillConformantVaryingArray establishes if the varying array is uni or multi dimensional and then fills the slice.func ( *Decoder) ( reflect.Value, reflect.StructTag, *[]deferedPtr) error { , := sliceDimensions(.Type())if > 1 { := .fillMultiDimensionalConformantVaryingArray(, , , , )if != nil {return } } else { := .fillUniDimensionalConformantVaryingArray(, , )if != nil {return } }returnnil}// fillUniDimensionalConformantVaryingArray fills the uni-dimensional slice value.func ( *Decoder) ( reflect.Value, reflect.StructTag, *[]deferedPtr) error { := .precedingMax() , := .readUint32()if != nil {returnfmt.Errorf("could not read offset of uni-dimensional conformant varying array: %v", ) } , := .readUint32()if != nil {returnfmt.Errorf("could not establish actual count of uni-dimensional conformant varying array: %v", ) }if < + {returnerrors.New("max count is less than the offset plus actual count") } := .Type() := int() := reflect.MakeSlice(, , )for := int(); < ; ++ { := .fill(.Index(), , )if != nil {returnfmt.Errorf("could not fill index %d of uni-dimensional conformant varying array: %v", , ) } } .Set()returnnil}// fillMultiDimensionalConformantVaryingArray fills the multi-dimensional slice value provided from conformant varying array data.// The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this// method not to panic.func ( *Decoder) ( reflect.Value, reflect.Type, int, reflect.StructTag, *[]deferedPtr) error {// Read the offset and actual count of each dimensions from the ndr stream := make([]int, , )for := range { [] = int(.precedingMax()) } := make([]int, , ) := make([]int, , )for := range { , := .readUint32()if != nil {returnfmt.Errorf("could not read offset of dimension %d: %v", +1, ) } [] = int() , := .readUint32()if != nil {returnfmt.Errorf("could not read actual count of dimension %d: %v", +1, ) }if [] < int()+int() { [] = int() + int() } [] = int() }// Initialise size of slices // Initialise the size of the 1st dimension := .Type() .Set(reflect.MakeSlice(, [0], [0]))// Initialise the size of the other dimensions recursivelymakeSubSlices(, [1:])// Get all permutations of the indexes and go through each and fill := multiDimensionalIndexPermutations()for , := range {// Get current multi-dimensional index to fill := varbool// should this permutation be skipped due to the offset of any of the dimensions or max is higher than the actual count being passedfor , := range {if < [] || >= [] { = truebreak } = .Index() }if {// This permutation should be skipped as it is less than the offset for one of the dimensions.continue } := .fill(, , )if != nil {returnfmt.Errorf("could not fill index %v of slice: %v", , ) } }returnnil}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.