Add zero-value check when parsing `f' line. Fixes #140.
This commit is contained in:
2
models/issue-140-zero-face-idx.mtl
Normal file
2
models/issue-140-zero-face-idx.mtl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
newmtl main
|
||||||
|
Kd 1 1 1
|
||||||
17
models/issue-140-zero-face-idx.obj
Normal file
17
models/issue-140-zero-face-idx.obj
Normal 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
|
||||||
@@ -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(
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user