9 Commits

Author SHA1 Message Date
Ray
16a0b966c3 Update rexm.c 2025-09-06 00:09:22 +02:00
Ray
4af48fba74 REXM: REVIEWED: UpdateSourceMetadata() and TextReplaceBetween() 2025-09-06 00:04:07 +02:00
Ray
446f015ac5 Review formating 2025-09-05 23:10:13 +02:00
Ray
b2684a9c38 Merge branch 'master' of https://github.com/raysan5/raylib 2025-09-05 23:07:46 +02:00
Ray
86ec1c08c2 Update rexm.c 2025-09-05 23:07:29 +02:00
bd810368b0 Fixing base64 decoding error when input string is bad (#5170)
The following code would crash the previous version when calling MemFree:

	// 53 * A
        const char maliciousBase64Input[] = "AAAAAAAAAAAAAAAAAAAAAAAA"
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
        int decodedSize = 0;
        unsigned char *decodedData = DecodeDataBase64(
		maliciousBase64Input, &decodedSize);
        if (decodedData) {
		MemFree(decodedData);
        }

The reason is a lack of array bound checks in the decoding loop, which
corrupted here the heap (though this is platform dependent).

Adding the bound checks here prevents the memory corruption.

Tested with encoding random data of sizes 0-1023 and comparing it
with the decoded result.
2025-09-05 23:05:08 +02:00
Ray
eb816898e5 Revert "Added creation-review years to examples"
This reverts commit b5e25916fc.
2025-09-05 23:02:06 +02:00
Ray
84e606b8c7 Update rexm.c 2025-09-05 23:00:36 +02:00
Ray
1d4d8da3e9 Removed temp code to generate updated examples_list.txt 2025-09-05 22:59:42 +02:00
5 changed files with 73 additions and 55 deletions

View File

@ -11,7 +11,7 @@
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025-2025 Luís Almeida (@luis605)
* Copyright (c) 2025 Luís Almeida (@luis605)
*
********************************************************************************************/

View File

@ -11,7 +11,7 @@
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025-2025 Hamza RAHAL (@hmz-rhl)
* Copyright (c) 2025 Hamza RAHAL (@hmz-rhl)
*
********************************************************************************************/

View File

@ -11,7 +11,7 @@
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025-2025 JoeCheong (@Joecheong2006)
* Copyright (c) 2025 JoeCheong (@Joecheong2006)
*
********************************************************************************************/

View File

@ -2671,13 +2671,25 @@ unsigned char *DecodeDataBase64(const char *text, int *outputSize)
for (int i = 0; i < dataSize;)
{
// Every 4 sixtets must generate 3 octets
if ((i + 2) >= dataSize)
{
TRACELOG(LOG_WARNING, "BASE64: Decoding error: Input data size is not valid");
break;
}
unsigned int sixtetA = base64DecodeTable[(unsigned char)text[i]];
unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]];
unsigned int sixtetC = ((unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
unsigned int sixtetD = ((unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
unsigned int sixtetC = (((i + 2) < dataSize) && (unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
unsigned int sixtetD = (((i + 3) < dataSize) && (unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12) | (sixtetC << 6) | sixtetD;
if ((outputCount + 3) > maxOutputSize)
{
TRACELOG(LOG_WARNING, "BASE64: Decoding error: Output data size is too small");
break;
}
decodedData[outputCount + 0] = (octetPack >> 16) & 0xff;
decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
decodedData[outputCount + 2] = octetPack & 0xff;

View File

@ -216,34 +216,23 @@ int main(int argc, char *argv[])
char exRename[64] = { 0 }; // Example re-name, without extension
int opCode = OP_NONE; // Operation code: 0-None(Help), 1-Create, 2-Add, 3-Rename, 4-Remove
/*
// Code used to update examples list, to be removed
int exListCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", false, &exListCount);
char *exColUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
char starsText[16] = { 0 };
for (int i = 0, textOffset = 0; i < exListCount; i++)
{
rlExampleInfo *info = LoadExampleInfo(TextFormat("%s/%s/%s.c", exBasePath, exCollection[i].category, exCollection[i].name));
// Testing code for UpdateSourceMetadata()
rlExampleInfo test = { 0 };
strcpy(test.category, "core");
strcpy(test.name, "core_boring_window");
test.stars = 4;
strcpy(test.verCreated, "2.9");
strcpy(test.verUpdated, "6.0");
test.yearCreated = 2010;
test.yearReviewed = 2026;
strcpy(test.author, "John W. Smith");
strcpy(test.authorGitHub, "littlejohnny");
// Get stars as text
for (int s = 0; s < 4; s++)
{
// NOTE: Every UTF-8 star are 3 bytes
if (s < exCollection[i].stars) strcpy(starsText + 3*s, "★");
else strcpy(starsText + 3*s, "☆");
}
//<example_category>;<example_name>;<example_stars>;<raylib_created_version>;<raylib_last_update_version>;<year_created>;<year_reviewed>;"<example_author_name>";<author_github_user>
textOffset += sprintf(exColUpdated + textOffset, "%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n",
exCollection[i].category, exCollection[i].name, starsText, exCollection[i].verCreated, exCollection[i].verUpdated,
info->yearCreated, info->yearReviewed, exCollection[i].author, exCollection[i].authorGitHub);
UnloadExampleInfo(info);
}
UnloadExamplesData(exCollection);
SaveFileText(TextFormat("%s/examples_list_updated.txt", exBasePath), exColUpdated);
char exSourcePath[512] = { 0 };
strcpy(exSourcePath, TextFormat("%s/core/core_basic_window.c", exBasePath)); // WARNING: Cache path for saving
UpdateSourceMetadata(exSourcePath, &test);
*/
// Command-line usage mode
@ -537,6 +526,7 @@ int main(int argc, char *argv[])
else if (strcmp(exCategory, "others") == 0) nextCategoryIndex = -1; // Add to EOF
// Get required example info from example file header (if provided)
// NOTE: If no example info is provided (other than category/name), just using some default values
rlExampleInfo *exInfo = LoadExampleInfo(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
@ -554,7 +544,7 @@ int main(int argc, char *argv[])
// Add example to collection at the EOF
int endIndex = (int)strlen(exCollectionList);
memcpy(exCollectionListUpdated, exCollectionList, endIndex);
sprintf(exCollectionListUpdated + endIndex, TextFormat("%s;%s;%s;%s;%s;%s;%s;\"%s\";@%s\n",
sprintf(exCollectionListUpdated + endIndex, TextFormat("%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n",
exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed, exInfo->author, exInfo->authorGitHub));
}
else
@ -562,8 +552,8 @@ int main(int argc, char *argv[])
// Add example to collection, at the end of the category list
int categoryIndex = TextFindIndex(exCollectionList, exCategories[nextCategoryIndex]);
memcpy(exCollectionListUpdated, exCollectionList, categoryIndex);
int textWritenSize = sprintf(exCollectionListUpdated + categoryIndex, TextFormat("%s;%s;%s;%s;%s;\"%s\";@%s\n",
exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->author, exInfo->authorGitHub));
int textWritenSize = sprintf(exCollectionListUpdated + categoryIndex, TextFormat("%s;%s;%s;%s;%s;%i;%i\"%s\";@%s\n",
exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed, exInfo->author, exInfo->authorGitHub));
memcpy(exCollectionListUpdated + categoryIndex + textWritenSize, exCollectionList + categoryIndex, strlen(exCollectionList) - categoryIndex);
}
@ -1590,7 +1580,7 @@ static int UpdateRequiredFiles(void)
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, "| example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |\n");
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, "|-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|\n");
char starsTexts[16] = { 0 };
char starsText[16] = { 0 };
for (int x = 0; x < exCollectionCount; x++)
{
for (int s = 0; s < 4; s++)
@ -1657,7 +1647,7 @@ static int UpdateRequiredFiles(void)
else
{
jsIndex += sprintf(jsTextUpdated + jsListStartIndex + jsIndex,
TextFormat(" exampleEntry('%s', '%s', '%s'),\n", stars, exCollection[x].category, exCollection[x].name + strlen(exCollection[x].category) + 1));
TextFormat(" exampleEntry('%s', '%s', '%s'),\n", starsText, exCollection[x].category, exCollection[x].name + strlen(exCollection[x].category) + 1));
}
}
@ -1969,8 +1959,8 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry)
strcpy(entry->verUpdated, tokens[4]);
// Get year created and year reviewed
strcpy(entry->yearCreated, tokens[5]);
strcpy(entry->yearReviewed, tokens[6]);
entry->yearCreated = TextToInteger(tokens[5]);
entry->yearReviewed = TextToInteger(tokens[6]);
// Get author and github
if (tokens[6][0] == '"') tokens[6] += 1;
@ -2285,10 +2275,14 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf
char *exTextUpdated[6] = { 0 }; // Pointers to multiple updated text versions
char exNameFormated[256] = { 0 }; // Example name without category and using spaces
int exNameIndex = TextFindIndex(info->name, "_");
strcpy(exNameFormated, info->name + exNameIndex + 1);
int exNameLen = strlen(exNameFormated);
for (int i = 0; i < exNameLen; i++) { if (exNameFormated[i] == '_') exNameFormated[i] = ' '; }
// Update example header title (line #3 - ALWAYS)
// String: "* raylib [shaders] example - texture drawing"
exTextUpdated[0] = TextReplaceBetween(exSrcPath,
exTextUpdated[0] = TextReplaceBetween(exText,
TextFormat("%s] example - %s", info->category, exNameFormated), "* raylib [", "\n");
// Update example complexity rating
@ -2309,22 +2303,32 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf
exTextUpdated[2] = TextReplaceBetween(exTextUpdated[1],
TextFormat("%s, last time updated with raylib %s", info->verCreated, info->verUpdated), "* Example originally created with raylib ", "\n");
// Update contributors names
// String: "* Example contributed by Contributor Name (@github_user) and reviewed by Ramon Santamaria (@raysan5)"
exTextUpdated[3] = TextReplaceBetween(exTextUpdated[2],
TextFormat("%s (@%s", info->author, info->authorGitHub), "* Example contributed by ", ")");
// Update copyright message
// String: "* Copyright (c) 2019-2025 Contributor Name (@github_user) and Ramon Santamaria (@raysan5)"
exTextUpdated[4] = TextReplaceBetween(exTextUpdated[3],
TextFormat("%i-%i %s (@%s", info->yearCreated, info->yearReviewed, info->author, info->authorGitHub), "Copyright (c) ", ")");
if (info->yearCreated == info->yearReviewed)
{
exTextUpdated[3] = TextReplaceBetween(exTextUpdated[2],
TextFormat("%i %s (@%s", info->yearCreated, info->author, info->authorGitHub), "Copyright (c) ", ")");
}
else
{
exTextUpdated[3] = TextReplaceBetween(exTextUpdated[2],
TextFormat("%i-%i %s (@%s", info->yearCreated, info->yearReviewed, info->author, info->authorGitHub), "Copyright (c) ", ")");
}
// Update window title
// String: "InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture drawing");"
exTextUpdated[5] = TextReplaceBetween(exTextUpdated[4],
exTextUpdated[4] = TextReplaceBetween(exTextUpdated[3],
TextFormat("raylib [%s] example - %s", info->category, exNameFormated), "InitWindow(screenWidth, screenHeight, \"", "\");");
SaveFileText(exSrcPath, exTextUpdated[5]);
// Update contributors names
// String: "* Example contributed by Contributor Name (@github_user) and reviewed by Ramon Santamaria (@raysan5)"
// WARNING: Not all examples are contributed by someone, so the result of this replace can be NULL (string not found)
exTextUpdated[5] = TextReplaceBetween(exTextUpdated[4],
TextFormat("%s (@%s", info->author, info->authorGitHub), "* Example contributed by ", ")");
if (exTextUpdated[5] != NULL) SaveFileText(exSrcPath, exTextUpdated[5]);
else SaveFileText(exSrcPath, exTextUpdated[4]);
for (int i = 0; i < 6; i++) { MemFree(exTextUpdated[i]); exTextUpdated[i] = NULL; }
@ -2424,19 +2428,21 @@ static char *TextReplaceBetween(const char *text, const char *replace, const cha
if (beginIndex > -1)
{
int endIndex = TextFindIndex(text + beginIndex, end);
int beginLen = strlen(begin);
int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
if (beginIndex > -1)
if (endIndex > -1)
{
endIndex += (beginIndex + beginLen);
int textLen = strlen(text);
int replaceLen = strlen(replace);
int toreplaceLen = (endIndex + beginIndex) - (beginIndex + strlen(begin));
int toreplaceLen = endIndex - beginIndex - beginLen;
result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char));
int beginLen = strlen(begin);
strncpy(result, text, textLen - beginIndex + strlen(begin)); // Copy first text part
strncpy(result + textLen - beginIndex + beginLen, replace, replaceLen); // Copy replace
strncpy(result + textLen - beginIndex + beginLen + replaceLen, text + beginIndex + toreplaceLen, textLen - endIndex); // Copy end text part
strncpy(result, text, beginIndex + beginLen); // Copy first text part
strncpy(result + beginIndex + beginLen, replace, replaceLen); // Copy replace
strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part
}
}