decode.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. package wire
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "reflect"
  9. "strings"
  10. )
  11. var (
  12. ErrUnmarshalFailure = errors.New("failed to unmarshal")
  13. errNotNullTerminated = errors.New("nullterm tag is set, but string is not null-terminated")
  14. )
  15. // UnmarshalBE unmarshalls OSCAR protocol messages in big-endian format.
  16. func UnmarshalBE(v any, r io.Reader) error {
  17. if err := unmarshal(reflect.TypeOf(v).Elem(), reflect.ValueOf(v).Elem(), "", r, binary.BigEndian, ""); err != nil {
  18. return fmt.Errorf("%w: %w", ErrUnmarshalFailure, err)
  19. }
  20. return nil
  21. }
  22. // UnmarshalLE unmarshalls OSCAR protocol messages in little-endian format.
  23. func UnmarshalLE(v any, r io.Reader) error {
  24. if err := unmarshal(reflect.TypeOf(v).Elem(), reflect.ValueOf(v).Elem(), "", r, binary.LittleEndian, ""); err != nil {
  25. return fmt.Errorf("%w: %w", ErrUnmarshalFailure, err)
  26. }
  27. return nil
  28. }
  29. func unmarshal(t reflect.Type, v reflect.Value, tag reflect.StructTag, r io.Reader, order binary.ByteOrder, activeQuirk string) error {
  30. oscTag, err := parseOSCARTag(tag)
  31. if err != nil {
  32. return fmt.Errorf("error parsing tag: %w", err)
  33. }
  34. effectiveQuirk := strings.TrimSpace(oscTag.quirk)
  35. if effectiveQuirk == "" {
  36. effectiveQuirk = activeQuirk
  37. }
  38. if oscTag.optional {
  39. v.Set(reflect.New(t.Elem()))
  40. err := unmarshalStruct(t.Elem(), v.Elem(), oscTag, r, order, effectiveQuirk)
  41. if errors.Is(err, io.EOF) {
  42. // no values to read, but that's ok since this struct is optional
  43. v.Set(reflect.Zero(t))
  44. err = nil
  45. }
  46. return err
  47. } else if v.Kind() == reflect.Ptr {
  48. return errNonOptionalPointer
  49. }
  50. switch v.Kind() {
  51. case reflect.Array:
  52. return unmarshalArray(v, r, order, effectiveQuirk)
  53. case reflect.Slice:
  54. return unmarshalSlice(v, oscTag, r, order, effectiveQuirk)
  55. case reflect.String:
  56. return unmarshalString(v, oscTag, r, order)
  57. case reflect.Struct:
  58. return unmarshalStruct(t, v, oscTag, r, order, effectiveQuirk)
  59. case reflect.Uint8:
  60. var l uint8
  61. if err := binary.Read(r, order, &l); err != nil {
  62. return err
  63. }
  64. v.Set(reflect.ValueOf(l))
  65. return nil
  66. case reflect.Uint16:
  67. var l uint16
  68. if err := binary.Read(r, order, &l); err != nil {
  69. return err
  70. }
  71. v.Set(reflect.ValueOf(l))
  72. return nil
  73. case reflect.Uint32:
  74. var l uint32
  75. if err := binary.Read(r, order, &l); err != nil {
  76. return err
  77. }
  78. v.Set(reflect.ValueOf(l))
  79. return nil
  80. case reflect.Uint64:
  81. var l uint64
  82. if err := binary.Read(r, order, &l); err != nil {
  83. return err
  84. }
  85. v.Set(reflect.ValueOf(l))
  86. return nil
  87. default:
  88. return fmt.Errorf("unsupported type %v", t.Kind())
  89. }
  90. }
  91. func unmarshalArray(v reflect.Value, r io.Reader, order binary.ByteOrder, activeQuirk string) error {
  92. arrLen := v.Len()
  93. arrType := v.Type().Elem()
  94. for i := 0; i < arrLen; i++ {
  95. elem := reflect.New(arrType).Elem()
  96. if err := unmarshal(arrType, elem, "", r, order, activeQuirk); err != nil {
  97. return err
  98. }
  99. v.Index(i).Set(elem)
  100. }
  101. return nil
  102. }
  103. func unmarshalSlice(v reflect.Value, oscTag oscarTag, r io.Reader, order binary.ByteOrder, activeQuirk string) error {
  104. slice := reflect.New(v.Type()).Elem()
  105. elemType := v.Type().Elem()
  106. if oscTag.hasLenPrefix {
  107. bufLen, err := unmarshalUnsignedInt(oscTag.lenPrefix, r, order)
  108. if err != nil {
  109. return err
  110. }
  111. b := make([]byte, bufLen)
  112. if bufLen > 0 {
  113. if _, err := io.ReadFull(r, b); err != nil {
  114. return err
  115. }
  116. }
  117. buf := bytes.NewBuffer(b)
  118. for buf.Len() > 0 {
  119. elem := reflect.New(elemType).Elem()
  120. if err := unmarshalSliceElement(elemType, elem, buf, order, activeQuirk); err != nil {
  121. return err
  122. }
  123. slice = reflect.Append(slice, elem)
  124. }
  125. } else if oscTag.hasCountPrefix {
  126. count, err := unmarshalUnsignedInt(oscTag.countPrefix, r, order)
  127. if err != nil {
  128. return err
  129. }
  130. for i := 0; i < count; i++ {
  131. elem := reflect.New(elemType).Elem()
  132. if err := unmarshalSliceElement(elemType, elem, r, order, activeQuirk); err != nil {
  133. return err
  134. }
  135. slice = reflect.Append(slice, elem)
  136. }
  137. } else {
  138. for {
  139. elem := reflect.New(elemType).Elem()
  140. if err := unmarshalSliceElement(elemType, elem, r, order, activeQuirk); err != nil {
  141. if errors.Is(err, io.EOF) {
  142. break
  143. }
  144. return err
  145. }
  146. slice = reflect.Append(slice, elem)
  147. }
  148. }
  149. v.Set(slice)
  150. return nil
  151. }
  152. // unmarshalSliceElement reads one element of a slice; for TLV under LE with decode quirks,
  153. // applies client-specific length workarounds (see unmarshalTLV* helpers).
  154. func unmarshalSliceElement(elemType reflect.Type, elem reflect.Value, r io.Reader, order binary.ByteOrder, activeQuirk string) error {
  155. if activeQuirk != "" {
  156. switch {
  157. case activeQuirk == "icq2003b_set_fullinfo" && order == binary.LittleEndian && elemType == reflect.TypeOf(TLV{}):
  158. return unmarshalTLVICQ2003bSetFullInfo(elem, r, order)
  159. case activeQuirk == "qip_2005_search_by_uin2" && order == binary.LittleEndian && elemType == reflect.TypeOf(TLV{}):
  160. return unmarshalTLVQIP2005SearchByUIN2(elem, r, order)
  161. }
  162. }
  163. return unmarshal(elemType, elem, "", r, order, activeQuirk)
  164. }
  165. // unmarshalTLVICQ2003bSetFullInfo decodes one TLV with ICQ 2003b save-info workaround for ICQTLVTagsEmail.
  166. func unmarshalTLVICQ2003bSetFullInfo(elem reflect.Value, r io.Reader, order binary.ByteOrder) error {
  167. var tag uint16
  168. if err := binary.Read(r, order, &tag); err != nil {
  169. return err
  170. }
  171. var n uint16
  172. if err := binary.Read(r, order, &n); err != nil {
  173. return err
  174. }
  175. if tag == ICQTLVTagsEmail && n == 3 {
  176. n = 4
  177. }
  178. buf := make([]byte, n)
  179. if n > 0 {
  180. if _, err := io.ReadFull(r, buf); err != nil {
  181. return err
  182. }
  183. }
  184. elem.Field(0).Set(reflect.ValueOf(tag))
  185. elem.Field(1).SetBytes(buf)
  186. return nil
  187. }
  188. // unmarshalTLVQIP2005SearchByUIN2 decodes one TLV for META SearchByUIN2 (0x0569): QIP 2005 sends
  189. // ICQTLVTagsUIN (0x0136) with an incorrect length (e.g. 6) for a 4-byte UIN, causing EOF on a strict read.
  190. func unmarshalTLVQIP2005SearchByUIN2(elem reflect.Value, r io.Reader, order binary.ByteOrder) error {
  191. var tag uint16
  192. if err := binary.Read(r, order, &tag); err != nil {
  193. return err
  194. }
  195. var n uint16
  196. if err := binary.Read(r, order, &n); err != nil {
  197. return err
  198. }
  199. if tag == ICQTLVTagsUIN && n != 4 {
  200. n = 4
  201. }
  202. buf := make([]byte, n)
  203. if n > 0 {
  204. if _, err := io.ReadFull(r, buf); err != nil {
  205. return err
  206. }
  207. }
  208. elem.Field(0).Set(reflect.ValueOf(tag))
  209. elem.Field(1).SetBytes(buf)
  210. return nil
  211. }
  212. func unmarshalString(v reflect.Value, oscTag oscarTag, r io.Reader, order binary.ByteOrder) error {
  213. if !oscTag.hasLenPrefix {
  214. return fmt.Errorf("missing len_prefix tag")
  215. }
  216. bufLen, err := unmarshalUnsignedInt(oscTag.lenPrefix, r, order)
  217. if err != nil {
  218. return err
  219. }
  220. buf := make([]byte, bufLen)
  221. if bufLen > 0 {
  222. if _, err := io.ReadFull(r, buf); err != nil {
  223. return err
  224. }
  225. if oscTag.nullTerminated {
  226. // search for null within string and truncate there if found
  227. // needed for icq 6 login to be working
  228. if nullPos := bytes.IndexByte(buf, 0x00); nullPos != -1 {
  229. buf = buf[0:nullPos]
  230. }
  231. }
  232. }
  233. // todo is there a more efficient way?
  234. v.SetString(string(buf))
  235. return nil
  236. }
  237. func unmarshalStruct(t reflect.Type, v reflect.Value, oscTag oscarTag, r io.Reader, order binary.ByteOrder, activeQuirk string) error {
  238. if oscTag.hasLenPrefix {
  239. bufLen, err := unmarshalUnsignedInt(oscTag.lenPrefix, r, order)
  240. if err != nil {
  241. return err
  242. }
  243. b := make([]byte, bufLen)
  244. if bufLen > 0 {
  245. if _, err := io.ReadFull(r, b); err != nil {
  246. return err
  247. }
  248. }
  249. r = bytes.NewBuffer(b)
  250. }
  251. for i := 0; i < v.NumField(); i++ {
  252. field := t.Field(i)
  253. value := v.Field(i)
  254. if field.Type.Kind() == reflect.Ptr {
  255. if i != v.NumField()-1 {
  256. return fmt.Errorf("pointer type found at non-final field %s", field.Name)
  257. }
  258. if field.Type.Elem().Kind() != reflect.Struct {
  259. return fmt.Errorf("%w: field %s must point to a struct, got %v instead",
  260. errNonOptionalPointer, field.Name, field.Type.Elem().Kind())
  261. }
  262. }
  263. if err := unmarshal(field.Type, value, field.Tag, r, order, activeQuirk); err != nil {
  264. return err
  265. }
  266. }
  267. return nil
  268. }
  269. func unmarshalUnsignedInt(intType reflect.Kind, r io.Reader, order binary.ByteOrder) (int, error) {
  270. var bufLen int
  271. switch intType {
  272. case reflect.Uint8:
  273. var l uint8
  274. if err := binary.Read(r, order, &l); err != nil {
  275. return 0, err
  276. }
  277. bufLen = int(l)
  278. case reflect.Uint16:
  279. var l uint16
  280. if err := binary.Read(r, order, &l); err != nil {
  281. return 0, err
  282. }
  283. bufLen = int(l)
  284. default:
  285. panic(fmt.Sprintf("unsupported type %s. allowed types: uint8, uint16", intType))
  286. }
  287. return bufLen, nil
  288. }