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, * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software * 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, * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software * 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, * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software * 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;) for (int i = 0; i < dataSize;)
{ {
// Every 4 sixtets must generate 3 octets // 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 sixtetA = base64DecodeTable[(unsigned char)text[i]];
unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]]; 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 sixtetC = (((i + 2) < dataSize) && (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 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; 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 + 0] = (octetPack >> 16) & 0xff;
decodedData[outputCount + 1] = (octetPack >> 8) & 0xff; decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
decodedData[outputCount + 2] = octetPack & 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 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 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 // Testing code for UpdateSourceMetadata()
int exListCount = 0; rlExampleInfo test = { 0 };
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", false, &exListCount); strcpy(test.category, "core");
char *exColUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); strcpy(test.name, "core_boring_window");
char starsText[16] = { 0 }; test.stars = 4;
for (int i = 0, textOffset = 0; i < exListCount; i++) strcpy(test.verCreated, "2.9");
{ strcpy(test.verUpdated, "6.0");
rlExampleInfo *info = LoadExampleInfo(TextFormat("%s/%s/%s.c", exBasePath, exCollection[i].category, exCollection[i].name)); test.yearCreated = 2010;
test.yearReviewed = 2026;
strcpy(test.author, "John W. Smith");
strcpy(test.authorGitHub, "littlejohnny");
// Get stars as text char exSourcePath[512] = { 0 };
for (int s = 0; s < 4; s++) strcpy(exSourcePath, TextFormat("%s/core/core_basic_window.c", exBasePath)); // WARNING: Cache path for saving
{ UpdateSourceMetadata(exSourcePath, &test);
// 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);
*/ */
// Command-line usage mode // 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 else if (strcmp(exCategory, "others") == 0) nextCategoryIndex = -1; // Add to EOF
// Get required example info from example file header (if provided) // 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 // 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)); 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 // Add example to collection at the EOF
int endIndex = (int)strlen(exCollectionList); int endIndex = (int)strlen(exCollectionList);
memcpy(exCollectionListUpdated, exCollectionList, endIndex); 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)); exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed, exInfo->author, exInfo->authorGitHub));
} }
else else
@ -562,8 +552,8 @@ int main(int argc, char *argv[])
// Add example to collection, at the end of the category list // Add example to collection, at the end of the category list
int categoryIndex = TextFindIndex(exCollectionList, exCategories[nextCategoryIndex]); int categoryIndex = TextFindIndex(exCollectionList, exCategories[nextCategoryIndex]);
memcpy(exCollectionListUpdated, exCollectionList, categoryIndex); memcpy(exCollectionListUpdated, exCollectionList, categoryIndex);
int textWritenSize = sprintf(exCollectionListUpdated + categoryIndex, TextFormat("%s;%s;%s;%s;%s;\"%s\";@%s\n", 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->author, exInfo->authorGitHub)); 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); 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, "| example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |\n");
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, "|-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|\n"); mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, "|-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|\n");
char starsTexts[16] = { 0 }; char starsText[16] = { 0 };
for (int x = 0; x < exCollectionCount; x++) for (int x = 0; x < exCollectionCount; x++)
{ {
for (int s = 0; s < 4; s++) for (int s = 0; s < 4; s++)
@ -1657,7 +1647,7 @@ static int UpdateRequiredFiles(void)
else else
{ {
jsIndex += sprintf(jsTextUpdated + jsListStartIndex + jsIndex, 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]); strcpy(entry->verUpdated, tokens[4]);
// Get year created and year reviewed // Get year created and year reviewed
strcpy(entry->yearCreated, tokens[5]); entry->yearCreated = TextToInteger(tokens[5]);
strcpy(entry->yearReviewed, tokens[6]); entry->yearReviewed = TextToInteger(tokens[6]);
// Get author and github // Get author and github
if (tokens[6][0] == '"') tokens[6] += 1; 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 *exTextUpdated[6] = { 0 }; // Pointers to multiple updated text versions
char exNameFormated[256] = { 0 }; // Example name without category and using spaces 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) // Update example header title (line #3 - ALWAYS)
// String: "* raylib [shaders] example - texture drawing" // String: "* raylib [shaders] example - texture drawing"
exTextUpdated[0] = TextReplaceBetween(exSrcPath, exTextUpdated[0] = TextReplaceBetween(exText,
TextFormat("%s] example - %s", info->category, exNameFormated), "* raylib [", "\n"); TextFormat("%s] example - %s", info->category, exNameFormated), "* raylib [", "\n");
// Update example complexity rating // Update example complexity rating
@ -2309,22 +2303,32 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf
exTextUpdated[2] = TextReplaceBetween(exTextUpdated[1], exTextUpdated[2] = TextReplaceBetween(exTextUpdated[1],
TextFormat("%s, last time updated with raylib %s", info->verCreated, info->verUpdated), "* Example originally created with raylib ", "\n"); 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 // Update copyright message
// String: "* Copyright (c) 2019-2025 Contributor Name (@github_user) and Ramon Santamaria (@raysan5)" // String: "* Copyright (c) 2019-2025 Contributor Name (@github_user) and Ramon Santamaria (@raysan5)"
exTextUpdated[4] = TextReplaceBetween(exTextUpdated[3], if (info->yearCreated == info->yearReviewed)
TextFormat("%i-%i %s (@%s", info->yearCreated, info->yearReviewed, info->author, info->authorGitHub), "Copyright (c) ", ")"); {
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 // Update window title
// String: "InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture drawing");" // 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, \"", "\");"); 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; } 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) 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 textLen = strlen(text);
int replaceLen = strlen(replace); 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)); result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char));
int beginLen = strlen(begin); strncpy(result, text, beginIndex + beginLen); // Copy first text part
strncpy(result, text, textLen - beginIndex + strlen(begin)); // Copy first text part strncpy(result + beginIndex + beginLen, replace, replaceLen); // Copy replace
strncpy(result + textLen - beginIndex + beginLen, replace, replaceLen); // Copy replace strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part
strncpy(result + textLen - beginIndex + beginLen + replaceLen, text + beginIndex + toreplaceLen, textLen - endIndex); // Copy end text part
} }
} }