podman
445 строк · 9.8 Кб
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
7package bsonrw
8
9import (
10"fmt"
11"io"
12
13"go.mongodb.org/mongo-driver/bson/bsontype"
14"go.mongodb.org/mongo-driver/bson/primitive"
15"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
16)
17
18// Copier is a type that allows copying between ValueReaders, ValueWriters, and
19// []byte values.
20type Copier struct{}
21
22// NewCopier creates a new copier with the given registry. If a nil registry is provided
23// a default registry is used.
24func NewCopier() Copier {
25return Copier{}
26}
27
28// CopyDocument handles copying a document from src to dst.
29func CopyDocument(dst ValueWriter, src ValueReader) error {
30return Copier{}.CopyDocument(dst, src)
31}
32
33// CopyDocument handles copying one document from the src to the dst.
34func (c Copier) CopyDocument(dst ValueWriter, src ValueReader) error {
35dr, err := src.ReadDocument()
36if err != nil {
37return err
38}
39
40dw, err := dst.WriteDocument()
41if err != nil {
42return err
43}
44
45return c.copyDocumentCore(dw, dr)
46}
47
48// CopyArrayFromBytes copies the values from a BSON array represented as a
49// []byte to a ValueWriter.
50func (c Copier) CopyArrayFromBytes(dst ValueWriter, src []byte) error {
51aw, err := dst.WriteArray()
52if err != nil {
53return err
54}
55
56err = c.CopyBytesToArrayWriter(aw, src)
57if err != nil {
58return err
59}
60
61return aw.WriteArrayEnd()
62}
63
64// CopyDocumentFromBytes copies the values from a BSON document represented as a
65// []byte to a ValueWriter.
66func (c Copier) CopyDocumentFromBytes(dst ValueWriter, src []byte) error {
67dw, err := dst.WriteDocument()
68if err != nil {
69return err
70}
71
72err = c.CopyBytesToDocumentWriter(dw, src)
73if err != nil {
74return err
75}
76
77return dw.WriteDocumentEnd()
78}
79
80type writeElementFn func(key string) (ValueWriter, error)
81
82// CopyBytesToArrayWriter copies the values from a BSON Array represented as a []byte to an
83// ArrayWriter.
84func (c Copier) CopyBytesToArrayWriter(dst ArrayWriter, src []byte) error {
85wef := func(_ string) (ValueWriter, error) {
86return dst.WriteArrayElement()
87}
88
89return c.copyBytesToValueWriter(src, wef)
90}
91
92// CopyBytesToDocumentWriter copies the values from a BSON document represented as a []byte to a
93// DocumentWriter.
94func (c Copier) CopyBytesToDocumentWriter(dst DocumentWriter, src []byte) error {
95wef := func(key string) (ValueWriter, error) {
96return dst.WriteDocumentElement(key)
97}
98
99return c.copyBytesToValueWriter(src, wef)
100}
101
102func (c Copier) copyBytesToValueWriter(src []byte, wef writeElementFn) error {
103// TODO(skriptble): Create errors types here. Anything thats a tag should be a property.
104length, rem, ok := bsoncore.ReadLength(src)
105if !ok {
106return fmt.Errorf("couldn't read length from src, not enough bytes. length=%d", len(src))
107}
108if len(src) < int(length) {
109return fmt.Errorf("length read exceeds number of bytes available. length=%d bytes=%d", len(src), length)
110}
111rem = rem[:length-4]
112
113var t bsontype.Type
114var key string
115var val bsoncore.Value
116for {
117t, rem, ok = bsoncore.ReadType(rem)
118if !ok {
119return io.EOF
120}
121if t == bsontype.Type(0) {
122if len(rem) != 0 {
123return fmt.Errorf("document end byte found before end of document. remaining bytes=%v", rem)
124}
125break
126}
127
128key, rem, ok = bsoncore.ReadKey(rem)
129if !ok {
130return fmt.Errorf("invalid key found. remaining bytes=%v", rem)
131}
132
133// write as either array element or document element using writeElementFn
134vw, err := wef(key)
135if err != nil {
136return err
137}
138
139val, rem, ok = bsoncore.ReadValue(rem, t)
140if !ok {
141return fmt.Errorf("not enough bytes available to read type. bytes=%d type=%s", len(rem), t)
142}
143err = c.CopyValueFromBytes(vw, t, val.Data)
144if err != nil {
145return err
146}
147}
148return nil
149}
150
151// CopyDocumentToBytes copies an entire document from the ValueReader and
152// returns it as bytes.
153func (c Copier) CopyDocumentToBytes(src ValueReader) ([]byte, error) {
154return c.AppendDocumentBytes(nil, src)
155}
156
157// AppendDocumentBytes functions the same as CopyDocumentToBytes, but will
158// append the result to dst.
159func (c Copier) AppendDocumentBytes(dst []byte, src ValueReader) ([]byte, error) {
160if br, ok := src.(BytesReader); ok {
161_, dst, err := br.ReadValueBytes(dst)
162return dst, err
163}
164
165vw := vwPool.Get().(*valueWriter)
166defer vwPool.Put(vw)
167
168vw.reset(dst)
169
170err := c.CopyDocument(vw, src)
171dst = vw.buf
172return dst, err
173}
174
175// AppendArrayBytes copies an array from the ValueReader to dst.
176func (c Copier) AppendArrayBytes(dst []byte, src ValueReader) ([]byte, error) {
177if br, ok := src.(BytesReader); ok {
178_, dst, err := br.ReadValueBytes(dst)
179return dst, err
180}
181
182vw := vwPool.Get().(*valueWriter)
183defer vwPool.Put(vw)
184
185vw.reset(dst)
186
187err := c.copyArray(vw, src)
188dst = vw.buf
189return dst, err
190}
191
192// CopyValueFromBytes will write the value represtend by t and src to dst.
193func (c Copier) CopyValueFromBytes(dst ValueWriter, t bsontype.Type, src []byte) error {
194if wvb, ok := dst.(BytesWriter); ok {
195return wvb.WriteValueBytes(t, src)
196}
197
198vr := vrPool.Get().(*valueReader)
199defer vrPool.Put(vr)
200
201vr.reset(src)
202vr.pushElement(t)
203
204return c.CopyValue(dst, vr)
205}
206
207// CopyValueToBytes copies a value from src and returns it as a bsontype.Type and a
208// []byte.
209func (c Copier) CopyValueToBytes(src ValueReader) (bsontype.Type, []byte, error) {
210return c.AppendValueBytes(nil, src)
211}
212
213// AppendValueBytes functions the same as CopyValueToBytes, but will append the
214// result to dst.
215func (c Copier) AppendValueBytes(dst []byte, src ValueReader) (bsontype.Type, []byte, error) {
216if br, ok := src.(BytesReader); ok {
217return br.ReadValueBytes(dst)
218}
219
220vw := vwPool.Get().(*valueWriter)
221defer vwPool.Put(vw)
222
223start := len(dst)
224
225vw.reset(dst)
226vw.push(mElement)
227
228err := c.CopyValue(vw, src)
229if err != nil {
230return 0, dst, err
231}
232
233return bsontype.Type(vw.buf[start]), vw.buf[start+2:], nil
234}
235
236// CopyValue will copy a single value from src to dst.
237func (c Copier) CopyValue(dst ValueWriter, src ValueReader) error {
238var err error
239switch src.Type() {
240case bsontype.Double:
241var f64 float64
242f64, err = src.ReadDouble()
243if err != nil {
244break
245}
246err = dst.WriteDouble(f64)
247case bsontype.String:
248var str string
249str, err = src.ReadString()
250if err != nil {
251return err
252}
253err = dst.WriteString(str)
254case bsontype.EmbeddedDocument:
255err = c.CopyDocument(dst, src)
256case bsontype.Array:
257err = c.copyArray(dst, src)
258case bsontype.Binary:
259var data []byte
260var subtype byte
261data, subtype, err = src.ReadBinary()
262if err != nil {
263break
264}
265err = dst.WriteBinaryWithSubtype(data, subtype)
266case bsontype.Undefined:
267err = src.ReadUndefined()
268if err != nil {
269break
270}
271err = dst.WriteUndefined()
272case bsontype.ObjectID:
273var oid primitive.ObjectID
274oid, err = src.ReadObjectID()
275if err != nil {
276break
277}
278err = dst.WriteObjectID(oid)
279case bsontype.Boolean:
280var b bool
281b, err = src.ReadBoolean()
282if err != nil {
283break
284}
285err = dst.WriteBoolean(b)
286case bsontype.DateTime:
287var dt int64
288dt, err = src.ReadDateTime()
289if err != nil {
290break
291}
292err = dst.WriteDateTime(dt)
293case bsontype.Null:
294err = src.ReadNull()
295if err != nil {
296break
297}
298err = dst.WriteNull()
299case bsontype.Regex:
300var pattern, options string
301pattern, options, err = src.ReadRegex()
302if err != nil {
303break
304}
305err = dst.WriteRegex(pattern, options)
306case bsontype.DBPointer:
307var ns string
308var pointer primitive.ObjectID
309ns, pointer, err = src.ReadDBPointer()
310if err != nil {
311break
312}
313err = dst.WriteDBPointer(ns, pointer)
314case bsontype.JavaScript:
315var js string
316js, err = src.ReadJavascript()
317if err != nil {
318break
319}
320err = dst.WriteJavascript(js)
321case bsontype.Symbol:
322var symbol string
323symbol, err = src.ReadSymbol()
324if err != nil {
325break
326}
327err = dst.WriteSymbol(symbol)
328case bsontype.CodeWithScope:
329var code string
330var srcScope DocumentReader
331code, srcScope, err = src.ReadCodeWithScope()
332if err != nil {
333break
334}
335
336var dstScope DocumentWriter
337dstScope, err = dst.WriteCodeWithScope(code)
338if err != nil {
339break
340}
341err = c.copyDocumentCore(dstScope, srcScope)
342case bsontype.Int32:
343var i32 int32
344i32, err = src.ReadInt32()
345if err != nil {
346break
347}
348err = dst.WriteInt32(i32)
349case bsontype.Timestamp:
350var t, i uint32
351t, i, err = src.ReadTimestamp()
352if err != nil {
353break
354}
355err = dst.WriteTimestamp(t, i)
356case bsontype.Int64:
357var i64 int64
358i64, err = src.ReadInt64()
359if err != nil {
360break
361}
362err = dst.WriteInt64(i64)
363case bsontype.Decimal128:
364var d128 primitive.Decimal128
365d128, err = src.ReadDecimal128()
366if err != nil {
367break
368}
369err = dst.WriteDecimal128(d128)
370case bsontype.MinKey:
371err = src.ReadMinKey()
372if err != nil {
373break
374}
375err = dst.WriteMinKey()
376case bsontype.MaxKey:
377err = src.ReadMaxKey()
378if err != nil {
379break
380}
381err = dst.WriteMaxKey()
382default:
383err = fmt.Errorf("Cannot copy unknown BSON type %s", src.Type())
384}
385
386return err
387}
388
389func (c Copier) copyArray(dst ValueWriter, src ValueReader) error {
390ar, err := src.ReadArray()
391if err != nil {
392return err
393}
394
395aw, err := dst.WriteArray()
396if err != nil {
397return err
398}
399
400for {
401vr, err := ar.ReadValue()
402if err == ErrEOA {
403break
404}
405if err != nil {
406return err
407}
408
409vw, err := aw.WriteArrayElement()
410if err != nil {
411return err
412}
413
414err = c.CopyValue(vw, vr)
415if err != nil {
416return err
417}
418}
419
420return aw.WriteArrayEnd()
421}
422
423func (c Copier) copyDocumentCore(dw DocumentWriter, dr DocumentReader) error {
424for {
425key, vr, err := dr.ReadElement()
426if err == ErrEOD {
427break
428}
429if err != nil {
430return err
431}
432
433vw, err := dw.WriteDocumentElement(key)
434if err != nil {
435return err
436}
437
438err = c.CopyValue(vw, vr)
439if err != nil {
440return err
441}
442}
443
444return dw.WriteDocumentEnd()
445}
446