decode.go 9.5 KB

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