arrays.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. package ndr
  2. import (
  3. "errors"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. )
  8. // intFromTag returns an int that is a value in a struct tag key/value pair
  9. func intFromTag(tag reflect.StructTag, key string) (int, error) {
  10. ndrTag := parseTags(tag)
  11. d := 1
  12. if n, ok := ndrTag.Map[key]; ok {
  13. i, err := strconv.Atoi(n)
  14. if err != nil {
  15. return d, fmt.Errorf("invalid dimensions tag [%s]: %v", n, err)
  16. }
  17. d = i
  18. }
  19. return d, nil
  20. }
  21. // parseDimensions returns the a slice of the size of each dimension and type of the member at the deepest level.
  22. func parseDimensions(v reflect.Value) (l []int, tb reflect.Type) {
  23. if v.Kind() == reflect.Ptr {
  24. v = v.Elem()
  25. }
  26. t := v.Type()
  27. if t.Kind() == reflect.Ptr {
  28. t = t.Elem()
  29. }
  30. if t.Kind() != reflect.Array && t.Kind() != reflect.Slice {
  31. return
  32. }
  33. l = append(l, v.Len())
  34. if t.Elem().Kind() == reflect.Array || t.Elem().Kind() == reflect.Slice {
  35. // contains array or slice
  36. var m []int
  37. m, tb = parseDimensions(v.Index(0))
  38. l = append(l, m...)
  39. } else {
  40. tb = t.Elem()
  41. }
  42. return
  43. }
  44. // sliceDimensions returns the count of dimensions a slice has.
  45. func sliceDimensions(t reflect.Type) (d int, tb reflect.Type) {
  46. if t.Kind() == reflect.Ptr {
  47. t = t.Elem()
  48. }
  49. if t.Kind() == reflect.Slice {
  50. d++
  51. var n int
  52. n, tb = sliceDimensions(t.Elem())
  53. d += n
  54. } else {
  55. tb = t
  56. }
  57. return
  58. }
  59. // makeSubSlices is a deep recursive creation/initialisation of multi-dimensional slices.
  60. // Takes the reflect.Value of the 1st dimension and a slice of the lengths of the sub dimensions
  61. func makeSubSlices(v reflect.Value, l []int) {
  62. ty := v.Type().Elem()
  63. if ty.Kind() != reflect.Slice {
  64. return
  65. }
  66. for i := 0; i < v.Len(); i++ {
  67. s := reflect.MakeSlice(ty, l[0], l[0])
  68. v.Index(i).Set(s)
  69. // Are there more sub dimensions?
  70. if len(l) > 1 {
  71. makeSubSlices(v.Index(i), l[1:])
  72. }
  73. }
  74. return
  75. }
  76. // multiDimensionalIndexPermutations returns all the permutations of the indexes of a multi-dimensional slice.
  77. // The input is a slice of integers that indicates the max size/length of each dimension
  78. func multiDimensionalIndexPermutations(l []int) (ps [][]int) {
  79. z := make([]int, len(l), len(l)) // The zeros permutation
  80. ps = append(ps, z)
  81. // for each dimension, in reverse
  82. for i := len(l) - 1; i >= 0; i-- {
  83. ws := make([][]int, len(ps))
  84. copy(ws, ps)
  85. //create a permutation for each of the iterations of the current dimension
  86. for j := 1; j <= l[i]-1; j++ {
  87. // For each existing permutation
  88. for _, p := range ws {
  89. np := make([]int, len(p), len(p))
  90. copy(np, p)
  91. np[i] = j
  92. ps = append(ps, np)
  93. }
  94. }
  95. }
  96. return
  97. }
  98. // precedingMax reads off the next conformant max value
  99. func (dec *Decoder) precedingMax() uint32 {
  100. m := dec.conformantMax[0]
  101. dec.conformantMax = dec.conformantMax[1:]
  102. return m
  103. }
  104. // fillFixedArray establishes if the fixed array is uni or multi dimensional and then fills it.
  105. func (dec *Decoder) fillFixedArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
  106. l, t := parseDimensions(v)
  107. if t.Kind() == reflect.String {
  108. tag = reflect.StructTag(subStringArrayTag)
  109. }
  110. if len(l) < 1 {
  111. return errors.New("could not establish dimensions of fixed array")
  112. }
  113. if len(l) == 1 {
  114. err := dec.fillUniDimensionalFixedArray(v, tag, def)
  115. if err != nil {
  116. return fmt.Errorf("could not fill uni-dimensional fixed array: %v", err)
  117. }
  118. return nil
  119. }
  120. // Fixed array is multidimensional
  121. ps := multiDimensionalIndexPermutations(l[:len(l)-1])
  122. for _, p := range ps {
  123. // Get current multi-dimensional index to fill
  124. a := v
  125. for _, i := range p {
  126. a = a.Index(i)
  127. }
  128. // fill with the last dimension array
  129. err := dec.fillUniDimensionalFixedArray(a, tag, def)
  130. if err != nil {
  131. return fmt.Errorf("could not fill dimension %v of multi-dimensional fixed array: %v", p, err)
  132. }
  133. }
  134. return nil
  135. }
  136. // readUniDimensionalFixedArray reads an array (not slice) from the byte stream.
  137. func (dec *Decoder) fillUniDimensionalFixedArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
  138. for i := 0; i < v.Len(); i++ {
  139. err := dec.fill(v.Index(i), tag, def)
  140. if err != nil {
  141. return fmt.Errorf("could not fill index %d of fixed array: %v", i, err)
  142. }
  143. }
  144. return nil
  145. }
  146. // fillConformantArray establishes if the conformant array is uni or multi dimensional and then fills the slice.
  147. func (dec *Decoder) fillConformantArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
  148. d, _ := sliceDimensions(v.Type())
  149. if d > 1 {
  150. err := dec.fillMultiDimensionalConformantArray(v, d, tag, def)
  151. if err != nil {
  152. return err
  153. }
  154. } else {
  155. err := dec.fillUniDimensionalConformantArray(v, tag, def)
  156. if err != nil {
  157. return err
  158. }
  159. }
  160. return nil
  161. }
  162. // fillUniDimensionalConformantArray fills the uni-dimensional slice value.
  163. func (dec *Decoder) fillUniDimensionalConformantArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
  164. m := dec.precedingMax()
  165. n := int(m)
  166. a := reflect.MakeSlice(v.Type(), n, n)
  167. for i := 0; i < n; i++ {
  168. err := dec.fill(a.Index(i), tag, def)
  169. if err != nil {
  170. return fmt.Errorf("could not fill index %d of uni-dimensional conformant array: %v", i, err)
  171. }
  172. }
  173. v.Set(a)
  174. return nil
  175. }
  176. // fillMultiDimensionalConformantArray fills the multi-dimensional slice value provided from conformant array data.
  177. // The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this
  178. // method not to panic.
  179. func (dec *Decoder) fillMultiDimensionalConformantArray(v reflect.Value, d int, tag reflect.StructTag, def *[]deferedPtr) error {
  180. // Read the max size of each dimensions from the ndr stream
  181. l := make([]int, d, d)
  182. for i := range l {
  183. l[i] = int(dec.precedingMax())
  184. }
  185. // Initialise size of slices
  186. // Initialise the size of the 1st dimension
  187. ty := v.Type()
  188. v.Set(reflect.MakeSlice(ty, l[0], l[0]))
  189. // Initialise the size of the other dimensions recursively
  190. makeSubSlices(v, l[1:])
  191. // Get all permutations of the indexes and go through each and fill
  192. ps := multiDimensionalIndexPermutations(l)
  193. for _, p := range ps {
  194. // Get current multi-dimensional index to fill
  195. a := v
  196. for _, i := range p {
  197. a = a.Index(i)
  198. }
  199. err := dec.fill(a, tag, def)
  200. if err != nil {
  201. return fmt.Errorf("could not fill index %v of slice: %v", p, err)
  202. }
  203. }
  204. return nil
  205. }
  206. // fillVaryingArray establishes if the varying array is uni or multi dimensional and then fills the slice.
  207. func (dec *Decoder) fillVaryingArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
  208. d, t := sliceDimensions(v.Type())
  209. if d > 1 {
  210. err := dec.fillMultiDimensionalVaryingArray(v, t, d, tag, def)
  211. if err != nil {
  212. return err
  213. }
  214. } else {
  215. err := dec.fillUniDimensionalVaryingArray(v, tag, def)
  216. if err != nil {
  217. return err
  218. }
  219. }
  220. return nil
  221. }
  222. // fillUniDimensionalVaryingArray fills the uni-dimensional slice value.
  223. func (dec *Decoder) fillUniDimensionalVaryingArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
  224. o, err := dec.readUint32()
  225. if err != nil {
  226. return fmt.Errorf("could not read offset of uni-dimensional varying array: %v", err)
  227. }
  228. s, err := dec.readUint32()
  229. if err != nil {
  230. return fmt.Errorf("could not establish actual count of uni-dimensional varying array: %v", err)
  231. }
  232. t := v.Type()
  233. // Total size of the array is the offset in the index being passed plus the actual count of elements being passed.
  234. n := int(s + o)
  235. a := reflect.MakeSlice(t, n, n)
  236. // Populate the array starting at the offset specified
  237. for i := int(o); i < n; i++ {
  238. err := dec.fill(a.Index(i), tag, def)
  239. if err != nil {
  240. return fmt.Errorf("could not fill index %d of uni-dimensional varying array: %v", i, err)
  241. }
  242. }
  243. v.Set(a)
  244. return nil
  245. }
  246. // fillMultiDimensionalVaryingArray fills the multi-dimensional slice value provided from varying array data.
  247. // The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this
  248. // method not to panic.
  249. func (dec *Decoder) fillMultiDimensionalVaryingArray(v reflect.Value, t reflect.Type, d int, tag reflect.StructTag, def *[]deferedPtr) error {
  250. // Read the offset and actual count of each dimensions from the ndr stream
  251. o := make([]int, d, d)
  252. l := make([]int, d, d)
  253. for i := range l {
  254. off, err := dec.readUint32()
  255. if err != nil {
  256. return fmt.Errorf("could not read offset of dimension %d: %v", i+1, err)
  257. }
  258. o[i] = int(off)
  259. s, err := dec.readUint32()
  260. if err != nil {
  261. return fmt.Errorf("could not read size of dimension %d: %v", i+1, err)
  262. }
  263. l[i] = int(s) + int(off)
  264. }
  265. // Initialise size of slices
  266. // Initialise the size of the 1st dimension
  267. ty := v.Type()
  268. v.Set(reflect.MakeSlice(ty, l[0], l[0]))
  269. // Initialise the size of the other dimensions recursively
  270. makeSubSlices(v, l[1:])
  271. // Get all permutations of the indexes and go through each and fill
  272. ps := multiDimensionalIndexPermutations(l)
  273. for _, p := range ps {
  274. // Get current multi-dimensional index to fill
  275. a := v
  276. var os bool // should this permutation be skipped due to the offset of any of the dimensions?
  277. for i, j := range p {
  278. if j < o[i] {
  279. os = true
  280. break
  281. }
  282. a = a.Index(j)
  283. }
  284. if os {
  285. // This permutation should be skipped as it is less than the offset for one of the dimensions.
  286. continue
  287. }
  288. err := dec.fill(a, tag, def)
  289. if err != nil {
  290. return fmt.Errorf("could not fill index %v of slice: %v", p, err)
  291. }
  292. }
  293. return nil
  294. }
  295. // fillConformantVaryingArray establishes if the varying array is uni or multi dimensional and then fills the slice.
  296. func (dec *Decoder) fillConformantVaryingArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
  297. d, t := sliceDimensions(v.Type())
  298. if d > 1 {
  299. err := dec.fillMultiDimensionalConformantVaryingArray(v, t, d, tag, def)
  300. if err != nil {
  301. return err
  302. }
  303. } else {
  304. err := dec.fillUniDimensionalConformantVaryingArray(v, tag, def)
  305. if err != nil {
  306. return err
  307. }
  308. }
  309. return nil
  310. }
  311. // fillUniDimensionalConformantVaryingArray fills the uni-dimensional slice value.
  312. func (dec *Decoder) fillUniDimensionalConformantVaryingArray(v reflect.Value, tag reflect.StructTag, def *[]deferedPtr) error {
  313. m := dec.precedingMax()
  314. o, err := dec.readUint32()
  315. if err != nil {
  316. return fmt.Errorf("could not read offset of uni-dimensional conformant varying array: %v", err)
  317. }
  318. s, err := dec.readUint32()
  319. if err != nil {
  320. return fmt.Errorf("could not establish actual count of uni-dimensional conformant varying array: %v", err)
  321. }
  322. if m < o+s {
  323. return errors.New("max count is less than the offset plus actual count")
  324. }
  325. t := v.Type()
  326. n := int(s)
  327. a := reflect.MakeSlice(t, n, n)
  328. for i := int(o); i < n; i++ {
  329. err := dec.fill(a.Index(i), tag, def)
  330. if err != nil {
  331. return fmt.Errorf("could not fill index %d of uni-dimensional conformant varying array: %v", i, err)
  332. }
  333. }
  334. v.Set(a)
  335. return nil
  336. }
  337. // fillMultiDimensionalConformantVaryingArray fills the multi-dimensional slice value provided from conformant varying array data.
  338. // The number of dimensions must be specified. This must be less than or equal to the dimensions in the slice for this
  339. // method not to panic.
  340. func (dec *Decoder) fillMultiDimensionalConformantVaryingArray(v reflect.Value, t reflect.Type, d int, tag reflect.StructTag, def *[]deferedPtr) error {
  341. // Read the offset and actual count of each dimensions from the ndr stream
  342. m := make([]int, d, d)
  343. for i := range m {
  344. m[i] = int(dec.precedingMax())
  345. }
  346. o := make([]int, d, d)
  347. l := make([]int, d, d)
  348. for i := range l {
  349. off, err := dec.readUint32()
  350. if err != nil {
  351. return fmt.Errorf("could not read offset of dimension %d: %v", i+1, err)
  352. }
  353. o[i] = int(off)
  354. s, err := dec.readUint32()
  355. if err != nil {
  356. return fmt.Errorf("could not read actual count of dimension %d: %v", i+1, err)
  357. }
  358. if m[i] < int(s)+int(off) {
  359. m[i] = int(s) + int(off)
  360. }
  361. l[i] = int(s)
  362. }
  363. // Initialise size of slices
  364. // Initialise the size of the 1st dimension
  365. ty := v.Type()
  366. v.Set(reflect.MakeSlice(ty, m[0], m[0]))
  367. // Initialise the size of the other dimensions recursively
  368. makeSubSlices(v, m[1:])
  369. // Get all permutations of the indexes and go through each and fill
  370. ps := multiDimensionalIndexPermutations(m)
  371. for _, p := range ps {
  372. // Get current multi-dimensional index to fill
  373. a := v
  374. var os bool // should this permutation be skipped due to the offset of any of the dimensions or max is higher than the actual count being passed
  375. for i, j := range p {
  376. if j < o[i] || j >= l[i] {
  377. os = true
  378. break
  379. }
  380. a = a.Index(j)
  381. }
  382. if os {
  383. // This permutation should be skipped as it is less than the offset for one of the dimensions.
  384. continue
  385. }
  386. err := dec.fill(a, tag, def)
  387. if err != nil {
  388. return fmt.Errorf("could not fill index %v of slice: %v", p, err)
  389. }
  390. }
  391. return nil
  392. }