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
|
@ -517,7 +517,7 @@ static void report_crtypes(FILE * F, const struct locale *lang)
|
|||
assert(hash > 0);
|
||||
fprintf(F, "MESSAGETYPE %d\n", hash);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const char *text;
|
||||
|
@ -151,7 +160,7 @@ int stream_order(struct stream *out, const struct order *ord, const struct local
|
|||
char obuf[1024];
|
||||
swrite(" ", 1, 1, out);
|
||||
if (escape) {
|
||||
text = str_escape(text, obuf, sizeof(obuf));
|
||||
text = crescape(text, obuf, sizeof(obuf));
|
||||
}
|
||||
swrite(text, 1, strlen(text), out);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ extern "C" {
|
|||
bool is_exclusive(const order * ord);
|
||||
bool is_repeated(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 *buffer, size_t size);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <tests.h>
|
||||
#include <CuTest.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void test_create_order(CuTest *tc) {
|
||||
char cmd[32];
|
||||
|
@ -484,10 +485,62 @@ static void test_study_order_unknown_quoted(CuTest *tc) {
|
|||
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 *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_crescape);
|
||||
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_order);
|
||||
SUITE_ADD_TEST(suite, test_study_order_unknown);
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
static int read_permissions(variant *var, void *owner, struct gamedata *data)
|
||||
{
|
||||
attrib *a;
|
||||
attrib *a = NULL;
|
||||
UNUSED_ARG(var);
|
||||
read_attribs(data, &a, owner);
|
||||
a_remove(&a, a);
|
||||
|
|
|
@ -172,8 +172,8 @@ static order *monster_attack(unit * u, const unit * target)
|
|||
if (monster_is_waiting(u))
|
||||
return NULL;
|
||||
|
||||
if (u->region->land) {
|
||||
assert(u->region->flags & RF_GUARDED);
|
||||
if (u->region->land && (u->region->flags & RF_GUARDED) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
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>
|
||||
#endif
|
||||
#include "strings.h"
|
||||
#include "assert.h"
|
||||
|
||||
/* libc includes */
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
@ -155,27 +155,28 @@ int str_hash(const char *s)
|
|||
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, '\"');
|
||||
if (!handle_start) handle_start = strchr(str, '\\');
|
||||
assert(buffer);
|
||||
if (handle_start) {
|
||||
const char *p;
|
||||
char *o;
|
||||
const char *p = str;
|
||||
char *o = buffer;
|
||||
size_t skip = handle_start - str;
|
||||
|
||||
if (skip > len) {
|
||||
skip = len;
|
||||
}
|
||||
memcpy(buffer, str, skip);
|
||||
o = buffer + skip;
|
||||
p = str + skip;
|
||||
len -= skip;
|
||||
if (skip > 0) {
|
||||
memcpy(buffer, str, skip);
|
||||
o += skip;
|
||||
p += skip;
|
||||
len -= skip;
|
||||
}
|
||||
do {
|
||||
if (*p == '\"' || *p == '\\') {
|
||||
if (len < 2) {
|
||||
*o = '\0';
|
||||
break;
|
||||
}
|
||||
(*o++) = '\\';
|
||||
|
@ -183,13 +184,15 @@ const char *str_escape(const char *str, char *buffer, size_t len)
|
|||
}
|
||||
else {
|
||||
if (len < 1) {
|
||||
*o = '\0';
|
||||
break;
|
||||
}
|
||||
--len;
|
||||
}
|
||||
(*o++) = (*p);
|
||||
} while (*p++);
|
||||
if (len > 0) {
|
||||
(*o++) = (*p);
|
||||
}
|
||||
} while (len > 0 && *p++);
|
||||
*o = '\0';
|
||||
return buffer;
|
||||
}
|
||||
return str;
|
||||
|
@ -306,3 +309,166 @@ char *str_unescape(char *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);
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
char scratch[64];
|
||||
CuAssertStrEquals(tc, "12345678901234567890", str_escape("12345678901234567890", scratch, 16));
|
||||
CuAssertStrEquals(tc, "123456789\\\"12345", str_escape("123456789\"1234567890", scratch, 16));
|
||||
CuAssertStrEquals(tc, "1234567890123456", str_escape("1234567890123456\"890", scratch, 16));
|
||||
char scratch[16];
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, (void *)str_escape("1234", scratch, 0));
|
||||
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, "\\\"\\\\", str_escape("\"\\", scratch, sizeof(scratch)));
|
||||
|
|
Loading…
Reference in New Issue