📄 marshal.c
字号:
else if (*fmt == '?') opt = TRUE; else if (*fmt == '(' && !opt) SVN_ERR(svn_ra_svn_start_list(conn, pool)); else if (*fmt == ')') { SVN_ERR(svn_ra_svn_end_list(conn, pool)); opt = FALSE; } else if (*fmt == '!' && !*(fmt + 1)) return SVN_NO_ERROR; else abort(); } SVN_ERR(svn_ra_svn_end_list(conn, pool)); return SVN_NO_ERROR;}svn_error_t *svn_ra_svn_write_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const char *fmt, ...){ svn_error_t *err; va_list ap; va_start(ap, fmt); err = vwrite_tuple(conn, pool, fmt, ap); va_end(ap); return err;}/* --- READING DATA ITEMS --- *//* Read LEN bytes from CONN into already-allocated structure ITEM. * Afterwards, *ITEM is of type 'SVN_RA_SVN_STRING', and its string * data is allocated in POOL. */static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, svn_ra_svn_item_t *item, apr_uint64_t len){ char readbuf[4096]; apr_size_t readbuf_len; svn_stringbuf_t *stringbuf = svn_stringbuf_create("", pool); /* We can't store strings longer than the maximum size of apr_size_t, * so check for wrapping */ if (((apr_size_t) len) < len) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("String length larger than maximum")); while (len) { readbuf_len = len > sizeof(readbuf) ? sizeof(readbuf) : len; SVN_ERR(readbuf_read(conn, pool, readbuf, readbuf_len)); /* Read into a stringbuf_t to so we don't allow the sender to allocate * an arbitrary amount of memory without actually sending us that much * data */ svn_stringbuf_appendbytes(stringbuf, readbuf, readbuf_len); len -= readbuf_len; } item->kind = SVN_RA_SVN_STRING; item->u.string = apr_palloc(pool, sizeof(*item->u.string)); item->u.string->data = stringbuf->data; item->u.string->len = stringbuf->len; return SVN_NO_ERROR; }/* Given the first non-whitespace character FIRST_CHAR, read an item * into the already allocated structure ITEM. LEVEL should be set * to 0 for the first call and is used to enforce a recurssion limit * on the parser. */static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool, svn_ra_svn_item_t *item, char first_char, int level){ char c = first_char; apr_uint64_t val, prev_val=0; svn_stringbuf_t *str; svn_ra_svn_item_t *listitem; if (++level >= 64) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Too many nested items")); /* Determine the item type and read it in. Make sure that c is the * first character at the end of the item so we can test to make * sure it's whitespace. */ if (apr_isdigit(c)) { /* It's a number or a string. Read the number part, either way. */ val = c - '0'; while (1) { prev_val = val; SVN_ERR(readbuf_getchar(conn, pool, &c)); if (!apr_isdigit(c)) break; val = val * 10 + (c - '0'); if ((val / 10) != prev_val) /* val wrapped past maximum value */ return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Number is larger than maximum")); } if (c == ':') { /* It's a string. */ SVN_ERR(read_string(conn, pool, item, val)); SVN_ERR(readbuf_getchar(conn, pool, &c)); } else { /* It's a number. */ item->kind = SVN_RA_SVN_NUMBER; item->u.number = val; } } else if (apr_isalpha(c)) { /* It's a word. */ str = svn_stringbuf_ncreate(&c, 1, pool); while (1) { SVN_ERR(readbuf_getchar(conn, pool, &c)); if (!apr_isalnum(c) && c != '-') break; svn_stringbuf_appendbytes(str, &c, 1); } item->kind = SVN_RA_SVN_WORD; item->u.word = str->data; } else if (c == '(') { /* Read in the list items. */ item->kind = SVN_RA_SVN_LIST; item->u.list = apr_array_make(pool, 0, sizeof(svn_ra_svn_item_t)); while (1) { SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); if (c == ')') break; listitem = apr_array_push(item->u.list); SVN_ERR(read_item(conn, pool, listitem, c, level)); } SVN_ERR(readbuf_getchar(conn, pool, &c)); } if (!svn_iswhitespace(c)) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Malformed network data")); return SVN_NO_ERROR;}svn_error_t *svn_ra_svn_read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool, svn_ra_svn_item_t **item){ char c; /* Allocate space, read the first character, and then do the rest of * the work. This makes sense because of the way lists are read. */ *item = apr_palloc(pool, sizeof(**item)); SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c)); return read_item(conn, pool, *item, c, 0);}svn_error_t *svn_ra_svn_skip_leading_garbage(svn_ra_svn_conn_t *conn, apr_pool_t *pool){ return readbuf_skip_leading_garbage(conn);}/* --- READING AND PARSING TUPLES --- *//* Parse a tuple. Advance *FMT to the end of the tuple specification * and advance AP by the corresponding arguments. */static svn_error_t *vparse_tuple(apr_array_header_t *list, apr_pool_t *pool, const char **fmt, va_list *ap){ int count, list_level; svn_ra_svn_item_t *elt; for (count = 0; **fmt && count < list->nelts; (*fmt)++, count++) { /* '?' just means the tuple may stop; skip past it. */ if (**fmt == '?') (*fmt)++; elt = &((svn_ra_svn_item_t *) list->elts)[count]; if (**fmt == 'n' && elt->kind == SVN_RA_SVN_NUMBER) *va_arg(*ap, apr_uint64_t *) = elt->u.number; else if (**fmt == 'r' && elt->kind == SVN_RA_SVN_NUMBER) *va_arg(*ap, svn_revnum_t *) = elt->u.number; else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING) *va_arg(*ap, svn_string_t **) = elt->u.string; else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING) *va_arg(*ap, const char **) = elt->u.string->data; else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD) *va_arg(*ap, const char **) = elt->u.word; else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD) { if (strcmp(elt->u.word, "true") == 0) *va_arg(*ap, svn_boolean_t *) = TRUE; else if (strcmp(elt->u.word, "false") == 0) *va_arg(*ap, svn_boolean_t *) = FALSE; else break; } else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST) *va_arg(*ap, apr_array_header_t **) = elt->u.list; else if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST) { (*fmt)++; SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap)); } else if (**fmt == ')') return SVN_NO_ERROR; else break; } if (**fmt == '?') { list_level = 0; for (; **fmt; (*fmt)++) { switch (**fmt) { case '?': break; case 'r': *va_arg(*ap, svn_revnum_t *) = SVN_INVALID_REVNUM; break; case 's': *va_arg(*ap, svn_string_t **) = NULL; break; case 'c': case 'w': *va_arg(*ap, const char **) = NULL; break; case 'l': *va_arg(*ap, apr_array_header_t **) = NULL; break; case 'n': *va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER; break; case '(': list_level++; break; case ')': if (--list_level < 0) return SVN_NO_ERROR; break; default: abort(); } } } if (**fmt && **fmt != ')') return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Malformed network data")); return SVN_NO_ERROR;}svn_error_t *svn_ra_svn_parse_tuple(apr_array_header_t *list, apr_pool_t *pool, const char *fmt, ...){ svn_error_t *err; va_list ap; va_start(ap, fmt); err = vparse_tuple(list, pool, &fmt, &ap); va_end(ap); return err;}svn_error_t *svn_ra_svn_read_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const char *fmt, ...){ va_list ap; svn_ra_svn_item_t *item; svn_error_t *err; SVN_ERR(svn_ra_svn_read_item(conn, pool, &item)); if (item->kind != SVN_RA_SVN_LIST) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Malformed network data")); va_start(ap, fmt); err = vparse_tuple(item->u.list, pool, &fmt, &ap); va_end(ap); return err;}/* --- READING AND WRITING COMMANDS AND RESPONSES --- */svn_error_t *svn_ra_svn__handle_failure_status(apr_array_header_t *params, apr_pool_t *pool){ const char *message, *file; svn_error_t *err = NULL; svn_ra_svn_item_t *elt; int i; apr_uint64_t apr_err, line; apr_pool_t *subpool = svn_pool_create(pool); if (params->nelts == 0) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Empty error list")); /* Rebuild the error list from the end, to avoid reversing the order. */ for (i = params->nelts - 1; i >= 0; i--) { svn_pool_clear(subpool); elt = &((svn_ra_svn_item_t *) params->elts)[i]; if (elt->kind != SVN_RA_SVN_LIST) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Malformed error list")); SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, subpool, "nccn", &apr_err, &message, &file, &line)); /* The message field should have been optional, but we can't easily change that, so "" means a nonexistent message. */ if (!*message) message = NULL; err = svn_error_create(apr_err, err, message); err->file = apr_pstrdup(err->pool, file); err->line = line; } svn_pool_destroy(subpool); return err;}svn_error_t *svn_ra_svn_read_cmd_response(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const char *fmt, ...){ va_list ap; const char *status; apr_array_header_t *params; svn_error_t *err; SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "wl", &status, ¶ms)); if (strcmp(status, "success") == 0) { va_start(ap, fmt); err = vparse_tuple(params, pool, &fmt, &ap); va_end(ap); return err; } else if (strcmp(status, "failure") == 0) { return svn_ra_svn__handle_failure_status(params, pool); } return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Unknown status '%s' in command response"), status);}svn_error_t *svn_ra_svn_handle_commands(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const svn_ra_svn_cmd_entry_t *commands, void *baton){ apr_pool_t *subpool = svn_pool_create(pool); const char *cmdname; int i; svn_error_t *err, *write_err; apr_array_header_t *params; while (1) { apr_pool_clear(subpool); SVN_ERR(svn_ra_svn_read_tuple(conn, subpool, "wl", &cmdname, ¶ms)); for (i = 0; commands[i].cmdname; i++) { if (strcmp(cmdname, commands[i].cmdname) == 0) break; } if (commands[i].cmdname) err = (*commands[i].handler)(conn, subpool, params, baton); else { err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL, _("Unknown command '%s'"), cmdname); err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL); } if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR) { write_err = svn_ra_svn_write_cmd_failure(conn, subpool, err->child); svn_error_clear(err); if (write_err) return write_err; } else if (err) return err; if (commands[i].terminate) break; } apr_pool_destroy(subpool); return SVN_NO_ERROR;}svn_error_t *svn_ra_svn_write_cmd(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const char *cmdname, const char *fmt, ...){ va_list ap; svn_error_t *err; SVN_ERR(svn_ra_svn_start_list(conn, pool)); SVN_ERR(svn_ra_svn_write_word(conn, pool, cmdname)); va_start(ap, fmt); err = vwrite_tuple(conn, pool, fmt, ap); va_end(ap); if (err) return err; SVN_ERR(svn_ra_svn_end_list(conn, pool)); return SVN_NO_ERROR;}svn_error_t *svn_ra_svn_write_cmd_response(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const char *fmt, ...){ va_list ap; svn_error_t *err; SVN_ERR(svn_ra_svn_start_list(conn, pool)); SVN_ERR(svn_ra_svn_write_word(conn, pool, "success")); va_start(ap, fmt); err = vwrite_tuple(conn, pool, fmt, ap); va_end(ap); if (err) return err; SVN_ERR(svn_ra_svn_end_list(conn, pool)); return SVN_NO_ERROR;}svn_error_t *svn_ra_svn_write_cmd_failure(svn_ra_svn_conn_t *conn, apr_pool_t *pool, svn_error_t *err){ SVN_ERR(svn_ra_svn_start_list(conn, pool)); SVN_ERR(svn_ra_svn_write_word(conn, pool, "failure")); SVN_ERR(svn_ra_svn_start_list(conn, pool)); for (; err; err = err->child) { /* The message string should have been optional, but we can't easily change that, so marshal nonexistent messages as "". */ SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "nccn", (apr_uint64_t) err->apr_err, err->message ? err->message : "", err->file, (apr_uint64_t) err->line)); } SVN_ERR(svn_ra_svn_end_list(conn, pool)); SVN_ERR(svn_ra_svn_end_list(conn, pool)); return SVN_NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -