|
|
@@ -461,6 +461,93 @@ DEFINE_PERCHAR(tolower, b_ascii_tolower(ch))
|
|
|
DEFINE_PERCHAR(toupper, b_ascii_toupper(ch))
|
|
|
|
|
|
|
|
|
+// struct_encode
|
|
|
+
|
|
|
+static int struct_encode_single (NCDCall call, ExpString *estr, NCDValRef encoding, NCDValRef value)
|
|
|
+{
|
|
|
+ uintmax_t val_int;
|
|
|
+ if (!ncd_read_uintmax(value, &val_int)) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "struct_encode: value must be an integer");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ int big;
|
|
|
+ int size;
|
|
|
+ if ((big = NCDVal_StringEquals(encoding, "u8"))) {
|
|
|
+ size = 1;
|
|
|
+ } else if ((big = NCDVal_StringEquals(encoding, "u16b")) || NCDVal_StringEquals(encoding, "u16l")) {
|
|
|
+ size = 2;
|
|
|
+ } else if ((big = NCDVal_StringEquals(encoding, "u32b")) || NCDVal_StringEquals(encoding, "u32l")) {
|
|
|
+ size = 4;
|
|
|
+ } else if ((big = NCDVal_StringEquals(encoding, "u64b")) || NCDVal_StringEquals(encoding, "u64l")) {
|
|
|
+ size = 8;
|
|
|
+ } else {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "struct_encode: invalid encoding specified");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ uint8_t results[8];
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
+ results[big ? (size - 1 - i) : i] = val_int;
|
|
|
+ val_int >>= 8;
|
|
|
+ }
|
|
|
+ if (val_int > 0) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "struct_encode: value is out of range");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (!ExpString_AppendBinaryMr(estr, MemRef_Make((char const *)results, size))) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "ExpString_AppendBinaryMr failed");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static void struct_encode_eval (NCDCall call)
|
|
|
+{
|
|
|
+ if (NCDCall_ArgCount(&call) != 1) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "struct_encode: need one argument");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+ NCDValRef arg = NCDCall_EvalArg(&call, 0, NCDCall_ResMem(&call));
|
|
|
+ if (NCDVal_IsInvalid(arg)) {
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+ if (!NCDVal_IsList(arg)) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "struct_encode: argument must be a list");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+ ExpString estr;
|
|
|
+ if (!ExpString_Init(&estr)) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "ExpString_Init failed");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+ size_t count = NCDVal_ListCount(arg);
|
|
|
+ for (size_t i = 0; i < count; i++) {
|
|
|
+ NCDValRef elem = NCDVal_ListGet(arg, i);
|
|
|
+ if (!NCDVal_IsList(elem)) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "struct_encode: element must be a list");
|
|
|
+ goto fail1;
|
|
|
+ }
|
|
|
+ NCDValRef encoding;
|
|
|
+ NCDValRef value;
|
|
|
+ if (!NCDVal_ListRead(elem, 2, &encoding, &value)) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "struct_encode: element list must have two elements");
|
|
|
+ goto fail1;
|
|
|
+ }
|
|
|
+ if (!NCDVal_IsString(encoding)) {
|
|
|
+ FunctionLog(&call, BLOG_ERROR, "struct_encode: encoding must be a string");
|
|
|
+ goto fail1;
|
|
|
+ }
|
|
|
+ if (!struct_encode_single(call, &estr, encoding, value)) {
|
|
|
+ goto fail1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ NCDCall_SetResult(&call, NCDVal_NewStringBinMr(NCDCall_ResMem(&call), ExpString_GetMr(&estr)));
|
|
|
+fail1:
|
|
|
+ ExpString_Free(&estr);
|
|
|
+fail0:
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static struct NCDModuleFunction const functions[] = {
|
|
|
{
|
|
|
.func_name = "error",
|
|
|
@@ -564,6 +651,9 @@ static struct NCDModuleFunction const functions[] = {
|
|
|
}, {
|
|
|
.func_name = "toupper",
|
|
|
.func_eval = perchar_toupper_eval
|
|
|
+ }, {
|
|
|
+ .func_name = "struct_encode",
|
|
|
+ .func_eval = struct_encode_eval
|
|
|
}, {
|
|
|
.func_name = NULL
|
|
|
}
|