Created
February 25, 2014 16:27
-
-
Save chao-he/9212346 to your computer and use it in GitHub Desktop.
php unserialize to json, implement in c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
struct stream { | |
char *beg; | |
char *end; | |
char *cur; | |
char *save; | |
char *fill; | |
}; | |
static void _unserialize(struct stream *s); | |
static void _read_until(struct stream *s, char c) | |
{ | |
s->save = s->cur; | |
while(s->cur != s->end && *(s->cur) != c) ++ s->cur; | |
} | |
static void _read_length(struct stream *s, size_t n) | |
{ | |
s->save = s->cur; | |
s->cur += n; | |
} | |
static int _expect(struct stream *s, char c) | |
{ | |
s->cur ++; | |
return c == *(s->cur - 1); | |
} | |
static void _dump(struct stream *s, const char *p, int l) | |
{ | |
sprintf(s->fill, "%.*s", l, p); | |
s->fill += strlen(s->fill); | |
} | |
static int64_t _int(const char *s, size_t l) | |
{ | |
char buf[50] = {0}; | |
int64_t num = -1; | |
if(l < sizeof(buf) / sizeof(buf[0])) | |
{ | |
memcpy(buf, s, l); | |
num = strtol(buf, NULL, 10); | |
} | |
return num; | |
} | |
static void _array(struct stream *s) | |
{ | |
int size = 0; | |
int i = 0; | |
_read_until(s, ':'); | |
size = _int(s->save, s->cur - s->save) * 2; | |
_expect(s, ':'); | |
_expect(s, '{'); | |
_dump(s, "{", 1); | |
for(i = 0; i < size; ++ i) | |
{ | |
_unserialize(s); | |
if(i % 2 == 0) | |
{ | |
_dump(s, ":", 1); | |
} else if(i != size - 1) { | |
_dump(s, ",", 1); | |
} | |
} | |
_dump(s, "}", 1); | |
_expect(s, '}'); | |
} | |
static void _unserialize(struct stream *s) | |
{ | |
char c = tolower(*(s->cur)); | |
int64_t len = 0; | |
s->cur ++; | |
switch(c) { | |
case 'n': | |
_expect(s, ';'); | |
_dump(s, "\"\"", 2); | |
break; | |
case 'i': | |
case 'd': | |
case 'b': | |
_expect(s, ':'); | |
_read_until(s, ';'); | |
_dump(s, s->save, s->cur - s->save); | |
_expect(s, ';'); | |
break; | |
case 's': | |
_expect(s, ':'); | |
_read_until(s, ':'); | |
len = _int(s->save, s->cur - s->save); | |
_expect(s, ':'); | |
_expect(s, '"'); | |
_read_length(s, len); | |
_dump(s, "\"", 1); | |
_dump(s, s->save, s->cur - s->save); | |
_dump(s, "\"", 1); | |
_expect(s, '"'); | |
_expect(s, ';'); | |
break; | |
case 'a': | |
_expect(s, ':'); | |
_array(s); | |
break; | |
case 'o': | |
_expect(s, ':'); | |
_read_until(s, ':'); | |
len = _int(s->save, s->cur - s->save); | |
_expect(s, ':'); | |
_expect(s, '"'); | |
_read_length(s, len); | |
_expect(s, '"'); | |
_expect(s, ':'); | |
_array(s); | |
break; | |
} | |
} | |
void unserialize(char *data, size_t size, char *buffer) | |
{ | |
struct stream s = { | |
.beg = data, | |
.end = data + size, | |
.cur = data, | |
.save = NULL, | |
.fill = buffer | |
}; | |
_unserialize(&s); | |
*s.fill = '\0'; | |
} | |
// i:10;d:10.1;b:0;s:5:"hello";n;a:1:{i:0;s:"3":"aaa";}o:3:"key":1:{s"a"} | |
// | |
int main(int argc, char **argv) | |
{ | |
char *buffer = malloc(10000); | |
memset(buffer, 0, 10000); | |
unserialize(argv[1], strlen(argv[1]), buffer); | |
printf("=>%s\n", buffer); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment