forked from github/server
escaping a string for use in CR needs to only replace quotes and backslashes.
This commit is contained in:
parent
226fa2ba08
commit
60a86e7b2f
9 changed files with 266 additions and 22 deletions
|
@ -517,7 +517,7 @@ static void report_crtypes(FILE * F, const struct locale *lang)
|
||||||
assert(hash > 0);
|
assert(hash > 0);
|
||||||
fprintf(F, "MESSAGETYPE %d\n", hash);
|
fprintf(F, "MESSAGETYPE %d\n", hash);
|
||||||
fputc('\"', F);
|
fputc('\"', F);
|
||||||
fputs(str_escape(nrt_string(kmt->mtype, lang), buffer, sizeof(buffer)), F);
|
fputs(crescape(nrt_string(kmt->mtype, lang), buffer, sizeof(buffer)), F);
|
||||||
fputs("\";text\n", F);
|
fputs("\";text\n", F);
|
||||||
fprintf(F, "\"%s\";section\n", kmt->mtype->section);
|
fprintf(F, "\"%s\";section\n", kmt->mtype->section);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,15 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si
|
||||||
return sbuffer;
|
return sbuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *crescape(const char *str, char *buffer, size_t size) {
|
||||||
|
const char *replace = "\"\\";
|
||||||
|
const char * pos = strpbrk(str, replace);
|
||||||
|
if (!pos) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return str_escape_ex(str, buffer, size, replace);
|
||||||
|
}
|
||||||
|
|
||||||
int stream_order(struct stream *out, const struct order *ord, const struct locale *lang, bool escape)
|
int stream_order(struct stream *out, const struct order *ord, const struct locale *lang, bool escape)
|
||||||
{
|
{
|
||||||
const char *text;
|
const char *text;
|
||||||
|
@ -151,7 +160,7 @@ int stream_order(struct stream *out, const struct order *ord, const struct local
|
||||||
char obuf[1024];
|
char obuf[1024];
|
||||||
swrite(" ", 1, 1, out);
|
swrite(" ", 1, 1, out);
|
||||||
if (escape) {
|
if (escape) {
|
||||||
text = str_escape(text, obuf, sizeof(obuf));
|
text = crescape(text, obuf, sizeof(obuf));
|
||||||
}
|
}
|
||||||
swrite(text, 1, strlen(text), out);
|
swrite(text, 1, strlen(text), out);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ extern "C" {
|
||||||
bool is_exclusive(const order * ord);
|
bool is_exclusive(const order * ord);
|
||||||
bool is_repeated(keyword_t kwd);
|
bool is_repeated(keyword_t kwd);
|
||||||
bool is_long(keyword_t kwd);
|
bool is_long(keyword_t kwd);
|
||||||
|
const char *crescape(const char *str, char *buffer, size_t size);
|
||||||
|
|
||||||
char *write_order(const order * ord, const struct locale *lang,
|
char *write_order(const order * ord, const struct locale *lang,
|
||||||
char *buffer, size_t size);
|
char *buffer, size_t size);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <tests.h>
|
#include <tests.h>
|
||||||
#include <CuTest.h>
|
#include <CuTest.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static void test_create_order(CuTest *tc) {
|
static void test_create_order(CuTest *tc) {
|
||||||
char cmd[32];
|
char cmd[32];
|
||||||
|
@ -484,10 +485,62 @@ static void test_study_order_unknown_quoted(CuTest *tc) {
|
||||||
test_teardown();
|
test_teardown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_create_order_long(CuTest *tc) {
|
||||||
|
char buffer[2048];
|
||||||
|
order *ord;
|
||||||
|
size_t len;
|
||||||
|
struct locale *lang;
|
||||||
|
stream out;
|
||||||
|
const char * longstr = "// BESCHREIBEN EINHEIT \"In weià ƒ ƒ ƒ ƒ ƒ ƒ &#"
|
||||||
|
"131;ƒƒƒƒƒƒ?e GewÃ
"
|
||||||
|
"1;ƒƒƒƒƒƒƒƒƒÃƒƒƒ"
|
||||||
|
"ƒƒƒƒƒƒƒƒƒÃƒƒƒ&#"
|
||||||
|
"131;ƒƒƒƒƒƒ‚Ã
"
|
||||||
|
"1;ƒƒƒƒ‚Ã"
|
||||||
|
"ƒ‚ÂÃ&"
|
||||||
|
"#131;ƒƒƒ‚ÂÃ&#"
|
||||||
|
"131;ƒƒ‚ÂÂÃ&#"
|
||||||
|
"130;¢‚Ã&"
|
||||||
|
"#131;ƒ‚Ã"
|
||||||
|
"31;‚ÂÃ
"
|
||||||
|
"1;ƒƒƒƒƒƒƒ‚Ã"
|
||||||
|
"ƒƒƒ‚[...]hB��2�xa�Hv$P�xa��A���A��";
|
||||||
|
test_setup();
|
||||||
|
lang = test_create_locale();
|
||||||
|
ord = parse_order(longstr, lang);
|
||||||
|
len = strlen(longstr);
|
||||||
|
CuAssertIntEquals(tc, 0, ord->command);
|
||||||
|
mstream_init(&out);
|
||||||
|
stream_order(&out, ord, lang, true);
|
||||||
|
out.api->rewind(out.handle);
|
||||||
|
out.api->readln(out.handle, buffer, sizeof(buffer));
|
||||||
|
mstream_done(&out);
|
||||||
|
free_order(ord);
|
||||||
|
test_teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_crescape(CuTest *tc) {
|
||||||
|
char buffer[16];
|
||||||
|
const char *input = "12345678901234567890";
|
||||||
|
|
||||||
|
CuAssertStrEquals(tc, "1234", crescape("1234", buffer, 16));
|
||||||
|
CuAssertPtrEquals(tc, (void *)input, (void *)crescape(input, buffer, 16));
|
||||||
|
|
||||||
|
CuAssertStrEquals(tc, "\\\"1234\\\"", crescape("\"1234\"", buffer, 16));
|
||||||
|
CuAssertStrEquals(tc, "\\\"1234\\\"", buffer);
|
||||||
|
|
||||||
|
CuAssertStrEquals(tc, "\\\"1234", crescape("\"1234\"", buffer, 8));
|
||||||
|
|
||||||
|
/* unlike in C strings, only " and \ are escaped: */
|
||||||
|
CuAssertStrEquals(tc, "\\\"\\\\\n\r\'", crescape("\"\\\n\r\'", buffer, 16));
|
||||||
|
}
|
||||||
|
|
||||||
CuSuite *get_order_suite(void)
|
CuSuite *get_order_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
SUITE_ADD_TEST(suite, test_crescape);
|
||||||
SUITE_ADD_TEST(suite, test_create_order);
|
SUITE_ADD_TEST(suite, test_create_order);
|
||||||
|
SUITE_ADD_TEST(suite, test_create_order_long);
|
||||||
SUITE_ADD_TEST(suite, test_study_orders);
|
SUITE_ADD_TEST(suite, test_study_orders);
|
||||||
SUITE_ADD_TEST(suite, test_study_order);
|
SUITE_ADD_TEST(suite, test_study_order);
|
||||||
SUITE_ADD_TEST(suite, test_study_order_unknown);
|
SUITE_ADD_TEST(suite, test_study_order_unknown);
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
|
|
||||||
static int read_permissions(variant *var, void *owner, struct gamedata *data)
|
static int read_permissions(variant *var, void *owner, struct gamedata *data)
|
||||||
{
|
{
|
||||||
attrib *a;
|
attrib *a = NULL;
|
||||||
UNUSED_ARG(var);
|
UNUSED_ARG(var);
|
||||||
read_attribs(data, &a, owner);
|
read_attribs(data, &a, owner);
|
||||||
a_remove(&a, a);
|
a_remove(&a, a);
|
||||||
|
|
|
@ -172,8 +172,8 @@ static order *monster_attack(unit * u, const unit * target)
|
||||||
if (monster_is_waiting(u))
|
if (monster_is_waiting(u))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (u->region->land) {
|
if (u->region->land && (u->region->flags & RF_GUARDED) == 0) {
|
||||||
assert(u->region->flags & RF_GUARDED);
|
return NULL;
|
||||||
}
|
}
|
||||||
return create_order(K_ATTACK, u->faction->locale, "%i", target->no);
|
return create_order(K_ATTACK, u->faction->locale, "%i", target->no);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#endif
|
#endif
|
||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
#include "assert.h"
|
|
||||||
|
|
||||||
/* libc includes */
|
/* libc includes */
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -155,27 +155,28 @@ int str_hash(const char *s)
|
||||||
return key & 0x7FFFFFFF;
|
return key & 0x7FFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *str_escape(const char *str, char *buffer, size_t len)
|
const char *str_escape_wrong(const char *str, char *buffer, size_t len)
|
||||||
{
|
{
|
||||||
const char *handle_start = strchr(str, '\"');
|
const char *handle_start = strchr(str, '\"');
|
||||||
if (!handle_start) handle_start = strchr(str, '\\');
|
if (!handle_start) handle_start = strchr(str, '\\');
|
||||||
assert(buffer);
|
assert(buffer);
|
||||||
if (handle_start) {
|
if (handle_start) {
|
||||||
const char *p;
|
const char *p = str;
|
||||||
char *o;
|
char *o = buffer;
|
||||||
size_t skip = handle_start - str;
|
size_t skip = handle_start - str;
|
||||||
|
|
||||||
if (skip > len) {
|
if (skip > len) {
|
||||||
skip = len;
|
skip = len;
|
||||||
}
|
}
|
||||||
|
if (skip > 0) {
|
||||||
memcpy(buffer, str, skip);
|
memcpy(buffer, str, skip);
|
||||||
o = buffer + skip;
|
o += skip;
|
||||||
p = str + skip;
|
p += skip;
|
||||||
len -= skip;
|
len -= skip;
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
if (*p == '\"' || *p == '\\') {
|
if (*p == '\"' || *p == '\\') {
|
||||||
if (len < 2) {
|
if (len < 2) {
|
||||||
*o = '\0';
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
(*o++) = '\\';
|
(*o++) = '\\';
|
||||||
|
@ -183,13 +184,15 @@ const char *str_escape(const char *str, char *buffer, size_t len)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
*o = '\0';
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
--len;
|
--len;
|
||||||
}
|
}
|
||||||
|
if (len > 0) {
|
||||||
(*o++) = (*p);
|
(*o++) = (*p);
|
||||||
} while (*p++);
|
}
|
||||||
|
} while (len > 0 && *p++);
|
||||||
|
*o = '\0';
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
|
@ -306,3 +309,166 @@ char *str_unescape(char *str) {
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *str_escape_ex(const char *str, char *buffer, size_t size, const char *chars)
|
||||||
|
{
|
||||||
|
const char *read = str;
|
||||||
|
char *write = buffer;
|
||||||
|
if (size < 1) return NULL;
|
||||||
|
while (size > 1 && *read) {
|
||||||
|
const char *pos = strpbrk(read, chars);
|
||||||
|
size_t len = size;
|
||||||
|
if (pos) {
|
||||||
|
len = pos - read;
|
||||||
|
}
|
||||||
|
if (len < size) {
|
||||||
|
unsigned char ch = *(const unsigned char *)pos;
|
||||||
|
if (len > 0) {
|
||||||
|
memmove(write, read, len);
|
||||||
|
write += len;
|
||||||
|
read += len;
|
||||||
|
size -= len;
|
||||||
|
}
|
||||||
|
switch (ch) {
|
||||||
|
case '\t':
|
||||||
|
if (size > 2) {
|
||||||
|
*write++ = '\\';
|
||||||
|
*write++ = 't';
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
if (size > 2) {
|
||||||
|
*write++ = '\\';
|
||||||
|
*write++ = 'n';
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
if (size > 2) {
|
||||||
|
*write++ = '\\';
|
||||||
|
*write++ = 'r';
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
case '\'':
|
||||||
|
case '\\':
|
||||||
|
if (size > 2) {
|
||||||
|
*write++ = '\\';
|
||||||
|
*write++ = ch;
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (size > 5) {
|
||||||
|
int n = sprintf(write, "\\%03o", ch);
|
||||||
|
if (n > 0) {
|
||||||
|
assert(n == 5);
|
||||||
|
write += n;
|
||||||
|
size -= n;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
}
|
||||||
|
++read;
|
||||||
|
} else {
|
||||||
|
/* end of buffer space */
|
||||||
|
len = size - 1;
|
||||||
|
if (len > 0) {
|
||||||
|
memmove(write, read, len);
|
||||||
|
write += len;
|
||||||
|
size -= len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*write = '\0';
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *str_escape(const char *str, char *buffer, size_t size) {
|
||||||
|
return str_escape_ex(str, buffer, size, "\n\t\r\'\"\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *str_escape_slow(const char *str, char *buffer, size_t size) {
|
||||||
|
const char *read = str;
|
||||||
|
char *write = buffer;
|
||||||
|
if (size < 1) return NULL;
|
||||||
|
while (size > 1 && *read) {
|
||||||
|
size_t len;
|
||||||
|
const char *pos = read;
|
||||||
|
while (pos + 1 < read + size && *pos) {
|
||||||
|
unsigned char ch = *(unsigned char *)pos;
|
||||||
|
if (iscntrl(ch) || ch == '\"' || ch == '\\' || ch == '\'' || ch == '\n' || ch == '\r' || ch == '\t') {
|
||||||
|
len = pos - read;
|
||||||
|
memmove(write, read, len);
|
||||||
|
write += len;
|
||||||
|
size -= len;
|
||||||
|
switch (ch) {
|
||||||
|
case '\t':
|
||||||
|
if (size > 2) {
|
||||||
|
*write++ = '\\';
|
||||||
|
*write++ = 't';
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
if (size > 2) {
|
||||||
|
*write++ = '\\';
|
||||||
|
*write++ = 'n';
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
if (size > 2) {
|
||||||
|
*write++ = '\\';
|
||||||
|
*write++ = 'r';
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
case '\'':
|
||||||
|
case '\\':
|
||||||
|
if (size > 2) {
|
||||||
|
*write++ = '\\';
|
||||||
|
*write++ = ch;
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (size > 5) {
|
||||||
|
int n = sprintf(write, "\\%03o", ch);
|
||||||
|
if (n > 0) {
|
||||||
|
assert(n == 5);
|
||||||
|
write += n;
|
||||||
|
size -= n;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
}
|
||||||
|
else size = 1;
|
||||||
|
}
|
||||||
|
assert(size > 0);
|
||||||
|
read = pos + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
if (read < pos) {
|
||||||
|
len = pos - read;
|
||||||
|
memmove(write, read, len);
|
||||||
|
read = pos;
|
||||||
|
write += len;
|
||||||
|
size -= len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*write = '\0';
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
|
@ -32,7 +32,8 @@ extern "C" {
|
||||||
size_t str_strlcat(char *dst, const char *src, size_t len);
|
size_t str_strlcat(char *dst, const char *src, size_t len);
|
||||||
char *str_strdup(const char *s);
|
char *str_strdup(const char *s);
|
||||||
|
|
||||||
const char *str_escape(const char *str, char *buffer, size_t len);
|
const char *str_escape(const char *str, char *buffer, size_t size);
|
||||||
|
const char *str_escape_ex(const char *str, char *buffer, size_t size, const char *chars);
|
||||||
char *str_unescape(char *str);
|
char *str_unescape(char *str);
|
||||||
|
|
||||||
unsigned int jenkins_hash(unsigned int a);
|
unsigned int jenkins_hash(unsigned int a);
|
||||||
|
|
|
@ -24,10 +24,24 @@ static void test_str_unescape(CuTest * tc)
|
||||||
|
|
||||||
static void test_str_escape(CuTest * tc)
|
static void test_str_escape(CuTest * tc)
|
||||||
{
|
{
|
||||||
char scratch[64];
|
char scratch[16];
|
||||||
CuAssertStrEquals(tc, "12345678901234567890", str_escape("12345678901234567890", scratch, 16));
|
|
||||||
CuAssertStrEquals(tc, "123456789\\\"12345", str_escape("123456789\"1234567890", scratch, 16));
|
CuAssertPtrEquals(tc, NULL, (void *)str_escape("1234", scratch, 0));
|
||||||
CuAssertStrEquals(tc, "1234567890123456", str_escape("1234567890123456\"890", scratch, 16));
|
CuAssertStrEquals(tc, "", str_escape("1234", scratch, 1));
|
||||||
|
CuAssertStrEquals(tc, "1", str_escape("1234", scratch, 2));
|
||||||
|
CuAssertStrEquals(tc, "\\n", str_escape("\n234", scratch, 3));
|
||||||
|
|
||||||
|
CuAssertStrEquals(tc, "\\n\\r\\t\\\\\\\"\\\'", str_escape("\n\r\t\\\"\'", scratch, 16));
|
||||||
|
CuAssertStrEquals(tc, "12345678", str_escape("12345678", scratch, 16));
|
||||||
|
CuAssertStrEquals(tc, "123456789012345", str_escape("123456789012345", scratch, 16));
|
||||||
|
CuAssertStrEquals(tc, "12345678901234", str_escape("12345678901234\n", scratch, 15));
|
||||||
|
CuAssertStrEquals(tc, "123456789012345", str_escape("12345678901234567890", scratch, 16));
|
||||||
|
|
||||||
|
CuAssertStrEquals(tc, "\\\\\\\"234", str_escape("\\\"234567890", scratch, 8));
|
||||||
|
CuAssertStrEquals(tc, "\\\"\\\\234", str_escape("\"\\234567890", scratch, 8));
|
||||||
|
CuAssertStrEquals(tc, "123456789012345", str_escape("12345678901234567890", scratch, 16));
|
||||||
|
CuAssertStrEquals(tc, "123456789\\\"1234", str_escape("123456789\"1234567890", scratch, 16));
|
||||||
|
CuAssertStrEquals(tc, "123456789012345", str_escape("1234567890123456\"890", scratch, 16));
|
||||||
CuAssertStrEquals(tc, "hello world", str_escape("hello world", scratch, sizeof(scratch)));
|
CuAssertStrEquals(tc, "hello world", str_escape("hello world", scratch, sizeof(scratch)));
|
||||||
CuAssertStrEquals(tc, "hello \\\"world\\\"", str_escape("hello \"world\"", scratch, sizeof(scratch)));
|
CuAssertStrEquals(tc, "hello \\\"world\\\"", str_escape("hello \"world\"", scratch, sizeof(scratch)));
|
||||||
CuAssertStrEquals(tc, "\\\"\\\\", str_escape("\"\\", scratch, sizeof(scratch)));
|
CuAssertStrEquals(tc, "\\\"\\\\", str_escape("\"\\", scratch, sizeof(scratch)));
|
||||||
|
|
Loading…
Reference in a new issue