decode.go 9.1 KB

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