/* ** upb::pb::Decoder ** ** A high performance, streaming, resumable decoder for the binary protobuf ** format. ** ** This interface works the same regardless of what decoder backend is being ** used. A client of this class does not need to know whether decoding is using ** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder. By default, ** it will always use the fastest available decoder. However, you can call ** set_allow_jit(false) to disable any JIT decoder that might be available. ** This is primarily useful for testing purposes. */ #ifndef UPB_DECODER_H_ #define UPB_DECODER_H_ #include "upb/sink.h" #ifdef __cplusplus namespace upb { namespace pb { class CodeCache; class DecoderPtr; class DecoderMethodPtr; class DecoderMethodOptions; } /* namespace pb */ } /* namespace upb */ #endif /* The maximum number of bytes we are required to buffer internally between * calls to the decoder. The value is 14: a 5 byte unknown tag plus ten-byte * varint, less one because we are buffering an incomplete value. * * Should only be used by unit tests. */ #define UPB_DECODER_MAX_RESIDUAL_BYTES 14 /* upb_pbdecodermethod ********************************************************/ struct upb_pbdecodermethod; typedef struct upb_pbdecodermethod upb_pbdecodermethod; #ifdef __cplusplus extern "C" { #endif const upb_handlers *upb_pbdecodermethod_desthandlers( const upb_pbdecodermethod *m); const upb_byteshandler *upb_pbdecodermethod_inputhandler( const upb_pbdecodermethod *m); bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m); #ifdef __cplusplus } /* extern "C" */ /* Represents the code to parse a protobuf according to a destination * Handlers. */ class upb::pb::DecoderMethodPtr { public: DecoderMethodPtr() : ptr_(nullptr) {} DecoderMethodPtr(const upb_pbdecodermethod* ptr) : ptr_(ptr) {} const upb_pbdecodermethod* ptr() { return ptr_; } /* The destination handlers that are statically bound to this method. * This method is only capable of outputting to a sink that uses these * handlers. */ const Handlers *dest_handlers() const { return upb_pbdecodermethod_desthandlers(ptr_); } /* The input handlers for this decoder method. */ const BytesHandler* input_handler() const { return upb_pbdecodermethod_inputhandler(ptr_); } /* Whether this method is native. */ bool is_native() const { return upb_pbdecodermethod_isnative(ptr_); } private: const upb_pbdecodermethod* ptr_; }; #endif /* upb_pbdecoder **************************************************************/ /* Preallocation hint: decoder won't allocate more bytes than this when first * constructed. This hint may be an overestimate for some build configurations. * But if the decoder library is upgraded without recompiling the application, * it may be an underestimate. */ #define UPB_PB_DECODER_SIZE 4416 struct upb_pbdecoder; typedef struct upb_pbdecoder upb_pbdecoder; #ifdef __cplusplus extern "C" { #endif upb_pbdecoder *upb_pbdecoder_create(upb_arena *arena, const upb_pbdecodermethod *method, upb_sink output, upb_status *status); const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d); upb_bytessink upb_pbdecoder_input(upb_pbdecoder *d); uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d); size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d); bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max); void upb_pbdecoder_reset(upb_pbdecoder *d); #ifdef __cplusplus } /* extern "C" */ /* A Decoder receives binary protobuf data on its input sink and pushes the * decoded data to its output sink. */ class upb::pb::DecoderPtr { public: DecoderPtr() : ptr_(nullptr) {} DecoderPtr(upb_pbdecoder* ptr) : ptr_(ptr) {} upb_pbdecoder* ptr() { return ptr_; } /* Constructs a decoder instance for the given method, which must outlive this * decoder. Any errors during parsing will be set on the given status, which * must also outlive this decoder. * * The sink must match the given method. */ static DecoderPtr Create(Arena *arena, DecoderMethodPtr method, upb::Sink output, Status *status) { return DecoderPtr(upb_pbdecoder_create(arena->ptr(), method.ptr(), output.sink(), status->ptr())); } /* Returns the DecoderMethod this decoder is parsing from. */ const DecoderMethodPtr method() const { return DecoderMethodPtr(upb_pbdecoder_method(ptr_)); } /* The sink on which this decoder receives input. */ BytesSink input() { return BytesSink(upb_pbdecoder_input(ptr())); } /* Returns number of bytes successfully parsed. * * This can be useful for determining the stream position where an error * occurred. * * This value may not be up-to-date when called from inside a parsing * callback. */ uint64_t BytesParsed() { return upb_pbdecoder_bytesparsed(ptr()); } /* Gets/sets the parsing nexting limit. If the total number of nested * submessages and repeated fields hits this limit, parsing will fail. This * is a resource limit that controls the amount of memory used by the parsing * stack. * * Setting the limit will fail if the parser is currently suspended at a depth * greater than this, or if memory allocation of the stack fails. */ size_t max_nesting() { return upb_pbdecoder_maxnesting(ptr()); } bool set_max_nesting(size_t max) { return upb_pbdecoder_setmaxnesting(ptr(), max); } void Reset() { upb_pbdecoder_reset(ptr()); } static const size_t kSize = UPB_PB_DECODER_SIZE; private: upb_pbdecoder *ptr_; }; #endif /* __cplusplus */ /* upb_pbcodecache ************************************************************/ /* Lazily builds and caches decoder methods that will push data to the given * handlers. The destination handlercache must outlive this object. */ struct upb_pbcodecache; typedef struct upb_pbcodecache upb_pbcodecache; #ifdef __cplusplus extern "C" { #endif upb_pbcodecache *upb_pbcodecache_new(upb_handlercache *dest); void upb_pbcodecache_free(upb_pbcodecache *c); bool upb_pbcodecache_allowjit(const upb_pbcodecache *c); void upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow); void upb_pbcodecache_setlazy(upb_pbcodecache *c, bool lazy); const upb_pbdecodermethod *upb_pbcodecache_get(upb_pbcodecache *c, const upb_msgdef *md); #ifdef __cplusplus } /* extern "C" */ /* A class for caching protobuf processing code, whether bytecode for the * interpreted decoder or machine code for the JIT. * * This class is not thread-safe. */ class upb::pb::CodeCache { public: CodeCache(upb::HandlerCache *dest) : ptr_(upb_pbcodecache_new(dest->ptr()), upb_pbcodecache_free) {} CodeCache(CodeCache&&) = default; CodeCache& operator=(CodeCache&&) = default; upb_pbcodecache* ptr() { return ptr_.get(); } const upb_pbcodecache* ptr() const { return ptr_.get(); } /* Whether the cache is allowed to generate machine code. Defaults to true. * There is no real reason to turn it off except for testing or if you are * having a specific problem with the JIT. * * Note that allow_jit = true does not *guarantee* that the code will be JIT * compiled. If this platform is not supported or the JIT was not compiled * in, the code may still be interpreted. */ bool allow_jit() const { return upb_pbcodecache_allowjit(ptr()); } /* This may only be called when the object is first constructed, and prior to * any code generation. */ void set_allow_jit(bool allow) { upb_pbcodecache_setallowjit(ptr(), allow); } /* Should the decoder push submessages to lazy handlers for fields that have * them? The caller should set this iff the lazy handlers expect data that is * in protobuf binary format and the caller wishes to lazy parse it. */ void set_lazy(bool lazy) { upb_pbcodecache_setlazy(ptr(), lazy); } /* Returns a DecoderMethod that can push data to the given handlers. * If a suitable method already exists, it will be returned from the cache. */ const DecoderMethodPtr Get(MessageDefPtr md) { return DecoderMethodPtr(upb_pbcodecache_get(ptr(), md.ptr())); } private: std::unique_ptr ptr_; }; #endif /* __cplusplus */ #endif /* UPB_DECODER_H_ */