| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748 |
- <?php
- function tokenize ($str, &$out) {
- $out = array();
- while (strlen($str) > 0) {
- if (preg_match('/^\\/\\/.*/', $str, $matches)) {
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^\\s+/', $str, $matches)) {
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^include/', $str, $matches)) {
- $out[] = array('include', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^message/', $str, $matches)) {
- $out[] = array('message', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^repeated/', $str, $matches)) {
- $out[] = array('repeated', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^required/', $str, $matches)) {
- $out[] = array('required', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^optional/', $str, $matches)) {
- $out[] = array('optional', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^{/', $str, $matches)) {
- $out[] = array('spar', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^}/', $str, $matches)) {
- $out[] = array('epar', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^\(/', $str, $matches)) {
- $out[] = array('srpar', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^\)/', $str, $matches)) {
- $out[] = array('erpar', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^=/', $str, $matches)) {
- $out[] = array('equals', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^;/', $str, $matches)) {
- $out[] = array('semicolon', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^uint(8|16|32|64)/', $str, $matches)) {
- $out[] = array('uint', $matches[1]);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^data/', $str, $matches)) {
- $out[] = array('data', null);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^[0-9]+/', $str, $matches)) {
- $out[] = array('number', $matches[0]);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*/', $str, $matches)) {
- $out[] = array('name', $matches[0]);
- $str = substr($str, strlen($matches[0]));
- }
- else if (preg_match('/^"([^"]*)"/', $str, $matches)) {
- $out[] = array('string', $matches[1]);
- $str = substr($str, strlen($matches[0]));
- }
- else {
- return FALSE;
- }
- }
- return TRUE;
- }
- function fatal_error ($message)
- {
- fwrite(STDERR, "Fatal error: $message\n");
- ob_get_clean();
- exit(1);
- }
- function make_writer_decl ($msg, $entry)
- {
- switch ($entry["type"]["type"]) {
- case "uint":
- return "void {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o, uint{$entry["type"]["size"]}_t v)";
- case "data":
- return "uint8_t * {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o, int len)";
- case "constdata":
- return "uint8_t * {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o)";
- default:
- assert(0);
- }
- }
- function make_parser_decl ($msg, $entry)
- {
- switch ($entry["type"]["type"]) {
- case "uint":
- return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint{$entry["type"]["size"]}_t *v)";
- case "data":
- return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint8_t **data, int *data_len)";
- case "constdata":
- return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint8_t **data)";
- default:
- assert(0);
- }
- }
- function make_parser_reset_decl ($msg, $entry)
- {
- return "void {$msg["name"]}Parser_Reset{$entry["name"]} ({$msg["name"]}Parser *o)";
- }
- function make_parser_forward_decl ($msg, $entry)
- {
- return "void {$msg["name"]}Parser_Forward{$entry["name"]} ({$msg["name"]}Parser *o)";
- }
- function make_type_name ($msg, $entry)
- {
- switch ($entry["type"]["type"]) {
- case "uint":
- return "BPROTO_TYPE_UINT{$entry["type"]["size"]}";
- case "data":
- return "BPROTO_TYPE_DATA";
- case "constdata":
- return "BPROTO_TYPE_CONSTDATA";
- default:
- assert(0);
- }
- }
- function make_finish_assert ($msg, $entry)
- {
- switch ($entry["cardinality"]) {
- case "repeated":
- return "ASSERT(o->{$entry["name"]}_count >= 0)";
- case "required repeated":
- return "ASSERT(o->{$entry["name"]}_count >= 1)";
- case "optional":
- return "ASSERT(o->{$entry["name"]}_count >= 0 && o->{$entry["name"]}_count <= 1)";
- case "required":
- return "ASSERT(o->{$entry["name"]}_count == 1)";
- default:
- assert(0);
- }
- }
- function make_add_count_assert ($msg, $entry)
- {
- if (in_array($entry["cardinality"], array("optional", "required"))) {
- return "ASSERT(o->{$entry["name"]}_count == 0)";
- }
- return "";
- }
- function make_add_length_assert ($msg, $entry)
- {
- if ($entry["type"]["type"] == "data") {
- return "ASSERT(len >= 0 && len <= UINT32_MAX)";
- }
- return "";
- }
- function make_size_define ($msg, $entry)
- {
- switch ($entry["type"]["type"]) {
- case "uint":
- return "#define {$msg["name"]}_SIZE{$entry["name"]} (sizeof(struct BProto_header_s) + sizeof(struct BProto_uint{$entry["type"]["size"]}_s))";
- case "data":
- return "#define {$msg["name"]}_SIZE{$entry["name"]}(_len) (sizeof(struct BProto_header_s) + sizeof(struct BProto_data_header_s) + (_len))";
- case "constdata":
- return "#define {$msg["name"]}_SIZE{$entry["name"]} (sizeof(struct BProto_header_s) + sizeof(struct BProto_data_header_s) + ({$entry["type"]["size"]}))";
- default:
- assert(0);
- }
- }
- function generate_header ($name, $directives, $messages) {
- ob_start();
- echo <<<EOD
- /*
- DO NOT EDIT THIS FILE!
- This file was automatically generated by the bproto generator.
- */
- #include <stdint.h>
- #include <misc/debug.h>
- #include <misc/byteorder.h>
- #include <bproto/BProto.h>
- EOD;
- foreach ($directives as $directive) {
- if ($directive["type"] == "include") {
- echo <<<EOD
- #include "{$directive["file"]}"
- EOD;
- }
- }
- echo <<<EOD
- EOD;
- foreach ($messages as $msg) {
- foreach ($msg["entries"] as $entry) {
- $def = make_size_define($msg, $entry);
- echo <<<EOD
- {$def}
- EOD;
- }
- echo <<<EOD
- typedef struct {
- uint8_t *out;
- int used;
- EOD;
- foreach ($msg["entries"] as $entry) {
- echo <<<EOD
- int {$entry["name"]}_count;
- EOD;
- }
- echo <<<EOD
- } {$msg["name"]}Writer;
- static void {$msg["name"]}Writer_Init ({$msg["name"]}Writer *o, uint8_t *out);
- static int {$msg["name"]}Writer_Finish ({$msg["name"]}Writer *o);
- EOD;
- foreach ($msg["entries"] as $entry) {
- $decl = make_writer_decl($msg, $entry);
- echo <<<EOD
- static {$decl};
- EOD;
- }
- echo <<<EOD
- typedef struct {
- uint8_t *buf;
- int buf_len;
- EOD;
- foreach ($msg["entries"] as $entry) {
- echo <<<EOD
- int {$entry["name"]}_start;
- int {$entry["name"]}_span;
- int {$entry["name"]}_pos;
- EOD;
- }
- echo <<<EOD
- } {$msg["name"]}Parser;
- static int {$msg["name"]}Parser_Init ({$msg["name"]}Parser *o, uint8_t *buf, int buf_len);
- static int {$msg["name"]}Parser_GotEverything ({$msg["name"]}Parser *o);
- EOD;
- foreach ($msg["entries"] as $entry) {
- $decl = make_parser_decl($msg, $entry);
- $reset_decl = make_parser_reset_decl($msg, $entry);
- $forward_decl = make_parser_forward_decl($msg, $entry);
- echo <<<EOD
- static {$decl};
- static {$reset_decl};
- static {$forward_decl};
- EOD;
- }
- echo <<<EOD
- void {$msg["name"]}Writer_Init ({$msg["name"]}Writer *o, uint8_t *out)
- {
- o->out = out;
- o->used = 0;
- EOD;
- foreach ($msg["entries"] as $entry) {
- echo <<<EOD
- o->{$entry["name"]}_count = 0;
- EOD;
- }
- echo <<<EOD
- }
- int {$msg["name"]}Writer_Finish ({$msg["name"]}Writer *o)
- {
- ASSERT(o->used >= 0)
- EOD;
- foreach ($msg["entries"] as $entry) {
- $ass = make_finish_assert($msg, $entry);
- echo <<<EOD
- {$ass}
- EOD;
- }
- echo <<<EOD
- return o->used;
- }
- EOD;
- foreach ($msg["entries"] as $entry) {
- $decl = make_writer_decl($msg, $entry);
- $type = make_type_name($msg, $entry);
- $add_count_assert = make_add_count_assert($msg, $entry);
- $add_length_assert = make_add_length_assert($msg, $entry);
- echo <<<EOD
- {$decl}
- {
- ASSERT(o->used >= 0)
- {$add_count_assert}
- {$add_length_assert}
- ((struct BProto_header_s *)(o->out + o->used))->id = htol16({$entry["id"]});
- ((struct BProto_header_s *)(o->out + o->used))->type = htol16({$type});
- o->used += sizeof(struct BProto_header_s);
- EOD;
- switch ($entry["type"]["type"]) {
- case "uint":
- echo <<<EOD
- ((struct BProto_uint{$entry["type"]["size"]}_s *)(o->out + o->used))->v = htol{$entry["type"]["size"]}(v);
- o->used += sizeof(struct BProto_uint{$entry["type"]["size"]}_s);
- EOD;
- break;
- case "data":
- echo <<<EOD
- ((struct BProto_data_header_s *)(o->out + o->used))->len = htol32(len);
- o->used += sizeof(struct BProto_data_header_s);
- uint8_t *dest = (o->out + o->used);
- o->used += len;
- EOD;
- break;
- case "constdata":
- echo <<<EOD
- ((struct BProto_data_header_s *)(o->out + o->used))->len = htol32({$entry["type"]["size"]});
- o->used += sizeof(struct BProto_data_header_s);
- uint8_t *dest = (o->out + o->used);
- o->used += ({$entry["type"]["size"]});
- EOD;
- break;
- default:
- assert(0);
- }
- echo <<<EOD
- o->{$entry["name"]}_count++;
- EOD;
- if (in_array($entry["type"]["type"], array("data", "constdata"))) {
- echo <<<EOD
- return dest;
- EOD;
- }
- echo <<<EOD
- }
- EOD;
- }
- echo <<<EOD
- int {$msg["name"]}Parser_Init ({$msg["name"]}Parser *o, uint8_t *buf, int buf_len)
- {
- ASSERT(buf_len >= 0)
- o->buf = buf;
- o->buf_len = buf_len;
- EOD;
- foreach ($msg["entries"] as $entry) {
- echo <<<EOD
- o->{$entry["name"]}_start = o->buf_len;
- o->{$entry["name"]}_span = 0;
- o->{$entry["name"]}_pos = 0;
- EOD;
- }
- echo <<<EOD
- EOD;
- foreach ($msg["entries"] as $entry) {
- echo <<<EOD
- int {$entry["name"]}_count = 0;
- EOD;
- }
- echo <<<EOD
- int pos = 0;
- int left = o->buf_len;
- while (left > 0) {
- int entry_pos = pos;
- if (!(left >= sizeof(struct BProto_header_s))) {
- return 0;
- }
- struct BProto_header_s *header = (struct BProto_header_s *)(o->buf + pos);
- pos += sizeof(struct BProto_header_s);
- left -= sizeof(struct BProto_header_s);
- uint16_t type = ltoh16(header->type);
- uint16_t id = ltoh16(header->id);
- switch (type) {
- EOD;
- foreach (array(8, 16, 32, 64) as $bits) {
- echo <<<EOD
- case BPROTO_TYPE_UINT{$bits}: {
- if (!(left >= sizeof(struct BProto_uint{$bits}_s))) {
- return 0;
- }
- struct BProto_uint{$bits}_s *val = (struct BProto_uint{$bits}_s *)(o->buf + pos);
- pos += sizeof(struct BProto_uint{$bits}_s);
- left -= sizeof(struct BProto_uint{$bits}_s);
- switch (id) {
- EOD;
- foreach ($msg["entries"] as $entry) {
- if (!($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits)) {
- continue;
- }
- $type = make_type_name($msg, $entry);
- echo <<<EOD
- case {$entry["id"]}:
- if (o->{$entry["name"]}_start == o->buf_len) {
- o->{$entry["name"]}_start = entry_pos;
- }
- o->{$entry["name"]}_span = pos - o->{$entry["name"]}_start;
- {$entry["name"]}_count++;
- break;
- EOD;
- }
- echo <<<EOD
- default:
- return 0;
- }
- } break;
- EOD;
- }
- echo <<<EOD
- case BPROTO_TYPE_DATA:
- case BPROTO_TYPE_CONSTDATA:
- {
- if (!(left >= sizeof(struct BProto_data_header_s))) {
- return 0;
- }
- struct BProto_data_header_s *val = (struct BProto_data_header_s *)(o->buf + pos);
- pos += sizeof(struct BProto_data_header_s);
- left -= sizeof(struct BProto_data_header_s);
- uint32_t payload_len = ltoh32(val->len);
- if (!(left >= payload_len)) {
- return 0;
- }
- pos += payload_len;
- left -= payload_len;
- switch (id) {
- EOD;
- foreach ($msg["entries"] as $entry) {
- if (!in_array($entry["type"]["type"], array("data", "constdata"))) {
- continue;
- }
- $type = make_type_name($msg, $entry);
- echo <<<EOD
- case {$entry["id"]}:
- if (!(type == {$type})) {
- return 0;
- }
- EOD;
- if ($entry["type"]["type"] == "constdata") {
- echo <<<EOD
- if (!(payload_len == ({$entry["type"]["size"]}))) {
- return 0;
- }
- EOD;
- }
- echo <<<EOD
- if (o->{$entry["name"]}_start == o->buf_len) {
- o->{$entry["name"]}_start = entry_pos;
- }
- o->{$entry["name"]}_span = pos - o->{$entry["name"]}_start;
- {$entry["name"]}_count++;
- break;
- EOD;
- }
- echo <<<EOD
- default:
- return 0;
- }
- } break;
- default:
- return 0;
- }
- }
- EOD;
- foreach ($msg["entries"] as $entry) {
- $cond = "";
- switch ($entry["cardinality"]) {
- case "repeated":
- break;
- case "required repeated":
- $cond = "{$entry["name"]}_count >= 1";
- break;
- case "optional":
- $cond = "{$entry["name"]}_count <= 1";
- break;
- case "required":
- $cond = "{$entry["name"]}_count == 1";
- break;
- default:
- assert(0);
- }
- if ($cond) {
- echo <<<EOD
- if (!({$cond})) {
- return 0;
- }
- EOD;
- }
- }
- echo <<<EOD
- return 1;
- }
- int {$msg["name"]}Parser_GotEverything ({$msg["name"]}Parser *o)
- {
- return (
- EOD;
- $first = 1;
- foreach ($msg["entries"] as $entry) {
- if ($first) {
- $first = 0;
- } else {
- echo <<<EOD
- &&
- EOD;
- }
- echo <<<EOD
- o->{$entry["name"]}_pos == o->{$entry["name"]}_span
- EOD;
- }
-
- echo <<<EOD
- );
- }
- EOD;
- foreach ($msg["entries"] as $entry) {
- $decl = make_parser_decl($msg, $entry);
- $reset_decl = make_parser_reset_decl($msg, $entry);
- $forward_decl = make_parser_forward_decl($msg, $entry);
- $type = make_type_name($msg, $entry);
- echo <<<EOD
- {$decl}
- {
- ASSERT(o->{$entry["name"]}_pos >= 0)
- ASSERT(o->{$entry["name"]}_pos <= o->{$entry["name"]}_span)
- int left = o->{$entry["name"]}_span - o->{$entry["name"]}_pos;
- while (left > 0) {
- ASSERT(left >= sizeof(struct BProto_header_s))
- struct BProto_header_s *header = (struct BProto_header_s *)(o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos);
- o->{$entry["name"]}_pos += sizeof(struct BProto_header_s);
- left -= sizeof(struct BProto_header_s);
- uint16_t type = ltoh16(header->type);
- uint16_t id = ltoh16(header->id);
- switch (type) {
- EOD;
- foreach (array(8, 16, 32, 64) as $bits) {
- echo <<<EOD
- case BPROTO_TYPE_UINT{$bits}: {
- ASSERT(left >= sizeof(struct BProto_uint{$bits}_s))
- struct BProto_uint{$bits}_s *val = (struct BProto_uint{$bits}_s *)(o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos);
- o->{$entry["name"]}_pos += sizeof(struct BProto_uint{$bits}_s);
- left -= sizeof(struct BProto_uint{$bits}_s);
- EOD;
- if ($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits) {
- echo <<<EOD
- if (id == {$entry["id"]}) {
- *v = ltoh{$bits}(val->v);
- return 1;
- }
- EOD;
- }
- echo <<<EOD
- } break;
- EOD;
- }
- echo <<<EOD
- case BPROTO_TYPE_DATA:
- case BPROTO_TYPE_CONSTDATA:
- {
- ASSERT(left >= sizeof(struct BProto_data_header_s))
- struct BProto_data_header_s *val = (struct BProto_data_header_s *)(o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos);
- o->{$entry["name"]}_pos += sizeof(struct BProto_data_header_s);
- left -= sizeof(struct BProto_data_header_s);
- uint32_t payload_len = ltoh32(val->len);
- ASSERT(left >= payload_len)
- uint8_t *payload = o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos;
- o->{$entry["name"]}_pos += payload_len;
- left -= payload_len;
- EOD;
- if ($entry["type"]["type"] == "data") {
- echo <<<EOD
- if (type == BPROTO_TYPE_DATA && id == {$entry["id"]}) {
- *data = payload;
- *data_len = payload_len;
- return 1;
- }
- EOD;
- }
- else if ($entry["type"]["type"] == "constdata") {
- echo <<<EOD
- if (type == BPROTO_TYPE_CONSTDATA && id == {$entry["id"]}) {
- *data = payload;
- return 1;
- }
- EOD;
- }
- echo <<<EOD
- } break;
- default:
- ASSERT(0);
- }
- }
- return 0;
- }
- {$reset_decl}
- {
- o->{$entry["name"]}_pos = 0;
- }
- {$forward_decl}
- {
- o->{$entry["name"]}_pos = o->{$entry["name"]}_span;
- }
- EOD;
- }
- }
- return ob_get_clean();
- }
|