27 | 27 |
#define IS_PY3 1
|
28 | 28 |
|
29 | 29 |
#endif
|
|
30 |
|
|
31 |
typedef struct {
|
|
32 |
unsigned int sort_keys;
|
|
33 |
} EncodeOptions;
|
30 | 34 |
|
31 | 35 |
// Hey Look! It's a polymorphic object structure in C!
|
32 | 36 |
|
|
994 | 998 |
return;
|
995 | 999 |
}
|
996 | 1000 |
|
997 | |
static int inner_dumps(PyObject* ob, uint8_t* out, uintptr_t* posp);
|
998 | |
|
999 | |
static int dumps_dict(PyObject* ob, uint8_t* out, uintptr_t* posp) {
|
|
1001 |
static int inner_dumps(EncodeOptions *optp, PyObject* ob, uint8_t* out, uintptr_t* posp);
|
|
1002 |
|
|
1003 |
static int dumps_dict(EncodeOptions *optp, PyObject* ob, uint8_t* out, uintptr_t* posp) {
|
1000 | 1004 |
uintptr_t pos = *posp;
|
1001 | |
Py_ssize_t dictiter = 0;
|
|
1005 |
Py_ssize_t dictlen = PyDict_Size(ob);
|
1002 | 1006 |
PyObject* key;
|
1003 | 1007 |
PyObject* val;
|
1004 | |
Py_ssize_t dictlen = PyDict_Size(ob);
|
1005 | 1008 |
int err;
|
|
1009 |
|
1006 | 1010 |
tag_aux_out(CBOR_MAP, dictlen, out, &pos);
|
1007 | |
while (PyDict_Next(ob, &dictiter, &key, &val)) {
|
1008 | |
err = inner_dumps(key, out, &pos);
|
1009 | |
if (err != 0) { return err; }
|
1010 | |
err = inner_dumps(val, out, &pos);
|
1011 | |
if (err != 0) { return err; }
|
1012 | |
}
|
|
1011 |
|
|
1012 |
if (optp->sort_keys) {
|
|
1013 |
Py_ssize_t index = 0;
|
|
1014 |
PyObject* keylist = PyDict_Keys(ob);
|
|
1015 |
PyList_Sort(keylist);
|
|
1016 |
|
|
1017 |
//fprintf(stderr, "sortking keys\n");
|
|
1018 |
for (index = 0; index < PyList_Size(keylist); index++) {
|
|
1019 |
key = PyList_GetItem(keylist, index); // Borrowed ref
|
|
1020 |
val = PyDict_GetItem(ob, key); // Borrowed ref
|
|
1021 |
err = inner_dumps(optp, key, out, &pos);
|
|
1022 |
if (err != 0) { return err; }
|
|
1023 |
err = inner_dumps(optp, val, out, &pos);
|
|
1024 |
if (err != 0) { return err; }
|
|
1025 |
}
|
|
1026 |
Py_DECREF(keylist);
|
|
1027 |
} else {
|
|
1028 |
Py_ssize_t dictiter = 0;
|
|
1029 |
//fprintf(stderr, "unsorted keys\n");
|
|
1030 |
while (PyDict_Next(ob, &dictiter, &key, &val)) {
|
|
1031 |
err = inner_dumps(optp, key, out, &pos);
|
|
1032 |
if (err != 0) { return err; }
|
|
1033 |
err = inner_dumps(optp, val, out, &pos);
|
|
1034 |
if (err != 0) { return err; }
|
|
1035 |
}
|
|
1036 |
}
|
|
1037 |
|
1013 | 1038 |
*posp = pos;
|
1014 | 1039 |
return 0;
|
1015 | 1040 |
}
|
1016 | 1041 |
|
1017 | 1042 |
|
1018 | |
static void dumps_bignum(uint8_t tag, PyObject* val, uint8_t* out, uintptr_t* posp) {
|
|
1043 |
static void dumps_bignum(EncodeOptions *optp, uint8_t tag, PyObject* val, uint8_t* out, uintptr_t* posp) {
|
1019 | 1044 |
uintptr_t pos = (posp != NULL) ? *posp : 0;
|
1020 | 1045 |
PyObject* eight = PyLong_FromLong(8);
|
1021 | 1046 |
PyObject* bytemask = NULL;
|
|
1065 | 1090 |
*posp = pos;
|
1066 | 1091 |
}
|
1067 | 1092 |
|
1068 | |
static int dumps_tag(PyObject* ob, uint8_t* out, uintptr_t* posp) {
|
|
1093 |
static int dumps_tag(EncodeOptions *optp, PyObject* ob, uint8_t* out, uintptr_t* posp) {
|
1069 | 1094 |
uintptr_t pos = (posp != NULL) ? *posp : 0;
|
1070 | 1095 |
int err = 0;
|
1071 | 1096 |
|
|
1083 | 1108 |
long val = PyInt_AsLong(tag_num);
|
1084 | 1109 |
if (val > 0) {
|
1085 | 1110 |
tag_aux_out(CBOR_TAG, val, out, &pos);
|
1086 | |
err = inner_dumps(tag_value, out, &pos);
|
|
1111 |
err = inner_dumps(optp, tag_value, out, &pos);
|
1087 | 1112 |
} else {
|
1088 | 1113 |
PyErr_Format(PyExc_ValueError, "tag cannot be a negative int: %ld", val);
|
1089 | 1114 |
err = -1;
|
|
1096 | 1121 |
if (overflow == 0) {
|
1097 | 1122 |
if (val >= 0) {
|
1098 | 1123 |
tag_aux_out(CBOR_TAG, val, out, &pos);
|
1099 | |
err = inner_dumps(tag_value, out, &pos);
|
|
1124 |
err = inner_dumps(optp, tag_value, out, &pos);
|
1100 | 1125 |
} else {
|
1101 | 1126 |
PyErr_Format(PyExc_ValueError, "tag cannot be a negative long: %lld", val);
|
1102 | 1127 |
err = -1;
|
|
1125 | 1150 |
|
1126 | 1151 |
// With out=NULL it just counts the length.
|
1127 | 1152 |
// return err, 0=OK
|
1128 | |
static int inner_dumps(PyObject* ob, uint8_t* out, uintptr_t* posp) {
|
|
1153 |
static int inner_dumps(EncodeOptions *optp, PyObject* ob, uint8_t* out, uintptr_t* posp) {
|
1129 | 1154 |
uintptr_t pos = (posp != NULL) ? *posp : 0;
|
1130 | 1155 |
|
1131 | |
if (PyBool_Check(ob)) {
|
|
1156 |
if (ob == Py_None) {
|
|
1157 |
if (out != NULL) {
|
|
1158 |
out[pos] = CBOR_NULL;
|
|
1159 |
}
|
|
1160 |
pos += 1;
|
|
1161 |
} else if (PyBool_Check(ob)) {
|
1132 | 1162 |
if (out != NULL) {
|
1133 | 1163 |
if (PyObject_IsTrue(ob)) {
|
1134 | 1164 |
out[pos] = CBOR_TRUE;
|
|
1137 | 1167 |
}
|
1138 | 1168 |
}
|
1139 | 1169 |
pos += 1;
|
1140 | |
} else if (ob == Py_None) {
|
1141 | |
if (out != NULL) {
|
1142 | |
out[pos] = CBOR_NULL;
|
1143 | |
}
|
1144 | |
pos += 1;
|
1145 | 1170 |
} else if (PyDict_Check(ob)) {
|
1146 | |
int err = dumps_dict(ob, out, &pos);
|
|
1171 |
int err = dumps_dict(optp, ob, out, &pos);
|
1147 | 1172 |
if (err != 0) { return err; }
|
1148 | 1173 |
} else if (PyList_Check(ob)) {
|
1149 | 1174 |
Py_ssize_t i;
|
1150 | 1175 |
Py_ssize_t listlen = PyList_Size(ob);
|
1151 | 1176 |
tag_aux_out(CBOR_ARRAY, listlen, out, &pos);
|
1152 | 1177 |
for (i = 0; i < listlen; i++) {
|
1153 | |
int err = inner_dumps(PyList_GetItem(ob, i), out, &pos);
|
|
1178 |
int err = inner_dumps(optp, PyList_GetItem(ob, i), out, &pos);
|
1154 | 1179 |
if (err != 0) { return err; }
|
1155 | 1180 |
}
|
1156 | 1181 |
} else if (PyTuple_Check(ob)) {
|
|
1158 | 1183 |
Py_ssize_t listlen = PyTuple_Size(ob);
|
1159 | 1184 |
tag_aux_out(CBOR_ARRAY, listlen, out, &pos);
|
1160 | 1185 |
for (i = 0; i < listlen; i++) {
|
1161 | |
int err = inner_dumps(PyTuple_GetItem(ob, i), out, &pos);
|
|
1186 |
int err = inner_dumps(optp, PyTuple_GetItem(ob, i), out, &pos);
|
1162 | 1187 |
if (err != 0) { return err; }
|
1163 | 1188 |
}
|
1164 | 1189 |
// TODO: accept other enumerables and emit a variable length array
|
|
1187 | 1212 |
PyObject* minusone = PyLong_FromLongLong(-1L);
|
1188 | 1213 |
PyObject* val = PyNumber_Subtract(minusone, ob);
|
1189 | 1214 |
Py_DECREF(minusone);
|
1190 | |
dumps_bignum(CBOR_TAG_NEGBIGNUM, val, out, &pos);
|
|
1215 |
dumps_bignum(optp, CBOR_TAG_NEGBIGNUM, val, out, &pos);
|
1191 | 1216 |
Py_DECREF(val);
|
1192 | 1217 |
} else {
|
1193 | 1218 |
// BIG INT
|
1194 | |
dumps_bignum(CBOR_TAG_BIGNUM, ob, out, &pos);
|
|
1219 |
dumps_bignum(optp, CBOR_TAG_BIGNUM, ob, out, &pos);
|
1195 | 1220 |
}
|
1196 | 1221 |
}
|
1197 | 1222 |
} else if (PyFloat_Check(ob)) {
|
|
1218 | 1243 |
{
|
1219 | 1244 |
PyObject* tag_class = getCborTagClass();
|
1220 | 1245 |
if (PyObject_IsInstance(ob, tag_class)) {
|
1221 | |
int err = dumps_tag(ob, out, &pos);
|
|
1246 |
int err = dumps_tag(optp, ob, out, &pos);
|
1222 | 1247 |
if (err != 0) { return err; }
|
1223 | 1248 |
handled = 1;
|
1224 | 1249 |
}
|
|
1246 | 1271 |
return 0;
|
1247 | 1272 |
}
|
1248 | 1273 |
|
|
1274 |
static int _dumps_kwargs(EncodeOptions *optp, PyObject* kwargs) {
|
|
1275 |
if (kwargs == NULL) {
|
|
1276 |
} else if (!PyDict_Check(kwargs)) {
|
|
1277 |
PyErr_Format(PyExc_ValueError, "kwargs not dict: %R\n", kwargs);
|
|
1278 |
return 0;
|
|
1279 |
} else {
|
|
1280 |
PyObject* sort_keys = PyDict_GetItemString(kwargs, "sort_keys"); // Borrowed ref
|
|
1281 |
if (sort_keys != NULL) {
|
|
1282 |
optp->sort_keys = PyObject_IsTrue(sort_keys);
|
|
1283 |
//fprintf(stderr, "sort_keys=%d\n", optp->sort_keys);
|
|
1284 |
}
|
|
1285 |
}
|
|
1286 |
return 1;
|
|
1287 |
}
|
|
1288 |
|
1249 | 1289 |
static PyObject*
|
1250 | |
cbor_dumps(PyObject* noself, PyObject* args) {
|
|
1290 |
cbor_dumps(PyObject* noself, PyObject* args, PyObject* kwargs) {
|
|
1291 |
|
1251 | 1292 |
PyObject* ob;
|
|
1293 |
EncodeOptions opts = {0};
|
|
1294 |
EncodeOptions *optp = &opts;
|
1252 | 1295 |
is_big_endian();
|
1253 | 1296 |
if (PyType_IsSubtype(Py_TYPE(args), &PyList_Type)) {
|
1254 | 1297 |
ob = PyList_GetItem(args, 0);
|
|
1257 | 1300 |
} else {
|
1258 | 1301 |
PyErr_Format(PyExc_ValueError, "args not list or tuple: %R\n", args);
|
1259 | 1302 |
return NULL;
|
|
1303 |
}
|
|
1304 |
if (ob == NULL) {
|
|
1305 |
return NULL;
|
|
1306 |
}
|
|
1307 |
|
|
1308 |
if (!_dumps_kwargs(optp, kwargs)) {
|
|
1309 |
return NULL;
|
1260 | 1310 |
}
|
1261 | 1311 |
|
1262 | 1312 |
{
|
|
1267 | 1317 |
int err;
|
1268 | 1318 |
|
1269 | 1319 |
// first pass just to count length
|
1270 | |
err = inner_dumps(ob, NULL, &pos);
|
|
1320 |
err = inner_dumps(optp, ob, NULL, &pos);
|
1271 | 1321 |
if (err != 0) {
|
1272 | 1322 |
return NULL;
|
1273 | 1323 |
}
|
|
1280 | 1330 |
return NULL;
|
1281 | 1331 |
}
|
1282 | 1332 |
|
1283 | |
err = inner_dumps(ob, out, NULL);
|
|
1333 |
err = inner_dumps(optp, ob, out, NULL);
|
1284 | 1334 |
if (err != 0) {
|
1285 | 1335 |
PyMem_Free(out);
|
1286 | 1336 |
return NULL;
|
|
1294 | 1344 |
}
|
1295 | 1345 |
|
1296 | 1346 |
static PyObject*
|
1297 | |
cbor_dump(PyObject* noself, PyObject* args) {
|
|
1347 |
cbor_dump(PyObject* noself, PyObject* args, PyObject *kwargs) {
|
1298 | 1348 |
// args should be (obj, fp)
|
1299 | 1349 |
PyObject* ob;
|
1300 | 1350 |
PyObject* fp;
|
|
1351 |
EncodeOptions opts = {0};
|
|
1352 |
EncodeOptions *optp = &opts;
|
1301 | 1353 |
|
1302 | 1354 |
is_big_endian();
|
1303 | 1355 |
if (PyType_IsSubtype(Py_TYPE(args), &PyList_Type)) {
|
|
1310 | 1362 |
PyErr_Format(PyExc_ValueError, "args not list or tuple: %R\n", args);
|
1311 | 1363 |
return NULL;
|
1312 | 1364 |
}
|
|
1365 |
if ((ob == NULL) || (fp == NULL)) {
|
|
1366 |
return NULL;
|
|
1367 |
}
|
|
1368 |
|
|
1369 |
if (!_dumps_kwargs(optp, kwargs)) {
|
|
1370 |
return NULL;
|
|
1371 |
}
|
1313 | 1372 |
|
1314 | 1373 |
{
|
1315 | 1374 |
// TODO: make this smarter, right now it is justt fp.write(dumps(ob))
|
|
1319 | 1378 |
int err;
|
1320 | 1379 |
|
1321 | 1380 |
// first pass just to count length
|
1322 | |
err = inner_dumps(ob, NULL, &pos);
|
|
1381 |
err = inner_dumps(optp, ob, NULL, &pos);
|
1323 | 1382 |
if (err != 0) {
|
1324 | 1383 |
return NULL;
|
1325 | 1384 |
}
|
|
1332 | 1391 |
return NULL;
|
1333 | 1392 |
}
|
1334 | 1393 |
|
1335 | |
err = inner_dumps(ob, out, NULL);
|
|
1394 |
err = inner_dumps(optp, ob, out, NULL);
|
1336 | 1395 |
if (err != 0) {
|
1337 | 1396 |
PyMem_Free(out);
|
1338 | 1397 |
return NULL;
|
|
1376 | 1435 |
static PyMethodDef CborMethods[] = {
|
1377 | 1436 |
{"loads", cbor_loads, METH_VARARGS,
|
1378 | 1437 |
"parse cbor from data buffer to objects"},
|
1379 | |
{"dumps", cbor_dumps, METH_VARARGS,
|
|
1438 |
{"dumps", (PyCFunction)cbor_dumps, METH_VARARGS|METH_KEYWORDS,
|
1380 | 1439 |
"serialize python object to bytes"},
|
1381 | 1440 |
{"load", cbor_load, METH_VARARGS,
|
1382 | 1441 |
"Parse cbor from data buffer to objects.\n"
|
1383 | 1442 |
"Takes a file-like object capable of .read(N)\n"},
|
1384 | |
{"dump", cbor_dump, METH_VARARGS,
|
|
1443 |
{"dump", (PyCFunction)cbor_dump, METH_VARARGS|METH_KEYWORDS,
|
1385 | 1444 |
"Serialize python object to bytes.\n"
|
1386 | 1445 |
"dump(obj, fp)\n"
|
1387 | 1446 |
"obj: object to output; fp: file-like object to .write() to\n"},
|