Skip to content

Commit d27b678

Browse files
committed
Merge pull request #6 from masonlet/refactor/improve-test-output
Refactor/improve test output
2 parents 41fa642 + bf3dbe6 commit d27b678

20 files changed

Lines changed: 782 additions & 497 deletions

inc/starlet-serializer/parser/parser.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ namespace Serializer {
1919
#define STARLET_PARSE_OR(onFail, parser, target, errorMsg) \
2020
do { \
2121
if (!(parser(p, target))) { \
22-
if((errorMsg) && *(errorMsg) != '\0') fprintf(stderr, "[Parser ERROR]: Failed to parse %s\n", errorMsg); \
22+
if((errorMsg) && *(errorMsg) != '\0') { \
23+
fprintf(stderr, "[Parser ERROR]: Failed to parse %s\n", errorMsg); \
24+
} \
2325
onFail; \
2426
} \
2527
} while(0)

src/parser/image/bmp_parser.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ bool BmpParser::parseHeader(const unsigned char* p, size_t fileSize, uint32_t& w
4444
if (!validateFileSignature(p, fileSize)) return false;
4545

4646
dataOffset = readUint32(p, 10);
47-
if (dataOffset >= fileSize) return Logger::error("BmpParser", "parseHeader", "Invalid data offset: " + std::to_string(dataOffset));
47+
const size_t actualDataSize = fileSize > 0 ? fileSize - 1 : 0;
48+
if (dataOffset >= actualDataSize)
49+
return Logger::error("BmpParser", "parseHeader", "Invalid data offset: " + std::to_string(dataOffset));
4850

4951
uint32_t dibSize = readUint32(p, 14);
5052
if (dibSize < BMP_DIB_HEADER_SIZE_MIN) return Logger::error("BmpParser", "parseHeader", "Unsupported DIB header size: " + std::to_string(dibSize));
@@ -82,7 +84,8 @@ bool BmpParser::copyPixelData(const unsigned char* p, size_t fileSize, uint32_t
8284
const size_t rowStridePadded = (static_cast<size_t>(width) * 3 + 3) & ~static_cast<size_t>(3);
8385
const size_t needed = static_cast<size_t>(dataOffset) + rowStridePadded * static_cast<size_t>(height);
8486

85-
if (needed > fileSize)
87+
const size_t actualDataSize = fileSize > 0 ? fileSize - 1 : 0;
88+
if (needed > actualDataSize)
8689
return Logger::error("BmpParser", "copyPixelData", "File too small for declared dimensions: " + std::to_string(fileSize) + " bytes, need " + std::to_string(needed) + " bytes");
8790

8891
const unsigned char* srcPixels = p + dataOffset;

src/parser/image/image_parser_base.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ void ImageParserBase::clearImageData(ImageData& data) const {
1313

1414
std::optional<std::vector<unsigned char>> ImageParserBase::loadImageData(const std::string& path) {
1515
std::vector<unsigned char> file;
16-
if (!loadBinaryFile(file, path)) {
17-
Logger::error("ImageParserBase", "loadImageData", std::string("Failed to load file: ") + path);
18-
return std::nullopt;
19-
}
16+
if (!loadBinaryFile(file, path)) return std::nullopt;
2017

2118
if (file.empty()) {
2219
Logger::error("ImageParserBase", "loadImageData", "File is empty");

src/parser/mesh/ply_parser.cpp

Lines changed: 85 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ namespace {
1818

1919
bool PlyParser::parse(const std::string& path, MeshData& out) {
2020
std::vector<unsigned char> file;
21-
if (!loadBinaryFile(file, path))
22-
return false;
21+
if (!loadBinaryFile(file, path)) return false;
2322

24-
if (file.empty()) return Logger::error("PlyParser", "parse", "Input pointer is null\n");
23+
if (file.empty() || file[0] == '\0')
24+
return Logger::error("PlyParser", "parse", "File is empty");
2525

2626
const unsigned char* p = file.data();
2727
std::string errorMsg;
2828
while (true) {
2929
if (!parseHeaderLine(p, out.numVertices, out.numTriangles, out.hasNormals, out.hasColours, out.hasTexCoords)) {
30-
errorMsg = "header or missing 'end_header'";
30+
errorMsg = "header, 'end_header' not found";
3131
break;
3232
}
3333

@@ -55,16 +55,17 @@ bool PlyParser::parse(const std::string& path, MeshData& out) {
5555
out.indices.clear();
5656
out.vertices.clear();
5757
out.numVertices = out.numIndices = out.numTriangles = 0;
58-
return Logger::error("PlyParser", "parse", ("Failed to parse " + errorMsg + '\n').c_str());
58+
return Logger::error("PlyParser", "parse", ("Failed to parse " + errorMsg).c_str());
5959
}
6060

6161
bool PlyParser::parseHeaderLine(const unsigned char*& p, unsigned int& numVerticesOut, unsigned int& numTrianglesOut, bool& hasNormalsOut, bool& hasColoursOut, bool& hasTexCoordsOut) {
62-
if (!p) return Logger::error("PlyParser", "parseHeaderLine", "Input pointer is null\n");
62+
if (!p) return Logger::error("PlyParser", "parseHeaderLine", "Input pointer is null");
6363
p = skipWhitespace(p);
6464

6565
bool hasNx = false, hasNy = false, hasNz = false;
6666
bool hasRed = false, hasGreen = false, hasBlue = false;
6767
bool hasU = false, hasV = false;
68+
6869
while (*p) {
6970
const unsigned char* nextLine = skipToNextLine(p);
7071
const unsigned char* lineEnd = trimEOL(p, nextLine);
@@ -97,11 +98,11 @@ bool PlyParser::parseHeaderLine(const unsigned char*& p, unsigned int& numVertic
9798
p = nextLine;
9899
}
99100

100-
return Logger::error("plyParser", "parseHeaderLine", "Failed, end of buffer reached");
101+
return false;
101102
}
102103

103104
bool PlyParser::parseElementLine(const unsigned char*& p, unsigned int& verticesOut, unsigned int& trianglesOut) {
104-
if (!p) return Logger::error("PlyParser", "parseElementLine", "Input pointer is null\n");
105+
if (!p) return Logger::error("PlyParser", "parseElementLine", "Input pointer is null");
105106

106107
p = skipWhitespace(p += 7);
107108
if (strncmp((const char*)p, "vertex", 6) == 0 && (p[6] == ' ' || p[6] == '\t')) {
@@ -115,47 +116,44 @@ bool PlyParser::parseElementLine(const unsigned char*& p, unsigned int& vertices
115116
return false;
116117
}
117118
bool PlyParser::parsePropertyLine(const unsigned char*& p, bool& hasNx, bool& hasNy, bool& hasNz, bool& hasR, bool& hasG, bool& hasB, bool& hasU, bool& hasV) {
118-
if (!p) return Logger::error("PlyParser", "parsePropertyLine", "Input pointer is null\n");
119+
if (!p) return Logger::error("PlyParser", "parsePropertyLine", "Input pointer is null");
119120
p = skipWhitespace(p += 8);
120121

121122
char type[32]{};
122123
if (!parseToken(p, (unsigned char*)type, sizeof(type)))
123-
return Logger::error("PlyParser", "parsePropertyLine", "Failed to parse property type :" + std::string(type));
124+
return Logger::error("PlyParser", "parsePropertyLine", "Failed to parse property type: " + std::string(type));
124125

125126
if (strcmp(type, "list") == 0) {
126-
/*
127-
1 = Count Type
128-
2 = Value Type
129-
3 = Property Name
130-
*/
131-
char property[3][32]{};
132-
for (int i = 0; i < 3; ++i)
133-
if (!parseToken(p, reinterpret_cast<unsigned char*>(property[i]), sizeof(property[i])))
134-
return Logger::error("PlyParser", "parsePropertyLine", "Failed to parse property list type, number: " + std::to_string(i));
135-
127+
char countType[32]{}, valueType[32]{}, propertyName[32]{};
128+
if (!parseToken(p, reinterpret_cast<unsigned char*>(countType), sizeof(countType)))
129+
return Logger::error("PlyParser", "parsePropertyLine", "Failed to parse property list: count type");
130+
if (!parseToken(p, reinterpret_cast<unsigned char*>(valueType), sizeof(valueType)))
131+
return Logger::error("PlyParser", "parsePropertyLine", "Failed to parse property list: value type");
132+
if (!parseToken(p, reinterpret_cast<unsigned char*>(propertyName), sizeof(propertyName)))
133+
return Logger::error("PlyParser", "parsePropertyLine", "Failed to parse property list: property name");
136134
return true;
137135
}
138136

139137
char propertyName[32]{};
140138
if (!parseToken(p, (unsigned char*)propertyName, sizeof(propertyName)))
141-
return Logger::error("PlyParser", "parsePropertyLine", "Failed to parse property name :" + std::string(propertyName));
139+
return Logger::error("PlyParser", "parsePropertyLine", "Failed to parse property name: " + std::string(propertyName));
142140

143-
if (strcmp(propertyName, "nx") == 0 || strcmp(propertyName, "normal_x") == 0) hasNx = true;
141+
if (strcmp(propertyName, "nx") == 0 || strcmp(propertyName, "normal_x") == 0) hasNx = true;
144142
else if (strcmp(propertyName, "ny") == 0 || strcmp(propertyName, "normal_y") == 0) hasNy = true;
145143
else if (strcmp(propertyName, "nz") == 0 || strcmp(propertyName, "normal_z") == 0) hasNz = true;
146-
else if (strcmp(propertyName, "red") == 0) hasR = true;
144+
else if (strcmp(propertyName, "red") == 0) hasR = true;
147145
else if (strcmp(propertyName, "green") == 0) hasG = true;
148-
else if (strcmp(propertyName, "blue") == 0) hasB = true;
146+
else if (strcmp(propertyName, "blue") == 0) hasB = true;
149147
else if (strcmp(propertyName, "u") == 0 || strcmp(propertyName, "texture_u") == 0) hasU = true;
150148
else if (strcmp(propertyName, "v") == 0 || strcmp(propertyName, "texture_v") == 0) hasV = true;
151149
return true;
152150
}
153151

154152
bool PlyParser::parseVertices(const unsigned char*& p, MeshData& out) {
155-
if (!p) return Logger::error("PlyParser", "parseVertices", "Input pointer is null\n");
156-
if (!out.numVertices) return Logger::error("PlyParser", "parseVertices", "No vertices declared in header\n");
153+
if (!p) return Logger::error("PlyParser", "parseVertices", "Input pointer is null");
154+
if (!out.numVertices) return Logger::error("PlyParser", "parseVertices", "No vertices declared in header");
157155

158-
float minY = FLT_MAX, maxY = -FLT_MAX;
156+
float minY = FLT_MAX, maxY = -FLT_MAX;
159157
unsigned int i = 0;
160158
while (i < out.numVertices && *p) {
161159
Math::Vertex& v = out.vertices[i];
@@ -167,83 +165,54 @@ bool PlyParser::parseVertices(const unsigned char*& p, MeshData& out) {
167165
continue;
168166
}
169167

170-
if (*p == '\0') return false;
168+
if (*p == '\0') return Logger::error("PlyParser", "parseVertices", "Unexpected end of data");
171169

172-
bool valid = true;
173-
while (valid) {
174-
STARLET_PARSE_OR(valid = false, parseFloat, v.pos.x, "Failed to parse position X");
175-
STARLET_PARSE_OR(valid = false, parseFloat, v.pos.y, "Failed to parse position Y");
176-
STARLET_PARSE_OR(valid = false, parseFloat, v.pos.z, "Failed to parse position Z");
177-
break;
178-
}
179-
if (!valid) {
180-
p = nextLine;
181-
continue;
182-
}
170+
if (!parseFloat(p, v.pos.x))
171+
return Logger::error("PlyParser", "parseVertices", "Failed to parse position X at vertex " + std::to_string(i));
172+
if (!parseFloat(p, v.pos.y))
173+
return Logger::error("PlyParser", "parseVertices", "Failed to parse position Y at vertex " + std::to_string(i));
174+
if (!parseFloat(p, v.pos.z))
175+
return Logger::error("PlyParser", "parseVertices", "Failed to parse position Z at vertex " + std::to_string(i));
183176

184177
if (out.hasNormals) {
185-
while (valid) {
186-
STARLET_PARSE_OR(valid = false, parseFloat, v.norm.x, "Failed to parse normal X");
187-
STARLET_PARSE_OR(valid = false, parseFloat, v.norm.y, "Failed to parse normal Y");
188-
STARLET_PARSE_OR(valid = false, parseFloat, v.norm.z, "Failed to parse normal Z");
189-
break;
190-
}
191-
192-
if (!valid) {
193-
p = nextLine;
194-
continue;
195-
}
178+
if (!parseFloat(p, v.norm.x))
179+
return Logger::error("PlyParser", "parseVertices", "Failed to parse normal X at vertex " + std::to_string(i));
180+
if (!parseFloat(p, v.norm.y))
181+
return Logger::error("PlyParser", "parseVertices", "Failed to parse normal Y at vertex " + std::to_string(i));
182+
if (!parseFloat(p, v.norm.z))
183+
return Logger::error("PlyParser", "parseVertices", "Failed to parse normal Z at vertex " + std::to_string(i));
196184
}
197185

198186
if (out.hasColours) {
199-
if (*p != '\0') {
200-
Math::Vec3 colour = { 1.0f, 1.0f, 1.0f };
201-
const unsigned char* original = p;
202-
while (valid) {
203-
STARLET_PARSE_OR(valid = false, parseFloat, colour.r, "Failed to parse float colour R");
204-
STARLET_PARSE_OR(valid = false, parseFloat, colour.g, "Failed to parse float colour G");
205-
STARLET_PARSE_OR(valid = false, parseFloat, colour.b, "Failed to parse float colour B");
206-
break;
207-
}
208-
209-
if (valid &&
210-
colour.x >= 0.0f && colour.x <= 1.0f &&
211-
colour.y >= 0.0f && colour.y <= 1.0f &&
212-
colour.z >= 0.0f && colour.z <= 1.0f) {
213-
v.col = Math::Vec4{ colour.x, colour.y, colour.z, 1.0f };
214-
out.hasColours = true;
215-
}
216-
else {
217-
p = original;
218-
unsigned int ri = 0, gi = 0, bi = 0, ai = 256;
219-
220-
valid = true;
221-
while (valid) {
222-
STARLET_PARSE_OR(valid = false, parseUInt, ri, "");
223-
STARLET_PARSE_OR(valid = false, parseUInt, gi, "");
224-
STARLET_PARSE_OR(valid = false, parseUInt, bi, "");
225-
break;
226-
}
227-
if (!parseUInt(p, ai)) ai = 255;
228-
229-
if (valid && ri <= 255 && gi <= 255 && bi <= 255) {
230-
v.col = Math::Vec4{
231-
static_cast<float>(ri) / 255.0f,
232-
static_cast<float>(gi) / 255.0f,
233-
static_cast<float>(bi) / 255.0f,
234-
static_cast<float>(ai) / 255.0f
235-
};
236-
}
237-
}
187+
const unsigned char* original = p;
188+
Math::Vec3 colour = { 1.0f, 1.0f, 1.0f };
189+
190+
if (parseFloat(p, colour.r) &&
191+
parseFloat(p, colour.g) &&
192+
parseFloat(p, colour.b) &&
193+
colour.r <= 1.0f && colour.g <= 1.0f && colour.b <= 1.0f) {
194+
v.col = Math::Vec4{ colour.r, colour.g, colour.b, 1.0f };
195+
} else {
196+
p = original;
197+
unsigned int ri = 0, gi = 0, bi = 0, ai = 256;
198+
199+
if (!parseUInt(p, ri) || !parseUInt(p, gi) || !parseUInt(p, bi))
200+
return Logger::error("PlyParser", "parseVertices", "Failed to parse colour at vertex " + std::to_string(i));
201+
if (ri > 255 || gi > 255 || bi > 255)
202+
return Logger::error("PlyParser", "parseVertices", "Colour out of range at vertex " + std::to_string(i));
203+
204+
parseUInt(p, ai);
205+
if (ai > 255) ai = 255;
206+
207+
v.col = Math::Vec4{ ri / 255.0f, gi / 255.0f, bi / 255.0f, ai / 255.0f };
238208
}
239209
}
240210

241211
if (out.hasTexCoords) {
242-
while (valid) {
243-
STARLET_PARSE_OR(valid = false, parseFloat, v.texCoord.x, "Failed to parse texcoord U");
244-
STARLET_PARSE_OR(valid = false, parseFloat, v.texCoord.y, "Failed to parse texcoord V");
245-
break;
246-
}
212+
if (!parseFloat(p, v.texCoord.x))
213+
return Logger::error("PlyParser", "parseVertices", "Failed to parse texCoord X at vertex " + std::to_string(i));
214+
if (!parseFloat(p, v.texCoord.y))
215+
return Logger::error("PlyParser", "parseVertices", "Failed to parse texCoord Y at vertex " + std::to_string(i));
247216
}
248217

249218
if (v.pos.y < minY) minY = v.pos.y;
@@ -262,10 +231,13 @@ bool PlyParser::parseVertices(const unsigned char*& p, MeshData& out) {
262231
}
263232
bool PlyParser::parseIndices(const unsigned char*& p, MeshData& out) {
264233
if (!p) return Logger::error("PlyParser", "parseIndices", "Input pointer is null");
265-
if (out.indices.empty() || out.numIndices == 0) return Logger::error("PlyParser", "parseIndices", "Index buffer not allocated");
234+
if (out.indices.empty() || out.numIndices == 0)
235+
return Logger::error("PlyParser", "parseIndices", "Index buffer not allocated");
236+
237+
unsigned int i = 0;
238+
while (i < out.numTriangles) {
239+
if (!p || *p == '\0') break;
266240

267-
unsigned int triangleIndex = 0;
268-
while (triangleIndex < out.numTriangles && *p) {
269241
const unsigned char* nextLine = skipToNextLine(p);
270242
const unsigned char* lineEnd = trimEOL(p, nextLine);
271243

@@ -276,40 +248,31 @@ bool PlyParser::parseIndices(const unsigned char*& p, MeshData& out) {
276248

277249
unsigned int count = 0;
278250
if (!parseUInt(p, count)) {
279-
p = nextLine;
280-
continue;
251+
if (*p == '\0') break;
252+
return Logger::error("PlyParser", "parseIndices", "Failed to parse face vertex count at triangle " + std::to_string(i));
281253
}
282254

283-
if (count != 3) {
284-
p = nextLine;
285-
continue;
286-
}
255+
if (count != 3)
256+
return Logger::error("PlyParser", "parseIndices", "Non-triangle face detected (vertex count: " + std::to_string(count) + ") at triangle " + std::to_string(i));
287257

288258
unsigned int i0{ 0 }, i1{ 0 }, i2{ 0 };
289-
bool valid = true;
290-
while (valid) {
291-
STARLET_PARSE_OR(valid = false, parseUInt, i0, "Failed to parse index 1");
292-
STARLET_PARSE_OR(valid = false, parseUInt, i1, "Failed to parse index 2");
293-
STARLET_PARSE_OR(valid = false, parseUInt, i2, "Failed to parse index 3");
294-
break;
295-
}
259+
if (!parseUInt(p, i0) || !parseUInt(p, i1) || !parseUInt(p, i2))
260+
return Logger::error("PlyParser", "parseIndices", "Failed to parse face indices at triangle " + std::to_string(i));
296261

297-
if (valid) {
298-
if (i0 >= out.numVertices || i1 >= out.numVertices || i2 >= out.numVertices)
299-
return Logger::error("PlyParser", "parseIndices", "Index out of bounds: face references vertex >= " + std::to_string(out.numVertices));
300-
301-
unsigned int base = triangleIndex * 3;
302-
out.indices[static_cast<size_t>(base) + 0] = i0;
303-
out.indices[static_cast<size_t>(base) + 1] = i1;
304-
out.indices[static_cast<size_t>(base) + 2] = i2;
305-
++triangleIndex;
306-
}
262+
if (i0 >= out.numVertices || i1 >= out.numVertices || i2 >= out.numVertices)
263+
return Logger::error("PlyParser", "parseIndices", "Index out of bounds at triangle " + std::to_string(i));
264+
265+
size_t base = static_cast<size_t>(i) * 3;
266+
out.indices[base + 0] = i0;
267+
out.indices[base + 1] = i1;
268+
out.indices[base + 2] = i2;
269+
++i;
307270

308271
p = nextLine;
309272
}
310273

311-
if (triangleIndex != out.numTriangles)
312-
return Logger::error("PlyParser", "parseIndices", "Face count declared: " + std::to_string(out.numTriangles) + " but parsed: " + std::to_string(triangleIndex));
274+
if (i != out.numTriangles)
275+
return Logger::error("PlyParser", "parseIndices", "Face count declared: " + std::to_string(out.numTriangles) + " but parsed: " + std::to_string(i));
313276

314277
return true;
315278
}

src/parser/parser.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ bool Parser::loadBinaryFile(std::vector<unsigned char>& dataOut, const std::stri
5656
return Logger::error("Parser", "loadBinaryFile", "Failed to get file size");
5757
}
5858

59-
dataOut.resize(fileSize);
59+
dataOut.resize(fileSize + 1);
6060
size_t bytesRead = fread(dataOut.data(), 1, fileSize, file);
6161
fclose(file);
6262

@@ -65,6 +65,7 @@ bool Parser::loadBinaryFile(std::vector<unsigned char>& dataOut, const std::stri
6565
return Logger::error("Parser", "loadBinaryFile", "fread failed. Expected " + std::to_string(fileSize) + ", got " + std::to_string(bytesRead));
6666
}
6767

68+
dataOut[fileSize] = '\0';
6869
return true;
6970
}
7071

@@ -80,7 +81,8 @@ bool Parser::parseBool(const unsigned char*& p, bool& out) {
8081
unsigned char tok[6]{};
8182
if (!parseToken(p, tok, sizeof(tok))) return false;
8283

83-
for (unsigned char& c : tok) c = static_cast<unsigned char>(std::tolower(c));
84+
for (unsigned char& c : tok)
85+
c = static_cast<unsigned char>(std::tolower(static_cast<int>(c)));
8486

8587
const char* str = reinterpret_cast<const char*>(tok);
8688
if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0) { out = true; return true; }
@@ -254,7 +256,7 @@ bool Parser::getFileSize(FILE* file, size_t& sizeOut) const {
254256
}
255257

256258
bool Parser::isDelim(unsigned char c, bool comma) {
257-
return c == 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r' || (comma && c == ',');
259+
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || (comma && c == ',');
258260
}
259261

260262
}

0 commit comments

Comments
 (0)