File Coverage

Raw.xs
Criterion Covered Total %
statement 83 93 89.2
branch 58 90 64.4
condition n/a
subroutine n/a
pod n/a
total 141 183 77.0


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #define NEED_newSVpvn_flags
6             #define NEED_newRV_noinc
7             #define NEED_sv_2pvbyte
8             #define NEED_sv_2pv_flags
9              
10             #include "ppport.h"
11              
12             #ifndef MUTABLE_AV
13             #define MUTABLE_AV(p) ((AV *)MUTABLE_PTR(p))
14             #endif
15              
16             #ifndef MUTABLE_SV
17             #define MUTABLE_SV(p) ((SV *)MUTABLE_PTR(p))
18             #endif
19              
20             #ifndef MUTABLE_HV
21             #define MUTABLE_HV(p) ((HV *)MUTABLE_PTR(p))
22             #endif
23              
24             #include
25              
26             #if !(IVSIZE == 8 || IVSIZE == 4 || IVSIZE == 2)
27             #error "msgpack only supports IVSIZE = 8, 4 or 2"
28             #endif
29              
30             typedef struct
31             {
32             int code;
33             SV *message;
34             const char *file;
35             unsigned int line;
36             } msgpack_raw_error;
37              
38             typedef struct
39             {
40             msgpack_packer packer;
41             SV *data;
42             } msgpack_raw_packer;
43              
44             typedef struct
45             {
46             msgpack_unpacker unpacker;
47             } msgpack_raw_unpacker;
48              
49             typedef msgpack_raw_packer *Packer;
50             typedef msgpack_raw_unpacker *Unpacker;
51              
52             #define MSGPACK_NEW_OBJ(rv, package, sv) \
53             STMT_START { \
54             (rv) = sv_setref_pv (newSV(0), package, sv); \
55             } STMT_END
56              
57 0           STATIC void *msgpack_sv_to_ptr (const char *type, SV *sv, const char *file, int line)
58             {
59 0           SV *full_type = sv_2mortal (newSVpvf ("MsgPack::Raw::%s", type));
60              
61 0 0         if (!(sv_isobject (sv) && sv_derived_from (sv, SvPV_nolen (full_type))))
    0          
    0          
62 0 0         croak("Argument is not of type %s @ (%s:%d)\n",
63 0           SvPV_nolen (full_type), file, line);
64              
65 0 0         return INT2PTR (void *, SvIV ((SV *) SvRV (sv)));
66             }
67              
68             #define MSGPACK_SV_TO_PTR(type, sv) \
69             msgpack_sv_to_ptr(#type, sv, __FILE__, __LINE__)
70              
71 406           STATIC int msgpack_raw_packer_write(void *data, const char *buf, size_t len)
72             {
73 406           msgpack_raw_packer *packer = (msgpack_raw_packer *)data;
74              
75 406           sv_catpvn (packer->data, buf, len);
76              
77 406           return 0;
78             }
79              
80 377           STATIC void encode_msgpack (msgpack_raw_packer *packer, SV *sv)
81             {
82 377 100         if (SvIOKp (sv))
83             {
84 37 50         if (SvUOK (sv))
85             {
86             #if IVSIZE == 8
87 0           msgpack_pack_uint64 (&packer->packer, SvUVX (sv));
88             #elif IVSIZE == 4
89             msgpack_pack_uint32 (&packer->packer, SvUVX (sv));
90             #elif IVSIZE == 2
91             msgpack_pack_uint16 (&packer->packer, SvUVX (sv));
92             #endif
93             }
94             else
95             {
96             #if IVSIZE == 8
97 37           msgpack_pack_int64 (&packer->packer, SvIVX (sv));
98             #elif IVSIZE == 4
99             msgpack_pack_int32 (&packer->packer, SvIVX (sv));
100             #elif IVSIZE == 2
101             msgpack_pack_int16 (&packer->packer, SvIVX (sv));
102             #endif
103             }
104             }
105 340 100         else if (SvPOKp (sv))
106             {
107 25 100         if (SvUTF8 (sv))
108             {
109 5           msgpack_pack_str (&packer->packer, SvCUR (sv));
110 5           msgpack_pack_str_body (&packer->packer, SvPVX_const (sv), SvCUR (sv));
111             }
112             else
113             {
114 20           msgpack_pack_bin (&packer->packer, SvCUR (sv));
115 25           msgpack_pack_bin_body (&packer->packer, SvPVX_const (sv), SvCUR (sv));
116             }
117             }
118 315 100         else if (SvNOKp (sv))
119             {
120 2           msgpack_pack_double (&packer->packer, (double)SvNVX (sv));
121             }
122 313 100         else if (SvROK (sv))
123             {
124 50 100         if (sv_isobject (sv) && sv_derived_from (sv, "MsgPack::Raw::Bool"))
    100          
125             {
126 20 50         if (SvIV (SvRV (sv)))
    100          
127 5           msgpack_pack_true (&packer->packer);
128             else
129 5           msgpack_pack_false (&packer->packer);
130             }
131 40 100         else if (sv_isobject (sv) && sv_derived_from (sv, "MsgPack::Raw::Ext"))
    100          
132 44           {
133 14           HV *hash = MUTABLE_HV (SvRV (sv));
134 14           SV **type = hv_fetchs (hash, "type", 0);
135 14           SV **data = hv_fetchs (hash, "data", 0);
136              
137 14 50         if (!type || !SvOK (*type))
    100          
    50          
    50          
138 1           croak ("MsgPack::Raw::Ext object doesn't have a type member");
139 13 50         if (!data || !SvOK (*data))
    100          
    50          
    50          
140 1           croak ("MsgPack::Raw::Ext object doesn't have a data member");
141 12 50         if (!SvIOK(*type) || SvIV(*type) < 0 || SvIV(*type)>255)
    50          
    100          
    0          
    50          
    100          
    0          
142 2           croak ("MsgPack::Raw::Ext type invalid");
143              
144 10 50         msgpack_pack_ext (&packer->packer, SvCUR (*data), SvIV (*type));
145 10           msgpack_pack_ext_body (&packer->packer, SvPVX_const (*data), SvCUR (*data));
146             }
147 26 100         else if (SvTYPE (SvRV (sv)) == SVt_PVHV)
148             {
149 4           HV *hash = MUTABLE_HV (SvRV (sv));
150 4           I32 count = hv_iterinit (hash);
151             HE *entry;
152              
153 4           msgpack_pack_map (&packer->packer, count);
154 10 100         while ((entry = hv_iternext (hash)))
155             {
156 6           encode_msgpack (packer, hv_iterkeysv (entry));
157 6           encode_msgpack (packer, hv_iterval (hash, entry));
158             }
159             }
160 22 100         else if (SvTYPE (SvRV (sv)) == SVt_PVAV)
161             {
162 20           AV *list = MUTABLE_AV (SvRV (sv));
163 20           STRLEN i, size = av_len (list)+1;
164              
165 20           msgpack_pack_array (&packer->packer, size);
166 315 100         for (i = 0; i < size; ++i)
167             {
168 295           SV **value = av_fetch (list, i, 0);
169 295 50         if (value && *value)
    50          
170 295           encode_msgpack (packer, *value);
171             else
172 0           msgpack_pack_nil (&packer->packer);
173             }
174             }
175             else
176             {
177 4 50         croak ("encountered object '%s', Data::MessagePack doesn't allow the object",
178 4           SvPV_nolen (sv_2mortal (newRV_inc (sv))));
179             }
180             }
181 263 50         else if (!SvOK (sv))
    50          
    50          
182             {
183 263           msgpack_pack_nil (&packer->packer);
184             }
185             else
186             {
187 0           croak ("cannot pack type: %d\n", SvTYPE (sv));
188             }
189 371           }
190              
191 27           STATIC SV *decode_msgpack (msgpack_object *obj)
192             {
193 27           switch (obj->type)
194             {
195             // simple types
196 1           case MSGPACK_OBJECT_NIL: return &PL_sv_undef;
197 2           case MSGPACK_OBJECT_POSITIVE_INTEGER: return newSVuv (obj->via.u64);
198 1           case MSGPACK_OBJECT_NEGATIVE_INTEGER: return newSViv (obj->via.i64);
199             case MSGPACK_OBJECT_FLOAT32: // fall-through
200 1           case MSGPACK_OBJECT_FLOAT64: return newSVnv (obj->via.f64);
201 1           case MSGPACK_OBJECT_STR: return newSVpvn_utf8 (obj->via.str.ptr, obj->via.str.size, 1);
202 10           case MSGPACK_OBJECT_BIN: return newSVpvn (obj->via.bin.ptr, obj->via.bin.size);
203              
204             // complex types
205             case MSGPACK_OBJECT_BOOLEAN:
206             {
207 4           return sv_bless (newRV_noinc (newSViv (obj->via.boolean)),
208             gv_stashpv ("MsgPack::Raw::Bool", 0));
209             }
210             case MSGPACK_OBJECT_ARRAY:
211             {
212 3           AV *list = MUTABLE_AV (sv_2mortal (MUTABLE_SV (newAV())));
213 3           msgpack_object *items = obj->via.array.ptr;
214 3           uint32_t size = obj->via.array.size;
215              
216 8 100         while (size--)
217             {
218 5           av_push (list, decode_msgpack (items++));
219             }
220              
221 3           return newRV_inc (MUTABLE_SV (list));
222             }
223             case MSGPACK_OBJECT_MAP:
224             {
225 2           HV *hash = MUTABLE_HV (sv_2mortal (MUTABLE_SV (newHV())));
226 2           msgpack_object_kv *items = obj->via.map.ptr;
227 2           uint32_t size = obj->via.map.size;
228              
229 6 100         while (size--)
230             {
231 4           SV *key = sv_2mortal (decode_msgpack (&items->key));
232 4           SV *value = sv_2mortal (decode_msgpack (&items->val));
233              
234 4           hv_store (hash, SvPVX (key), SvCUR (key), value, 0);
235 4           SvREFCNT_inc_NN (value);
236              
237 4           ++items;
238             }
239              
240 2           return newRV_inc (MUTABLE_SV (hash));
241             }
242             case MSGPACK_OBJECT_EXT:
243             {
244 2           HV *hash = MUTABLE_HV (sv_2mortal (MUTABLE_SV (newHV())));
245 2           hv_stores (hash, "type", newSViv (obj->via.ext.type));
246 2           hv_stores (hash, "data", newSVpvn (obj->via.ext.ptr, obj->via.ext.size));
247 2           return sv_bless (newRV_inc (MUTABLE_SV (hash)),
248             gv_stashpv ("MsgPack::Raw::Ext", 0));
249             }
250              
251             default:
252 0           croak ("unknown object type: %d", obj->type);
253             }
254              
255             // unreachable
256             return &PL_sv_undef;
257             }
258              
259             MODULE = MsgPack::Raw PACKAGE = MsgPack::Raw
260              
261             INCLUDE: xs/Packer.xs
262             INCLUDE: xs/Unpacker.xs
263