diff options
author | Syoyo Fujita <syoyo@lighttransport.com> | 2017-09-25 02:30:24 +0900 |
---|---|---|
committer | Syoyo Fujita <syoyo@lighttransport.com> | 2017-09-25 02:30:24 +0900 |
commit | 75a4bd1d35f489808a3e4dc52d0f9121823fe5f4 (patch) | |
tree | 1fc43a8d5334f96cdf6615ebcbfa473b5cf43067 | |
parent | 7c7335c907907d04bb22c56d1af59e5c88e943f6 (diff) | |
download | tinyobjloader-75a4bd1d35f489808a3e4dc52d0f9121823fe5f4.tar.gz |
Add zero-value check when parsing `f' line. Fixes #140.
-rw-r--r-- | models/issue-140-zero-face-idx.mtl | 2 | ||||
-rw-r--r-- | models/issue-140-zero-face-idx.obj | 17 | ||||
-rw-r--r-- | tests/tester.cc | 17 | ||||
-rw-r--r-- | tiny_obj_loader.h | 115 |
4 files changed, 115 insertions, 36 deletions
diff --git a/models/issue-140-zero-face-idx.mtl b/models/issue-140-zero-face-idx.mtl new file mode 100644 index 0000000..990a345 --- /dev/null +++ b/models/issue-140-zero-face-idx.mtl @@ -0,0 +1,2 @@ +newmtl main +Kd 1 1 1 diff --git a/models/issue-140-zero-face-idx.obj b/models/issue-140-zero-face-idx.obj new file mode 100644 index 0000000..21a6060 --- /dev/null +++ b/models/issue-140-zero-face-idx.obj @@ -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 diff --git a/tests/tester.cc b/tests/tester.cc index 5c31cc9..4a97f86 100644 --- a/tests/tester.cc +++ b/tests/tester.cc @@ -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 int main( diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 4e2f6b5..6f0515b 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -100,11 +100,11 @@ namespace tinyobj { // cube_left | cube_right #ifdef TINYOBJLOADER_USE_DOUBLE - //#pragma message "using double" - typedef double real_t; +//#pragma message "using double" +typedef double real_t; #else - //#pragma message "using float" - typedef float real_t; +//#pragma message "using float" +typedef float real_t; #endif typedef enum { @@ -119,7 +119,7 @@ typedef enum { } texture_type_t; typedef struct { - texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) real_t sharpness; // -boost (default 1.0?) real_t brightness; // base_value in -mm option (default 0) real_t contrast; // gain_value in -mm option (default 1) @@ -364,7 +364,6 @@ namespace tinyobj { MaterialReader::~MaterialReader() {} - struct vertex_index { int v_idx, vt_idx, vn_idx; 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')) // Make index zero-base, and also support relative index. -static inline int fixIndex(int idx, int n) { - if (idx > 0) return idx - 1; - if (idx == 0) return 0; - return n + idx; // negative value = relative +static inline bool fixIndex(int idx, int n, int *ret) { + if (!ret) { + return false; + } + + 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) { @@ -584,9 +600,9 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) { } assemble: - *result = - (sign == '+' ? 1 : -1) * - (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) : mantissa); + *result = (sign == '+' ? 1 : -1) * + (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) + : mantissa); return true; fail: return false; @@ -603,16 +619,16 @@ static inline real_t parseReal(const char **token, double default_value = 0.0) { } static inline void parseReal2(real_t *x, real_t *y, const char **token, - const double default_x = 0.0, - const double default_y = 0.0) { + const double default_x = 0.0, + const double default_y = 0.0) { (*x) = parseReal(token, default_x); (*y) = parseReal(token, default_y); } -static inline void parseReal3(real_t *x, real_t *y, real_t *z, const char **token, - const double default_x = 0.0, - const double default_y = 0.0, - const double default_z = 0.0) { +static inline void parseReal3(real_t *x, real_t *y, real_t *z, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { (*x) = parseReal(token, default_x); (*y) = parseReal(token, default_y); (*z) = parseReal(token, default_z); @@ -694,37 +710,57 @@ static tag_sizes parseTagTriple(const char **token) { } // Parse triples with index offsets: i, i/j/k, i//k, i/j -static vertex_index parseTriple(const char **token, int vsize, int vnsize, - int vtsize) { +static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize, + vertex_index *ret) { + if (!ret) { + return false; + } + 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"); if ((*token)[0] != '/') { - return vi; + (*ret) = vi; + return true; } (*token)++; // i//k if ((*token)[0] == '/') { (*token)++; - vi.vn_idx = fixIndex(atoi((*token)), vnsize); + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } (*token) += strcspn((*token), "/ \t\r"); - return vi; + (*ret) = vi; + return true; } // 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"); if ((*token)[0] != '/') { - return vi; + (*ret) = vi; + return true; } // i/j/k (*token)++; // skip '/' - vi.vn_idx = fixIndex(atoi((*token)), vnsize); + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } (*token) += strcspn((*token), "/ \t\r"); - return vi; + + (*ret) = vi; + + return true; } // Parse raw triples: i, i/j/k, i//k, i/j @@ -813,15 +849,15 @@ static bool ParseTextureNameAndOption(std::string *texname, } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { token += 3; parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), - &(texopt->origin_offset[2]), &token); + &(texopt->origin_offset[2]), &token); } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { token += 3; parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), - &token, 1.0, 1.0, 1.0); + &token, 1.0, 1.0, 1.0); } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { token += 3; parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), - &(texopt->turbulence[2]), &token); + &(texopt->turbulence[2]), &token); } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { token += 5; texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); @@ -1532,9 +1568,16 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes, face.reserve(3); while (!IS_NEW_LINE(token[0])) { - vertex_index vi = parseTriple(&token, static_cast<int>(v.size() / 3), - static_cast<int>(vn.size() / 3), - static_cast<int>(vt.size() / 2)); + vertex_index vi; + if (!parseTriple(&token, static_cast<int>(v.size() / 3), + static_cast<int>(vn.size() / 3), + 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); size_t n = strspn(token, " \t\r"); token += n; @@ -1622,7 +1665,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes, // flush previous face group. bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, triangulate); - (void)ret; // return value not used. + (void)ret; // return value not used. if (shape.mesh.indices.size() > 0) { shapes->push_back(shape); |