File Coverage

srl_reader_decompress.h
Criterion Covered Total %
statement 46 51 90.2
branch 13 24 54.1
condition n/a
subroutine n/a
pod n/a
total 59 75 78.6


line stmt bran cond sub pod time code
1             #ifndef SRL_READER_DECOMPRESS_H_
2             #define SRL_READER_DECOMPRESS_H_
3              
4             #include "srl_inline.h"
5             #include "srl_common.h"
6             #include "srl_reader.h"
7             #include "srl_reader_error.h"
8             #include "srl_reader_varint.h"
9             #include "srl_protocol.h"
10              
11             #if defined(HAVE_CSNAPPY)
12             #include
13             #else
14             /* PLEASE READ!!!
15             * Since the decompression code was migrated to this header file
16             * and it's not a good practise to include C files into headers (actually, doing so
17             * cases 'duplicate symbol' errors in Sereal::Path, expected huh?) and I didn't
18             * found right way how to compile snappy's implementation files and link them
19             * (main problem is that snappy files in a subdirectory) I'm only including
20             * header file here and a dev should include C file in his code.
21             *
22             * It should be something like this:
23             * #if !defined(HAVE_CSNAPPY)
24             * # include "snappy/csnappy_decompress.c"
25             * #endif
26             */
27             #include "snappy/csnappy.h"
28             #endif
29              
30             #if defined(HAVE_ZSTD)
31             #include
32             #else
33             #include "zstd/zstd.h"
34             #endif
35              
36             #if defined(HAVE_MINIZ)
37             #include
38             #else
39             #include "miniz.h"
40             #endif
41              
42             /* Creates a new buffer of size header_len + body_len + 1 and swaps it into place
43             * of the current reader's buffer. Sets reader position to right after the
44             * header and makes the reader state internally consistent. The buffer is
45             * owned by a mortal SV which is returned. */
46             /* TODO reuse the buffer */
47              
48             SRL_STATIC_INLINE SV *
49 88025           srl_realloc_empty_buffer(pTHX_ srl_reader_buffer_t *buf,
50             const STRLEN header_len,
51             const STRLEN body_len)
52             {
53             SV *b_sv;
54             srl_reader_char_ptr b;
55              
56             /* Let perl clean this up. Yes, it's not the most efficient thing
57             * ever, but it's just one mortal per full decompression, so not
58             * a bottle-neck. */
59 88025           b_sv = sv_2mortal( newSV(header_len + body_len + 1 ));
60 88025           b = (srl_reader_char_ptr) SvPVX(b_sv);
61              
62 88025           buf->start = b;
63 88025           buf->pos = b + header_len;
64 88025           buf->end = buf->pos + body_len;
65              
66             /*SRL_RDR_UPDATE_BODY_POS(buf); // XXX caller *MUST* call by himself/herself */
67 88025           return b_sv;
68             }
69              
70             /* Decompress a Snappy-compressed document body and put the resulting document
71             * body back in the place of the old compressed blob. The function internaly
72             * creates temporary buffer which is owned by mortal SV. If the caller is
73             * interested in keeping the buffer around for longer time, it should pass
74             * buf_owner parameter and unmortalize it.
75             * The caller *MUST* call SRL_RDR_UPDATE_BODY_POS right after existing from this function. */
76              
77             SRL_STATIC_INLINE UV
78 58322           srl_decompress_body_snappy(pTHX_ srl_reader_buffer_t *buf, U8 encoding_flags, SV** buf_owner)
79             {
80             SV *buf_sv;
81             int header_len;
82             int decompress_ok;
83             uint32_t dest_len;
84             UV bytes_consumed;
85              
86             srl_reader_char_ptr old_pos;
87 58322           const STRLEN sereal_header_len = (STRLEN) SRL_RDR_POS_OFS(buf);
88 58322           const STRLEN compressed_packet_len =
89             encoding_flags == SRL_PROTOCOL_ENCODING_SNAPPY_INCREMENTAL
90             ? (STRLEN) srl_read_varint_uv_length(aTHX_ buf, " while reading compressed packet size")
91 58322 100         : (STRLEN) SRL_RDR_SPACE_LEFT(buf);
92              
93             /* All bufl's above here, or we break C89 compilers */
94 58322           old_pos = buf->pos;
95 58322           bytes_consumed = compressed_packet_len + SRL_RDR_POS_OFS(buf);
96 58322           header_len = csnappy_get_uncompressed_length((char *)buf->pos,
97             compressed_packet_len,
98             &dest_len);
99              
100 58322 50         if (header_len == CSNAPPY_E_HEADER_BAD)
101 0           SRL_RDR_ERROR(buf, "Invalid Snappy header in Snappy-compressed Sereal packet");
102              
103             /* Allocate output buffer and swap it into place within the bufoder. */
104 58322           buf_sv = srl_realloc_empty_buffer(aTHX_ buf, sereal_header_len, dest_len);
105 58322 50         if (buf_owner) *buf_owner = buf_sv;
106              
107 58322           decompress_ok = csnappy_decompress_noheader((char *)(old_pos + header_len),
108             compressed_packet_len - header_len,
109 58322           (char *)buf->pos,
110             &dest_len);
111              
112 58322 50         if (expect_false( decompress_ok != 0 )) {
113 0           SRL_RDR_ERRORf1(buf, "Snappy decompression of Sereal packet payload failed with error %i!",
114             decompress_ok);
115             }
116              
117 58322           return bytes_consumed;
118             }
119              
120             /* Decompress a zlib-compressed document body and put the resulting
121             * document body back in the place of the old compressed blob. The function
122             * internaly creates temporary buffer which is owned by mortal SV. If the
123             * caller is interested in keeping the buffer around for longer time, it should
124             * pass buf_owner parameter and unmortalize it.
125             * The caller *MUST* call SRL_RDR_UPDATE_BODY_POS right after existing from this function. */
126              
127             SRL_STATIC_INLINE UV
128 20162           srl_decompress_body_zlib(pTHX_ srl_reader_buffer_t *buf, SV** buf_owner)
129             {
130             SV *buf_sv;
131             mz_ulong tmp;
132             int decompress_ok;
133             UV bytes_consumed;
134             srl_reader_char_ptr old_pos;
135 20162           const STRLEN sereal_header_len = (STRLEN)SRL_RDR_POS_OFS(buf);
136 20162           const STRLEN uncompressed_packet_len = (STRLEN)srl_read_varint_uv(aTHX_ buf);
137 20162           const STRLEN compressed_packet_len =
138             (STRLEN)srl_read_varint_uv_length(aTHX_ buf, " while reading compressed packet size");
139              
140 20162 50         SRL_RDR_ASSERT_SPACE(buf, compressed_packet_len, " while reading compressed packet");
    50          
    50          
141              
142             /* All decl's above here, or we break C89 compilers */
143 20162           old_pos = buf->pos;
144 20162           bytes_consumed = compressed_packet_len + SRL_RDR_POS_OFS(buf);
145              
146             /* Allocate output buffer and swap it into place within the decoder. */
147 20162           buf_sv = srl_realloc_empty_buffer(aTHX_ buf, sereal_header_len, uncompressed_packet_len);
148 20162 50         if (buf_owner) *buf_owner = buf_sv;
149              
150 20162           tmp = uncompressed_packet_len;
151 20162           decompress_ok = mz_uncompress((unsigned char *)buf->pos,
152             &tmp, old_pos, compressed_packet_len);
153              
154 20162 50         if (expect_false( decompress_ok != Z_OK )) {
155 0           SRL_RDR_ERRORf1(buf, "ZLIB decompression of Sereal packet payload failed with error %i!", decompress_ok);
156             }
157              
158 20162           return bytes_consumed;
159             }
160              
161             /* Decompress a zstd-compressed document body and put the resulting document
162             * body back in the place of the old compressed blob. The function internaly
163             * creates temporary buffer which is owned by mortal SV. If the caller is
164             * interested in keeping the buffer around for longer time, it should pass
165             * buf_owner parameter and unmortalize it. The caller *MUST* call
166             * SRL_RDR_UPDATE_BODY_POS right after existing from this function. */
167              
168             SRL_STATIC_INLINE UV
169 9541           srl_decompress_body_zstd(pTHX_ srl_reader_buffer_t *buf, SV** buf_owner)
170             {
171             SV *buf_sv;
172             UV bytes_consumed;
173             size_t decompress_code;
174              
175             srl_reader_char_ptr old_pos;
176             unsigned long long uncompressed_packet_len;
177 9541           const STRLEN sereal_header_len = (STRLEN) SRL_RDR_POS_OFS(buf);
178 9541           const STRLEN compressed_packet_len = (STRLEN) srl_read_varint_uv_length(aTHX_ buf,
179             " while reading compressed packet size");
180              
181             /* All bufl's above here, or we break C89 compilers */
182 9541           old_pos = buf->pos;
183 9541           bytes_consumed = compressed_packet_len + SRL_RDR_POS_OFS(buf);
184              
185 9541           uncompressed_packet_len = ZSTD_getDecompressedSize((const void *)buf->pos, (size_t) compressed_packet_len);
186 9541 50         if (expect_false(uncompressed_packet_len == 0))
187 0           SRL_RDR_ERROR(buf, "Invalid zstd packet with unknown uncompressed size");
188              
189             /* Allocate output buffer and swap it into place within the decoder. */
190 9541           buf_sv = srl_realloc_empty_buffer(aTHX_ buf, sereal_header_len, (STRLEN) uncompressed_packet_len);
191 9541 50         if (buf_owner) *buf_owner = buf_sv;
192              
193 9541           decompress_code = ZSTD_decompress((void *)buf->pos, (size_t) uncompressed_packet_len,
194             (void *)old_pos, (size_t) compressed_packet_len);
195              
196 9541 50         if (expect_false( ZSTD_isError(decompress_code) )) {
197 0           SRL_RDR_ERRORf1(buf, "Zstd decompression of Sereal packet payload failed with error %s!",
198             ZSTD_getErrorName(decompress_code));
199             }
200              
201 9541           return bytes_consumed;
202             }
203              
204             #endif