Add zero-value check when parsing `f' line. Fixes #140.

This commit is contained in:
Syoyo Fujita
2017-09-25 02:30:24 +09:00
parent 7c7335c907
commit 75a4bd1d35
4 changed files with 115 additions and 36 deletions

View File

@@ -0,0 +1,2 @@
newmtl main
Kd 1 1 1

View File

@@ -0,0 +1,17 @@
mtllib issue-140-zero-face-idx.mtl
v -0.5 -0.5 0
v 0.5 -0.5 0
v 0.5 0.5 0
v -0.5 0.5 0
vt 0 0 0
vt 1 0 0
vt 1 1 0
vt 0 1 0
vn 0 0 -1
usemtl main
f 0/0/0 1/1/0 3/3/0
f 1/1/0 3/3/0 2/2/0

View File

@@ -643,6 +643,23 @@ TEST_CASE("norm_texopts", "[norm]") {
} }
TEST_CASE("zero-face-idx-value", "[Issue140]") {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/issue-140-zero-face-idx.obj", gMtlBasePath);
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(false == ret);
REQUIRE(!err.empty());
}
#if 0 #if 0
int int
main( main(

View File

@@ -100,11 +100,11 @@ namespace tinyobj {
// cube_left | cube_right // cube_left | cube_right
#ifdef TINYOBJLOADER_USE_DOUBLE #ifdef TINYOBJLOADER_USE_DOUBLE
//#pragma message "using double" //#pragma message "using double"
typedef double real_t; typedef double real_t;
#else #else
//#pragma message "using float" //#pragma message "using float"
typedef float real_t; typedef float real_t;
#endif #endif
typedef enum { typedef enum {
@@ -364,7 +364,6 @@ namespace tinyobj {
MaterialReader::~MaterialReader() {} MaterialReader::~MaterialReader() {}
struct vertex_index { struct vertex_index {
int v_idx, vt_idx, vn_idx; int v_idx, vt_idx, vn_idx;
vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
@@ -428,10 +427,27 @@ static std::istream &safeGetline(std::istream &is, std::string &t) {
#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) #define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
// Make index zero-base, and also support relative index. // Make index zero-base, and also support relative index.
static inline int fixIndex(int idx, int n) { static inline bool fixIndex(int idx, int n, int *ret) {
if (idx > 0) return idx - 1; if (!ret) {
if (idx == 0) return 0; return false;
return n + idx; // negative value = relative }
if (idx > 0) {
(*ret) = idx - 1;
return true;
}
if (idx == 0) {
// zero is not allowed according to the spec.
return false;
}
if (idx < 0) {
(*ret) = n + idx; // negative value = relative
return true;
}
return false; // never reach here.
} }
static inline std::string parseString(const char **token) { static inline std::string parseString(const char **token) {
@@ -584,9 +600,9 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
} }
assemble: assemble:
*result = *result = (sign == '+' ? 1 : -1) *
(sign == '+' ? 1 : -1) * (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent)
(exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) : mantissa); : mantissa);
return true; return true;
fail: fail:
return false; return false;
@@ -609,8 +625,8 @@ static inline void parseReal2(real_t *x, real_t *y, const char **token,
(*y) = parseReal(token, default_y); (*y) = parseReal(token, default_y);
} }
static inline void parseReal3(real_t *x, real_t *y, real_t *z, const char **token, static inline void parseReal3(real_t *x, real_t *y, real_t *z,
const double default_x = 0.0, const char **token, const double default_x = 0.0,
const double default_y = 0.0, const double default_y = 0.0,
const double default_z = 0.0) { const double default_z = 0.0) {
(*x) = parseReal(token, default_x); (*x) = parseReal(token, default_x);
@@ -694,37 +710,57 @@ static tag_sizes parseTagTriple(const char **token) {
} }
// Parse triples with index offsets: i, i/j/k, i//k, i/j // Parse triples with index offsets: i, i/j/k, i//k, i/j
static vertex_index parseTriple(const char **token, int vsize, int vnsize, static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize,
int vtsize) { vertex_index *ret) {
if (!ret) {
return false;
}
vertex_index vi(-1); vertex_index vi(-1);
vi.v_idx = fixIndex(atoi((*token)), vsize); if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) {
return false;
}
(*token) += strcspn((*token), "/ \t\r"); (*token) += strcspn((*token), "/ \t\r");
if ((*token)[0] != '/') { if ((*token)[0] != '/') {
return vi; (*ret) = vi;
return true;
} }
(*token)++; (*token)++;
// i//k // i//k
if ((*token)[0] == '/') { if ((*token)[0] == '/') {
(*token)++; (*token)++;
vi.vn_idx = fixIndex(atoi((*token)), vnsize); if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) {
return false;
}
(*token) += strcspn((*token), "/ \t\r"); (*token) += strcspn((*token), "/ \t\r");
return vi; (*ret) = vi;
return true;
} }
// i/j/k or i/j // i/j/k or i/j
vi.vt_idx = fixIndex(atoi((*token)), vtsize); if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx))) {
return false;
}
(*token) += strcspn((*token), "/ \t\r"); (*token) += strcspn((*token), "/ \t\r");
if ((*token)[0] != '/') { if ((*token)[0] != '/') {
return vi; (*ret) = vi;
return true;
} }
// i/j/k // i/j/k
(*token)++; // skip '/' (*token)++; // skip '/'
vi.vn_idx = fixIndex(atoi((*token)), vnsize); if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) {
return false;
}
(*token) += strcspn((*token), "/ \t\r"); (*token) += strcspn((*token), "/ \t\r");
return vi;
(*ret) = vi;
return true;
} }
// Parse raw triples: i, i/j/k, i//k, i/j // Parse raw triples: i, i/j/k, i//k, i/j
@@ -1532,9 +1568,16 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
face.reserve(3); face.reserve(3);
while (!IS_NEW_LINE(token[0])) { while (!IS_NEW_LINE(token[0])) {
vertex_index vi = parseTriple(&token, static_cast<int>(v.size() / 3), vertex_index vi;
if (!parseTriple(&token, static_cast<int>(v.size() / 3),
static_cast<int>(vn.size() / 3), static_cast<int>(vn.size() / 3),
static_cast<int>(vt.size() / 2)); static_cast<int>(vt.size() / 2), &vi)) {
if (err) {
(*err) = "Failed parse `f' line(e.g. zero value for face index).\n";
}
return false;
}
face.push_back(vi); face.push_back(vi);
size_t n = strspn(token, " \t\r"); size_t n = strspn(token, " \t\r");
token += n; token += n;