blob: c936428cd93c897fd7e8a5bbdbe17666740d498e [file] [log] [blame]
Roger Meier6cf0ffc2014-04-05 00:45:42 +02001//
2// Licensed to the Apache Software Foundation (ASF) under one
3// or more contributor license agreements. See the NOTICE file
4// distributed with this work for additional information
5// regarding copyright ownership. The ASF licenses this file
6// to you under the Apache License, Version 2.0 (the
7// "License"); you may not use this file except in compliance
8// with the License. You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing,
13// software distributed under the License is distributed on an
14// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15// KIND, either express or implied. See the License for the
16// specific language governing permissions and limitations
17// under the License.
18//
19
20#include <lua.h>
21#include <lauxlib.h>
22#include <string.h>
23#include <inttypes.h>
24#include <netinet/in.h>
25
26extern int64_t lualongnumber_checklong(lua_State *L, int index);
27extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val);
28
29// host order to network order (64-bit)
30static int64_t T_htonll(uint64_t data) {
31 uint32_t d1 = htonl((uint32_t)data);
32 uint32_t d2 = htonl((uint32_t)(data >> 32));
33 return ((uint64_t)d1 << 32) + (uint64_t)d2;
34}
35
36// network order to host order (64-bit)
37static int64_t T_ntohll(uint64_t data) {
38 uint32_t d1 = ntohl((uint32_t)data);
39 uint32_t d2 = ntohl((uint32_t)(data >> 32));
40 return ((uint64_t)d1 << 32) + (uint64_t)d2;
41}
42
43/**
44 * bpack(type, data)
45 * c - Signed Byte
46 * s - Signed Short
47 * i - Signed Int
48 * l - Signed Long
49 * d - Double
50 */
51static int l_bpack(lua_State *L) {
52 const char *code = luaL_checkstring(L, 1);
53 luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character.");
54 luaL_Buffer buf;
55 luaL_buffinit(L, &buf);
56
57 switch (code[0]) {
58 case 'c': {
59 int8_t data = luaL_checknumber(L, 2);
60 luaL_addlstring(&buf, (void*)&data, sizeof(data));
61 break;
62 }
63 case 's': {
64 int16_t data = luaL_checknumber(L, 2);
65 data = (int16_t)htons(data);
66 luaL_addlstring(&buf, (void*)&data, sizeof(data));
67 break;
68 }
69 case 'i': {
70 int32_t data = luaL_checkinteger(L, 2);
71 data = (int32_t)htonl(data);
72 luaL_addlstring(&buf, (void*)&data, sizeof(data));
73 break;
74 }
75 case 'l': {
76 int64_t data = lualongnumber_checklong(L, 2);
77 data = (int64_t)T_htonll(data);
78 luaL_addlstring(&buf, (void*)&data, sizeof(data));
79 break;
80 }
81 case 'd': {
82 double data = luaL_checknumber(L, 2);
83 luaL_addlstring(&buf, (void*)&data, sizeof(data));
84 break;
85 }
86 default:
87 luaL_argcheck(L, 0, 0, "Invalid format code.");
88 }
89
90 luaL_pushresult(&buf);
91 return 1;
92}
93
94/**
95 * bunpack(type, data)
96 * c - Signed Byte
97 * s - Signed Short
98 * i - Signed Int
99 * l - Signed Long
100 * d - Double
101 */
102static int l_bunpack(lua_State *L) {
103 const char *code = luaL_checkstring(L, 1);
104 luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character.");
105 const char *data = luaL_checkstring(L, 2);
106 size_t len = lua_rawlen(L, 2);
107
108 switch (code[0]) {
109 case 'c': {
110 int8_t val;
111 luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
112 memcpy(&val, data, sizeof(val));
113 lua_pushnumber(L, val);
114 break;
115 }
116 case 's': {
117 int16_t val;
118 luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
119 memcpy(&val, data, sizeof(val));
120 val = (int16_t)ntohs(val);
121 lua_pushnumber(L, val);
122 break;
123 }
124 case 'i': {
125 int32_t val;
126 luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
127 memcpy(&val, data, sizeof(val));
128 val = (int32_t)ntohl(val);
129 lua_pushnumber(L, val);
130 break;
131 }
132 case 'l': {
133 int64_t val;
134 luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
135 memcpy(&val, data, sizeof(val));
136 val = (int64_t)T_ntohll(val);
137 lualongnumber_pushlong(L, &val);
138 break;
139 }
140 case 'd': {
141 double val;
142 luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
143 memcpy(&val, data, sizeof(val));
144 lua_pushnumber(L, val);
145 break;
146 }
147 default:
148 luaL_argcheck(L, 0, 0, "Invalid format code.");
149 }
150 return 1;
151}
152
153static const struct luaL_Reg lua_bpack[] = {
154 {"bpack", l_bpack},
155 {"bunpack", l_bunpack},
156 {NULL, NULL}
157};
158
159int luaopen_libluabpack(lua_State *L) {
160 luaL_register(L, "libluabpack", lua_bpack);
161 return 1;
162}