Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAras Pranckevicius <aras@nesnausk.org>2022-07-10 18:27:07 +0300
committerAras Pranckevicius <aras@nesnausk.org>2022-07-28 17:03:06 +0300
commit38f8dfa611158f9d529ec89f27d5732e91e27cf8 (patch)
tree2710e36d108967dd84de67273b265d8f84d8d491
parent0167920d0bde3187a7ffb75d04541ece8c725a86 (diff)
Fix T99536: new 3.2 OBJ importer fails with trailing space after wrapped lines
Address the issue by re-working line continuation handling: stop trying to parse sequences like "backslash, newline" (which is the bug: it should also handle "backslash, possible whitespace, newline") during parsing. Instead, fixup line continuations after reading chunks of input file data - turn backslash and the following newline into spaces. The rest of parsing code does not have to be aware of them at all then. Makes the file attached to T99536 load correctly now. # Conflicts: # source/blender/io/common/intern/string_utils_test.cc # source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc # source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh
-rw-r--r--source/blender/io/common/IO_string_utils.hh11
-rw-r--r--source/blender/io/common/intern/string_utils.cc26
-rw-r--r--source/blender/io/common/intern/string_utils_test.cc23
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc9
4 files changed, 54 insertions, 15 deletions
diff --git a/source/blender/io/common/IO_string_utils.hh b/source/blender/io/common/IO_string_utils.hh
index 25f1f01c6ed..23cb5ec7d84 100644
--- a/source/blender/io/common/IO_string_utils.hh
+++ b/source/blender/io/common/IO_string_utils.hh
@@ -16,21 +16,22 @@ namespace blender::io {
* The returned line will not have '\n' characters at the end;
* the `buffer` is modified to contain remaining text without
* the input line.
- *
- * Note that backslash (\) character is treated as a line
- * continuation, similar to OBJ file format or a C preprocessor.
*/
StringRef read_next_line(StringRef &buffer);
/**
+ * Fix up OBJ line continuations by replacing backslash (\) and the
+ * following newline with spaces.
+ */
+void fixup_line_continuations(char *p, char *end);
+
+/**
* Drop leading white-space from a StringRef.
- * Note that backslash character is considered white-space.
*/
StringRef drop_whitespace(StringRef str);
/**
* Drop leading non-white-space from a StringRef.
- * Note that backslash character is considered white-space.
*/
StringRef drop_non_whitespace(StringRef str);
diff --git a/source/blender/io/common/intern/string_utils.cc b/source/blender/io/common/intern/string_utils.cc
index 3a12250e14b..eff50e40f13 100644
--- a/source/blender/io/common/intern/string_utils.cc
+++ b/source/blender/io/common/intern/string_utils.cc
@@ -18,14 +18,12 @@ StringRef read_next_line(StringRef &buffer)
const char *start = buffer.begin();
const char *end = buffer.end();
size_t len = 0;
- char prev = 0;
const char *ptr = start;
while (ptr < end) {
char c = *ptr++;
- if (c == '\n' && prev != '\\') {
+ if (c == '\n') {
break;
}
- prev = c;
++len;
}
@@ -35,7 +33,27 @@ StringRef read_next_line(StringRef &buffer)
static bool is_whitespace(char c)
{
- return c <= ' ' || c == '\\';
+ return c <= ' ';
+}
+
+void fixup_line_continuations(char *p, char *end)
+{
+ while (true) {
+ /* Find next backslash, if any. */
+ char *backslash = std::find(p, end, '\\');
+ if (backslash == end)
+ break;
+ /* Skip over possible whitespace right after it. */
+ p = backslash + 1;
+ while (p < end && is_whitespace(*p) && *p != '\n')
+ ++p;
+ /* If then we have a newline, turn both backslash
+ * and the newline into regular spaces. */
+ if (p < end && *p == '\n') {
+ *backslash = ' ';
+ *p = ' ';
+ }
+ }
}
StringRef drop_whitespace(StringRef str)
diff --git a/source/blender/io/common/intern/string_utils_test.cc b/source/blender/io/common/intern/string_utils_test.cc
index a78bd7ab8a3..91b94d22fb9 100644
--- a/source/blender/io/common/intern/string_utils_test.cc
+++ b/source/blender/io/common/intern/string_utils_test.cc
@@ -10,17 +10,34 @@ namespace blender::io {
TEST(string_utils, read_next_line)
{
- std::string str = "abc\n \n\nline with \\\ncontinuation\nCRLF ending:\r\na";
+ std::string str = "abc\n \n\nline with \t spaces\nCRLF ending:\r\na";
StringRef s = str;
EXPECT_STRREF_EQ("abc", read_next_line(s));
EXPECT_STRREF_EQ(" ", read_next_line(s));
EXPECT_STRREF_EQ("", read_next_line(s));
- EXPECT_STRREF_EQ("line with \\\ncontinuation", read_next_line(s));
+ EXPECT_STRREF_EQ("line with \t spaces", read_next_line(s));
EXPECT_STRREF_EQ("CRLF ending:\r", read_next_line(s));
EXPECT_STRREF_EQ("a", read_next_line(s));
EXPECT_TRUE(s.is_empty());
}
+TEST(string_utils, fixup_line_continuations)
+{
+ const char *str =
+ "backslash \\\n eol\n"
+ "backslash spaces \\ \n eol\n"
+ "without eol \\ is \\\\ \\ left intact\n"
+ "\\";
+ const char *exp =
+ "backslash eol\n"
+ "backslash spaces eol\n"
+ "without eol \\ is \\\\ \\ left intact\n"
+ "\\";
+ std::string buf(str);
+ fixup_line_continuations(buf.data(), buf.data() + buf.size());
+ EXPECT_STRREF_EQ(exp, buf);
+}
+
TEST(string_utils, drop_whitespace)
{
/* Empty */
@@ -36,7 +53,7 @@ TEST(string_utils, drop_whitespace)
/* No leading whitespace */
EXPECT_STRREF_EQ("c", drop_whitespace("c"));
/* Case with backslash, should be treated as whitespace */
- EXPECT_STRREF_EQ("d", drop_whitespace(" \\ d"));
+ EXPECT_STRREF_EQ("d", drop_whitespace(" \t d"));
}
TEST(string_utils, parse_int_valid)
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
index 94d723cacf5..f801bb1d3fa 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
@@ -375,6 +375,11 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
break; /* No more data to read. */
}
+ /* Take care of line continuations now (turn them into spaces);
+ * the rest of the parsing code does not need to worry about them anymore. */
+ fixup_line_continuations(buffer.data() + buffer_offset,
+ buffer.data() + buffer_offset + bytes_read);
+
/* Ensure buffer ends in a newline. */
if (bytes_read < read_buffer_size_) {
if (bytes_read == 0 || buffer[buffer_offset + bytes_read - 1] != '\n') {
@@ -393,9 +398,7 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
while (last_nl > 0) {
--last_nl;
if (buffer[last_nl] == '\n') {
- if (last_nl < 1 || buffer[last_nl - 1] != '\\') {
- break;
- }
+ break;
}
}
if (buffer[last_nl] != '\n') {