You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

389 lines
8.5 KiB

  1. // Copyright (C) MongoDB, Inc. 2017-present.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. package bsonrw
  7. import (
  8. "fmt"
  9. "io"
  10. "go.mongodb.org/mongo-driver/bson/bsontype"
  11. "go.mongodb.org/mongo-driver/bson/primitive"
  12. "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
  13. )
  14. // Copier is a type that allows copying between ValueReaders, ValueWriters, and
  15. // []byte values.
  16. type Copier struct{}
  17. // NewCopier creates a new copier with the given registry. If a nil registry is provided
  18. // a default registry is used.
  19. func NewCopier() Copier {
  20. return Copier{}
  21. }
  22. // CopyDocument handles copying a document from src to dst.
  23. func CopyDocument(dst ValueWriter, src ValueReader) error {
  24. return Copier{}.CopyDocument(dst, src)
  25. }
  26. // CopyDocument handles copying one document from the src to the dst.
  27. func (c Copier) CopyDocument(dst ValueWriter, src ValueReader) error {
  28. dr, err := src.ReadDocument()
  29. if err != nil {
  30. return err
  31. }
  32. dw, err := dst.WriteDocument()
  33. if err != nil {
  34. return err
  35. }
  36. return c.copyDocumentCore(dw, dr)
  37. }
  38. // CopyDocumentFromBytes copies the values from a BSON document represented as a
  39. // []byte to a ValueWriter.
  40. func (c Copier) CopyDocumentFromBytes(dst ValueWriter, src []byte) error {
  41. dw, err := dst.WriteDocument()
  42. if err != nil {
  43. return err
  44. }
  45. err = c.CopyBytesToDocumentWriter(dw, src)
  46. if err != nil {
  47. return err
  48. }
  49. return dw.WriteDocumentEnd()
  50. }
  51. // CopyBytesToDocumentWriter copies the values from a BSON document represented as a []byte to a
  52. // DocumentWriter.
  53. func (c Copier) CopyBytesToDocumentWriter(dst DocumentWriter, src []byte) error {
  54. // TODO(skriptble): Create errors types here. Anything thats a tag should be a property.
  55. length, rem, ok := bsoncore.ReadLength(src)
  56. if !ok {
  57. return fmt.Errorf("couldn't read length from src, not enough bytes. length=%d", len(src))
  58. }
  59. if len(src) < int(length) {
  60. return fmt.Errorf("length read exceeds number of bytes available. length=%d bytes=%d", len(src), length)
  61. }
  62. rem = rem[:length-4]
  63. var t bsontype.Type
  64. var key string
  65. var val bsoncore.Value
  66. for {
  67. t, rem, ok = bsoncore.ReadType(rem)
  68. if !ok {
  69. return io.EOF
  70. }
  71. if t == bsontype.Type(0) {
  72. if len(rem) != 0 {
  73. return fmt.Errorf("document end byte found before end of document. remaining bytes=%v", rem)
  74. }
  75. break
  76. }
  77. key, rem, ok = bsoncore.ReadKey(rem)
  78. if !ok {
  79. return fmt.Errorf("invalid key found. remaining bytes=%v", rem)
  80. }
  81. dvw, err := dst.WriteDocumentElement(key)
  82. if err != nil {
  83. return err
  84. }
  85. val, rem, ok = bsoncore.ReadValue(rem, t)
  86. if !ok {
  87. return fmt.Errorf("not enough bytes available to read type. bytes=%d type=%s", len(rem), t)
  88. }
  89. err = c.CopyValueFromBytes(dvw, t, val.Data)
  90. if err != nil {
  91. return err
  92. }
  93. }
  94. return nil
  95. }
  96. // CopyDocumentToBytes copies an entire document from the ValueReader and
  97. // returns it as bytes.
  98. func (c Copier) CopyDocumentToBytes(src ValueReader) ([]byte, error) {
  99. return c.AppendDocumentBytes(nil, src)
  100. }
  101. // AppendDocumentBytes functions the same as CopyDocumentToBytes, but will
  102. // append the result to dst.
  103. func (c Copier) AppendDocumentBytes(dst []byte, src ValueReader) ([]byte, error) {
  104. if br, ok := src.(BytesReader); ok {
  105. _, dst, err := br.ReadValueBytes(dst)
  106. return dst, err
  107. }
  108. vw := vwPool.Get().(*valueWriter)
  109. defer vwPool.Put(vw)
  110. vw.reset(dst)
  111. err := c.CopyDocument(vw, src)
  112. dst = vw.buf
  113. return dst, err
  114. }
  115. // CopyValueFromBytes will write the value represtend by t and src to dst.
  116. func (c Copier) CopyValueFromBytes(dst ValueWriter, t bsontype.Type, src []byte) error {
  117. if wvb, ok := dst.(BytesWriter); ok {
  118. return wvb.WriteValueBytes(t, src)
  119. }
  120. vr := vrPool.Get().(*valueReader)
  121. defer vrPool.Put(vr)
  122. vr.reset(src)
  123. vr.pushElement(t)
  124. return c.CopyValue(dst, vr)
  125. }
  126. // CopyValueToBytes copies a value from src and returns it as a bsontype.Type and a
  127. // []byte.
  128. func (c Copier) CopyValueToBytes(src ValueReader) (bsontype.Type, []byte, error) {
  129. return c.AppendValueBytes(nil, src)
  130. }
  131. // AppendValueBytes functions the same as CopyValueToBytes, but will append the
  132. // result to dst.
  133. func (c Copier) AppendValueBytes(dst []byte, src ValueReader) (bsontype.Type, []byte, error) {
  134. if br, ok := src.(BytesReader); ok {
  135. return br.ReadValueBytes(dst)
  136. }
  137. vw := vwPool.Get().(*valueWriter)
  138. defer vwPool.Put(vw)
  139. start := len(dst)
  140. vw.reset(dst)
  141. vw.push(mElement)
  142. err := c.CopyValue(vw, src)
  143. if err != nil {
  144. return 0, dst, err
  145. }
  146. return bsontype.Type(vw.buf[start]), vw.buf[start+2:], nil
  147. }
  148. // CopyValue will copy a single value from src to dst.
  149. func (c Copier) CopyValue(dst ValueWriter, src ValueReader) error {
  150. var err error
  151. switch src.Type() {
  152. case bsontype.Double:
  153. var f64 float64
  154. f64, err = src.ReadDouble()
  155. if err != nil {
  156. break
  157. }
  158. err = dst.WriteDouble(f64)
  159. case bsontype.String:
  160. var str string
  161. str, err = src.ReadString()
  162. if err != nil {
  163. return err
  164. }
  165. err = dst.WriteString(str)
  166. case bsontype.EmbeddedDocument:
  167. err = c.CopyDocument(dst, src)
  168. case bsontype.Array:
  169. err = c.copyArray(dst, src)
  170. case bsontype.Binary:
  171. var data []byte
  172. var subtype byte
  173. data, subtype, err = src.ReadBinary()
  174. if err != nil {
  175. break
  176. }
  177. err = dst.WriteBinaryWithSubtype(data, subtype)
  178. case bsontype.Undefined:
  179. err = src.ReadUndefined()
  180. if err != nil {
  181. break
  182. }
  183. err = dst.WriteUndefined()
  184. case bsontype.ObjectID:
  185. var oid primitive.ObjectID
  186. oid, err = src.ReadObjectID()
  187. if err != nil {
  188. break
  189. }
  190. err = dst.WriteObjectID(oid)
  191. case bsontype.Boolean:
  192. var b bool
  193. b, err = src.ReadBoolean()
  194. if err != nil {
  195. break
  196. }
  197. err = dst.WriteBoolean(b)
  198. case bsontype.DateTime:
  199. var dt int64
  200. dt, err = src.ReadDateTime()
  201. if err != nil {
  202. break
  203. }
  204. err = dst.WriteDateTime(dt)
  205. case bsontype.Null:
  206. err = src.ReadNull()
  207. if err != nil {
  208. break
  209. }
  210. err = dst.WriteNull()
  211. case bsontype.Regex:
  212. var pattern, options string
  213. pattern, options, err = src.ReadRegex()
  214. if err != nil {
  215. break
  216. }
  217. err = dst.WriteRegex(pattern, options)
  218. case bsontype.DBPointer:
  219. var ns string
  220. var pointer primitive.ObjectID
  221. ns, pointer, err = src.ReadDBPointer()
  222. if err != nil {
  223. break
  224. }
  225. err = dst.WriteDBPointer(ns, pointer)
  226. case bsontype.JavaScript:
  227. var js string
  228. js, err = src.ReadJavascript()
  229. if err != nil {
  230. break
  231. }
  232. err = dst.WriteJavascript(js)
  233. case bsontype.Symbol:
  234. var symbol string
  235. symbol, err = src.ReadSymbol()
  236. if err != nil {
  237. break
  238. }
  239. err = dst.WriteSymbol(symbol)
  240. case bsontype.CodeWithScope:
  241. var code string
  242. var srcScope DocumentReader
  243. code, srcScope, err = src.ReadCodeWithScope()
  244. if err != nil {
  245. break
  246. }
  247. var dstScope DocumentWriter
  248. dstScope, err = dst.WriteCodeWithScope(code)
  249. if err != nil {
  250. break
  251. }
  252. err = c.copyDocumentCore(dstScope, srcScope)
  253. case bsontype.Int32:
  254. var i32 int32
  255. i32, err = src.ReadInt32()
  256. if err != nil {
  257. break
  258. }
  259. err = dst.WriteInt32(i32)
  260. case bsontype.Timestamp:
  261. var t, i uint32
  262. t, i, err = src.ReadTimestamp()
  263. if err != nil {
  264. break
  265. }
  266. err = dst.WriteTimestamp(t, i)
  267. case bsontype.Int64:
  268. var i64 int64
  269. i64, err = src.ReadInt64()
  270. if err != nil {
  271. break
  272. }
  273. err = dst.WriteInt64(i64)
  274. case bsontype.Decimal128:
  275. var d128 primitive.Decimal128
  276. d128, err = src.ReadDecimal128()
  277. if err != nil {
  278. break
  279. }
  280. err = dst.WriteDecimal128(d128)
  281. case bsontype.MinKey:
  282. err = src.ReadMinKey()
  283. if err != nil {
  284. break
  285. }
  286. err = dst.WriteMinKey()
  287. case bsontype.MaxKey:
  288. err = src.ReadMaxKey()
  289. if err != nil {
  290. break
  291. }
  292. err = dst.WriteMaxKey()
  293. default:
  294. err = fmt.Errorf("Cannot copy unknown BSON type %s", src.Type())
  295. }
  296. return err
  297. }
  298. func (c Copier) copyArray(dst ValueWriter, src ValueReader) error {
  299. ar, err := src.ReadArray()
  300. if err != nil {
  301. return err
  302. }
  303. aw, err := dst.WriteArray()
  304. if err != nil {
  305. return err
  306. }
  307. for {
  308. vr, err := ar.ReadValue()
  309. if err == ErrEOA {
  310. break
  311. }
  312. if err != nil {
  313. return err
  314. }
  315. vw, err := aw.WriteArrayElement()
  316. if err != nil {
  317. return err
  318. }
  319. err = c.CopyValue(vw, vr)
  320. if err != nil {
  321. return err
  322. }
  323. }
  324. return aw.WriteArrayEnd()
  325. }
  326. func (c Copier) copyDocumentCore(dw DocumentWriter, dr DocumentReader) error {
  327. for {
  328. key, vr, err := dr.ReadElement()
  329. if err == ErrEOD {
  330. break
  331. }
  332. if err != nil {
  333. return err
  334. }
  335. vw, err := dw.WriteDocumentElement(key)
  336. if err != nil {
  337. return err
  338. }
  339. err = c.CopyValue(vw, vr)
  340. if err != nil {
  341. return err
  342. }
  343. }
  344. return dw.WriteDocumentEnd()
  345. }