summaryrefslogtreecommitdiff
path: root/src/stringprep/stringprep_drv.c
diff options
context:
space:
mode:
authorAlexey Shchepin <alexey@process-one.net>2003-09-26 18:55:01 +0000
committerAlexey Shchepin <alexey@process-one.net>2003-09-26 18:55:01 +0000
commit8888e2528ca55a9c1c7461f850c6cad2e9c66f22 (patch)
tree0d9482dfab365b3831521b2fe054a68cce0b0347 /src/stringprep/stringprep_drv.c
parent* src/mod_muc/mod_muc_room.erl: Debug output switched off (diff)
* src/stringprep/: Support for stringprep (not completed yet)
* src/mod_muc/mod_muc.erl: Replaced io:format calls to ?DEBUG ones SVN Revision: 141
Diffstat (limited to '')
-rw-r--r--src/stringprep/stringprep_drv.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/src/stringprep/stringprep_drv.c b/src/stringprep/stringprep_drv.c
new file mode 100644
index 00000000..e6eb3d37
--- /dev/null
+++ b/src/stringprep/stringprep_drv.c
@@ -0,0 +1,147 @@
+/* $Id$ */
+
+#include <stdio.h>
+#include <erl_driver.h>
+#include <ei.h>
+#include <iconv.h>
+
+#include "uni_data.c"
+
+typedef struct {
+ ErlDrvPort port;
+} stringprep_data;
+
+
+static ErlDrvData stringprep_erl_start(ErlDrvPort port, char *buff)
+{
+ stringprep_data* d = (stringprep_data*)driver_alloc(sizeof(stringprep_data));
+ d->port = port;
+
+ set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
+
+ return (ErlDrvData)d;
+}
+
+static void stringprep_erl_stop(ErlDrvData handle)
+{
+ driver_free((char*)handle);
+}
+
+static int stringprep_erl_control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, int len,
+ char **rbuf, int rlen)
+{
+ int i, j=0;
+ unsigned char c;
+ int bad = 0;
+ int uc, ruc;
+ int size;
+ int info;
+ ErlDrvBinary *b;
+ char *rstring;
+
+ size = len;
+
+ rstring = malloc(size);
+
+ for(i=0; i < len; i++)
+ {
+ c = buf[i];
+ if(c < 0x80) {
+ uc = c;
+ } else if(c < 0xC0) {
+ bad = 1;
+ } else if(c < 0xE0) {
+ if(i+1 < len && (buf[i+1] & 0xC0) == 0x80) {
+ uc = ((c & 0x1F) << 6) | (buf[i+1] & 0x3F);
+ i++;
+ } else {
+ bad = 1;
+ }
+ } else if(c < 0xF0) {
+ if(i+2 < len && (buf[i+1] & 0xC0) == 0x80 &&
+ (buf[i+2] & 0xC0) == 0x80) {
+ uc = ((c & 0x1F) << 12) | ((buf[i+1] & 0x1F) << 6)
+ | (buf[i+2] & 0x3F);
+ i += 2;
+ } else {
+ bad = 1;
+ }
+ } else {
+ // TODO
+ bad = 1;
+ }
+
+ if(bad) {
+ *rbuf = (char*)(b = driver_alloc_binary(1));
+ b->orig_bytes[0] = 0;
+ free(rstring);
+ return 1;
+ }
+
+
+ info = GetUniCharInfo(uc);
+ ruc = uc + GetDelta(info);
+
+ if(ruc < 0x80) {
+ if(j >= size) {
+ size = 2*size + 1;
+ rstring = realloc(rstring, size);
+ }
+ rstring[j] = (char) ruc;
+ j++;
+ } else if(ruc < 0x7FF) {
+ if(j >= size) {
+ size = 2*size + 2;
+ rstring = realloc(rstring, size);
+ }
+ rstring[j] = (char) ((ruc >> 6) | 0xC0);
+ rstring[j+1] = (char) ((ruc | 0x80) & 0xBF);
+ j += 2;
+ } else if(ruc < 0xFFFF) {
+ if(j >= size) {
+ size = 2*size + 3;
+ rstring = realloc(rstring, size);
+ }
+ rstring[j] = (char) ((ruc >> 12) | 0xE0);
+ rstring[j+1] = (char) (((ruc >> 6) | 0x80) & 0xBF);
+ rstring[j+2] = (char) ((ruc | 0x80) & 0xBF);
+ j += 3;
+ }
+ }
+
+
+
+ *rbuf = (char*)(b = driver_alloc_binary(j));
+ memcpy(b->orig_bytes, rstring, j);
+ free(rstring);
+
+ return j;
+}
+
+
+
+ErlDrvEntry stringprep_driver_entry = {
+ NULL, /* F_PTR init, N/A */
+ stringprep_erl_start, /* L_PTR start, called when port is opened */
+ stringprep_erl_stop, /* F_PTR stop, called when port is closed */
+ NULL, /* F_PTR output, called when erlang has sent */
+ NULL, /* F_PTR ready_input, called when input descriptor ready */
+ NULL, /* F_PTR ready_output, called when output descriptor ready */
+ "stringprep_drv", /* char *driver_name, the argument to open_port */
+ NULL, /* F_PTR finish, called when unloaded */
+ NULL, /* handle */
+ stringprep_erl_control, /* F_PTR control, port_command callback */
+ NULL, /* F_PTR timeout, reserved */
+ NULL /* F_PTR outputv, reserved */
+};
+
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+DRIVER_INIT(stringprep_erl) /* must match name in driver_entry */
+{
+ return &stringprep_driver_entry;
+}
+