Skip to content
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 78 additions & 42 deletions src/rtext.c
Original file line number Diff line number Diff line change
Expand Up @@ -2029,7 +2029,8 @@ static Font LoadBMFont(const char *fileName)

int imWidth = 0;
int imHeight = 0;
char imFileName[129] = { 0 };
int totalPage = 1; // page variable
char imFileName[10][129] = { 0 }; // up to ten png file.

int base = 0; // Useless data
int readBytes = 0; // Data bytes read
Expand All @@ -2048,17 +2049,20 @@ static Font LoadBMFont(const char *fileName)
// Read line data
readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "lineHeight");
readVars = sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &imWidth, &imHeight);
readVars = sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i pages=%i", &fontSize, &base, &imWidth, &imHeight, &totalPage);
fileTextPtr += (readBytes + 1);

if (readVars < 4) { UnloadFileText(fileText); return font; } // Some data not available, file malformed

readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "file");
readVars = sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName);
fileTextPtr += (readBytes + 1);
for (int i = 0; i < totalPage; i++)
{
readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "file");
readVars = sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName[i]);
fileTextPtr += (readBytes + 1);

if (readVars < 1) { UnloadFileText(fileText); return font; } // No fileName read
if (readVars < 1) { UnloadFileText(fileText); return font; } // No fileName read
}

readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "count");
Expand All @@ -2068,49 +2072,79 @@ static Font LoadBMFont(const char *fileName)
if (readVars < 1) { UnloadFileText(fileText); return font; } // No glyphCount read

// Compose correct path using route of .fnt file (fileName) and imFileName
char *imPath = NULL;
char **imPath;
char *lastSlash = NULL;
imPath = malloc(sizeof(char) * 100); // imPath Initialization

lastSlash = strrchr(fileName, '/');
if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');

if (lastSlash != NULL)
for (int i = 0; i< totalPage; i++)
{
// NOTE: We need some extra space to avoid memory corruption on next allocations!
imPath = (char *)RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
memcpy(imPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
memcpy(imPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName));
lastSlash = strrchr(fileName, '/');
if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');

if (lastSlash != NULL)
{
// NOTE: We need some extra space to avoid memory corruption on next allocations!
imPath[i] = (char *)RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName[i]) + 4, 1);
memcpy(imPath[i], fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
memcpy(imPath[i] + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName[i], TextLength(imFileName[i]));
}
else imPath[i] = imFileName[i];

TRACELOGD(" > Image loading path: %s", imPath[i]);
}
else imPath = imFileName;

TRACELOGD(" > Image loading path: %s", imPath);
// Resize and ReDraw Font Image
Image fullFont = LoadImage(imPath[0]);;

Image imFont = LoadImage(imPath);
Image imFont[totalPage]; // font atlas

if (imFont.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
for (int i = 0; i < totalPage; i++)
{
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
Image imFontAlpha = {
.data = RL_CALLOC(imFont.width*imFont.height, 2),
.width = imFont.width,
.height = imFont.height,
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA
};
imFont[i] = LoadImage(imPath[i]);

for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++)
if (imFont[i].format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
{
((unsigned char *)(imFontAlpha.data))[p] = 0xff;
((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont.data)[i];
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
Image imFontAlpha = {
.data = RL_CALLOC(imFont[i].width*imFont[i].height, 2),
.width = imFont[i].width,
.height = imFont[i].height,
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA
};

for (int p = 0, pi = 0; p < (imFont[i].width*imFont[i].height*2); p += 2, pi++)
{
((unsigned char *)(imFontAlpha.data))[p] = 0xff;
((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont[i].data)[pi];
}

UnloadImage(imFont[i]);
imFont[i] = imFontAlpha;
}

UnloadImage(imFont);
imFont = imFontAlpha;
if (lastSlash != NULL) RL_FREE(imPath[i]);
}

fullFont = imFont[0];

// If multiple atlas, then merge atlas
if (totalPage > 1)
{
// Resize and ReDraw Font Image
ImageResizeCanvas(&fullFont, imWidth, imHeight * totalPage, 0, 0, BLACK);

for (int index = 1; index <= totalPage; index++)
{
Rectangle srcRec = { 0.0f, 0.0f, (float)imWidth, (float)imHeight};
Rectangle destRec = { 0.0f, (float)imHeight * (float)index, (float)imWidth, (float)imHeight};
ImageDraw(&fullFont, imFont[index], srcRec, destRec, WHITE);
}

Check failure

Code scanning / CodeQL

Overflow in uncontrolled allocation size

This allocation size is derived from [user input (string read by fread)](1) and might overflow.
}

font.texture = LoadTextureFromImage(imFont);
font.texture = LoadTextureFromImage(fullFont);


if (lastSlash != NULL) RL_FREE(imPath);

// Fill font characters info data
font.baseSize = fontSize;
Expand All @@ -2119,19 +2153,19 @@ static Font LoadBMFont(const char *fileName)
font.glyphs = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo));
font.recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle));

int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX, pageID;

for (int i = 0; i < glyphCount; i++)
{
readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
readVars = sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
readVars = sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i page=%i",
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX, &pageID);
fileTextPtr += (readBytes + 1);

if (readVars == 8) // Make sure all char data has been properly read
if (readVars == 9) // Make sure all char data has been properly read
{
// Get character rectangle in the font atlas texture
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
font.recs[i] = (Rectangle){ (float)charX, (float)charY + (float)imHeight * pageID, (float)charWidth, (float)charHeight };

// Save data properly in sprite font
font.glyphs[i].value = charId;
Expand All @@ -2140,12 +2174,12 @@ static Font LoadBMFont(const char *fileName)
font.glyphs[i].advanceX = charAdvanceX;

// Fill character image data from imFont data
font.glyphs[i].image = ImageFromImage(imFont, font.recs[i]);
font.glyphs[i].image = ImageFromImage(fullFont, font.recs[i]);
}
else TRACELOG(LOG_WARNING, "FONT: [%s] Some characters data not correctly provided", fileName);
}

UnloadImage(imFont);
UnloadImage(fullFont);
UnloadFileText(fileText);

if (font.texture.id == 0)
Expand All @@ -2156,8 +2190,10 @@ static Font LoadBMFont(const char *fileName)
}
else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully (%i glyphs)", fileName, font.glyphCount);

free(imPath);
return font;
}

#endif

#endif // SUPPORT_MODULE_RTEXT