diff --git a/README.md b/README.md index 36b34b2..ed13cf2 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Tiny but powerful single file wavefront obj loader written in C++. No dependency `tinyobjloader` is good for embedding .obj loader to your (global illumination) renderer ;-) +If you are looking for C89 version, please see https://github.com/syoyo/tinyobjloader-c . + Notice! ------- diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index c2b49b3..0200ff5 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -257,6 +257,38 @@ struct obj_shape { std::vector vt; }; +// See +// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf +static std::istream &safeGetline(std::istream &is, std::string &t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf *sb = is.rdbuf(); + + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') sb->sbumpc(); + return is; + case EOF: + // Also handle the case when the last line has no line ending + if (t.empty()) is.setstate(std::ios::eofbit); + return is; + default: + t += static_cast(c); + } + } +} + #define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) #define IS_DIGIT(x) \ (static_cast((x) - '0') < static_cast(10)) @@ -646,12 +678,10 @@ void LoadMtl(std::map *material_map, material_t material; InitMaterial(&material); - size_t maxchars = 8192; // Alloc enough size. - std::vector buf(maxchars); // Alloc enough size. while (inStream->peek() != -1) { - inStream->getline(&buf[0], static_cast(maxchars)); + std::string linebuf; - std::string linebuf(&buf[0]); + safeGetline(*inStream, linebuf); // Trim trailing whitespace. if (linebuf.size() > 0) { @@ -1031,7 +1061,7 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, while (inStream->peek() != -1) { std::string linebuf; - std::getline((*inStream), linebuf); + safeGetline(*inStream, linebuf); // Trim newline '\r\n' or '\n' if (linebuf.size() > 0) { @@ -1312,7 +1342,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, std::string linebuf; while (inStream.peek() != -1) { - std::getline(inStream, linebuf); + safeGetline(inStream, linebuf); // Trim newline '\r\n' or '\n' if (linebuf.size() > 0) {