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
int
main(

View File

@@ -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 {
@@ -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;
@@ -609,8 +625,8 @@ static inline void parseReal2(real_t *x, real_t *y, const char **token,
(*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,
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);
@@ -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
@@ -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),
vertex_index vi;
if (!parseTriple(&token, static_cast<int>(v.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);
size_t n = strspn(token, " \t\r");
token += n;