From cfefaf581a64974b501b1a364fba57ebd74a311e Mon Sep 17 00:00:00 2001 From: Robert MacGregor Date: Sat, 12 Mar 2016 15:41:56 -0500 Subject: [PATCH 1/2] Fix for Ecc failing on empty files --- Sources/Ecc/Main.cpp | 128 ++++++++++++++++++++++++++++++++++++++++--- Sources/Ecc/StdH.h | 4 +- 2 files changed, 121 insertions(+), 11 deletions(-) diff --git a/Sources/Ecc/Main.cpp b/Sources/Ecc/Main.cpp index 3cc2987..7c8f12a 100644 --- a/Sources/Ecc/Main.cpp +++ b/Sources/Ecc/Main.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2002-2012 Croteam Ltd. +/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation @@ -63,7 +63,7 @@ char *LineDirective(int i) return strdup(str); } -SType SType::operator+(const SType &other) +SType SType::operator+(const SType &other) { SType sum; sum.strString = stradd(strString, other.strString); @@ -116,7 +116,7 @@ FILE *FOpen(const char *strFileName, char *strMode) /* * Print a header to an output file. */ -static void PrintHeader(FILE *f) +static void PrintHeader(FILE *f) { fprintf(f, "/*\n"); fprintf(f, " * This file is generated by Entity Class Compiler, (c) CroTeam 1997-98\n"); @@ -174,13 +174,13 @@ void ReplaceFileRL(const char *strOld, const char *strNew) { continue; } - + // process each charachter for(int ich=0;ich0) && (*(pchNew-1)=='\\')) { } else bQuotes = !bQuotes; } @@ -227,8 +227,106 @@ void ReplaceFile(const char *strOld, const char *strNew) remove(strOld); rename(strNew, strOld); } + +enum ESStatus +{ + /* Appears to be non-empty, ready to parse. */ + Good, + /* Appears to be empty, ignore it. */ + Empty, + /* Error occured during status check. */ + Error, +}; + +/* Determine whether or not our target ES file is indeed valid input. */ +ESStatus GetESStatus(char *filename) +{ + ESStatus result = ESStatus::Good; + + // Read a temporary buffer of the entire file contents + fseek(_fInput, 0, SEEK_END); + size_t length = ftell(_fInput); + char* temporaryBuffer = (char*)malloc(length); + fseek(_fInput, 0, SEEK_SET); + fread(temporaryBuffer, length, 1, _fInput); + fclose(_fInput); + + // First, let's remove line comments + char *commentBegin = NULL; + while (commentBegin = strstr(temporaryBuffer, "//")) + { + size_t commentLength = length; + + char* lineEnding = strstr(commentBegin, "\n"); + if (lineEnding) + commentLength = (size_t)(lineEnding) - (size_t)commentBegin; + + memset(commentBegin, 0x20, commentLength); + } + + // Then block comments + commentBegin = NULL; + while (commentBegin = strstr(temporaryBuffer, "/*")) + { + size_t commentLength = length; + + char* commentEnd = strstr(commentBegin, "*/"); + if (commentEnd) + commentLength = (size_t)(commentEnd + 3) - (size_t)commentBegin; + else + { + result = ESStatus::Error; + break; + } + + memset(commentBegin, 0x20, commentLength); + } + + // If we return here, it was because of unbalanced block comments + if (result != ESStatus::Good) + { + free(temporaryBuffer); + return result; + } + + // Now we just loop through the buffer until we find something that's not 0x20 or \n + result = ESStatus::Empty; + for (size_t iteration = 0; iteration < length; iteration++) + if (temporaryBuffer[iteration] != 0x20 && temporaryBuffer[iteration] != '\n') + { + size_t checkLength = length; + char* checkStart = &temporaryBuffer[iteration]; + + char* lineEnding = strstr(checkStart, "\n"); + if (lineEnding) + checkLength = (size_t)(lineEnding) - (size_t)checkStart; + + // Loop through and use isdigit to check all the digits + checkStart[checkLength + 1] = 0x00; + + for (int digit = 0; digit < strlen(checkStart); digit++) + if (checkStart[digit] != 0x20 && checkStart[digit] != '\n' && isdigit(checkStart[digit])) + result = ESStatus::Good; + else if (checkStart[digit] != 0x20 && checkStart[digit] != '\n') + { + // If this occurs, then the first non-whitespace line we read wasn't a number. + result = ESStatus::Error; + break; + } + + break; + } + + + free(temporaryBuffer); + if (result == ESStatus::Good) + _fInput = FOpen(filename, "r"); + + return result; +} + /* Replace a file with a new file if they are different. - * Used to keep .h files from constantly changing when you change the implementation. + * Used to keep .h files from constantly changing when you change the implementation. */ void ReplaceIfChanged(const char *strOld, const char *strNew) { @@ -240,7 +338,7 @@ void ReplaceIfChanged(const char *strOld, const char *strNew) while (!feof(fOld)) { char strOldLine[4096] = "#l"; char strNewLine[4096] = "#l"; - + // skip #line directives while(strNewLine[0]=='#' && strNewLine[1]=='l' && !feof(fNew)) { fgets(strNewLine, sizeof(strNewLine)-1, fNew); @@ -283,6 +381,18 @@ int main(int argc, char *argv[]) } // open the input file _fInput = FOpen(argv[1], "r"); + + // Make sure we're loading a valid ES file + ESStatus status = GetESStatus(argv[1]); + + switch (status) + { + case ESStatus::Empty: + return EXIT_SUCCESS; + case ESStatus::Error: + return EXIT_FAILURE; + } + //printf("%s\n", argv[1]); // open all the output files char *strImplementation = ChangeFileNameExtension(argv[1], ".cpp_tmp"); @@ -333,7 +443,7 @@ int main(int argc, char *argv[]) ReplaceFile(strImplementationOld, strImplementation); ReplaceIfChanged(strDeclarationOld, strDeclaration); ReplaceIfChanged(strTablesOld, strTables); - + return EXIT_SUCCESS; // if there were errors } else { diff --git a/Sources/Ecc/StdH.h b/Sources/Ecc/StdH.h index 6def450..3482ed6 100644 --- a/Sources/Ecc/StdH.h +++ b/Sources/Ecc/StdH.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002-2012 Croteam Ltd. +/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation @@ -13,6 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include #include @@ -27,4 +28,3 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #define _fullpath(x, y, z) realpath(y, x) #endif - From 9f50d3ef84bb34ae70864927f73ef0b3fb0083c6 Mon Sep 17 00:00:00 2001 From: Robert MacGregor Date: Sat, 12 Mar 2016 16:45:43 -0500 Subject: [PATCH 2/2] Performance fix Ecc --- Sources/Ecc/Main.cpp | 121 ++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 58 deletions(-) diff --git a/Sources/Ecc/Main.cpp b/Sources/Ecc/Main.cpp index 7c8f12a..a175910 100644 --- a/Sources/Ecc/Main.cpp +++ b/Sources/Ecc/Main.cpp @@ -241,7 +241,7 @@ enum ESStatus /* Determine whether or not our target ES file is indeed valid input. */ ESStatus GetESStatus(char *filename) { - ESStatus result = ESStatus::Good; + ESStatus result = ESStatus::Empty; // Read a temporary buffer of the entire file contents fseek(_fInput, 0, SEEK_END); @@ -251,72 +251,77 @@ ESStatus GetESStatus(char *filename) fread(temporaryBuffer, length, 1, _fInput); fclose(_fInput); - // First, let's remove line comments - char *commentBegin = NULL; - while (commentBegin = strstr(temporaryBuffer, "//")) + // Loop through each line + char* currentSequence = strtok(temporaryBuffer, "\n"); + + // No newlines, but it might still be valid. + if (!currentSequence) + currentSequence = temporaryBuffer; + + bool inBlockComment = false; + do { - size_t commentLength = length; + size_t sequenceLength = strlen(currentSequence); - char* lineEnding = strstr(commentBegin, "\n"); - if (lineEnding) - commentLength = (size_t)(lineEnding) - (size_t)commentBegin; - - memset(commentBegin, 0x20, commentLength); - } - - // Then block comments - commentBegin = NULL; - while (commentBegin = strstr(temporaryBuffer, "/*")) - { - size_t commentLength = length; - - char* commentEnd = strstr(commentBegin, "*/"); - if (commentEnd) - commentLength = (size_t)(commentEnd + 3) - (size_t)commentBegin; - else + for (size_t iteration = 0; iteration < sequenceLength; iteration++) { - result = ESStatus::Error; - break; - } - - memset(commentBegin, 0x20, commentLength); - } - - // If we return here, it was because of unbalanced block comments - if (result != ESStatus::Good) - { - free(temporaryBuffer); - return result; - } - - // Now we just loop through the buffer until we find something that's not 0x20 or \n - result = ESStatus::Empty; - for (size_t iteration = 0; iteration < length; iteration++) - if (temporaryBuffer[iteration] != 0x20 && temporaryBuffer[iteration] != '\n') - { - size_t checkLength = length; - char* checkStart = &temporaryBuffer[iteration]; - - char* lineEnding = strstr(checkStart, "\n"); - if (lineEnding) - checkLength = (size_t)(lineEnding) - (size_t)checkStart; - - // Loop through and use isdigit to check all the digits - checkStart[checkLength + 1] = 0x00; - - for (int digit = 0; digit < strlen(checkStart); digit++) - if (checkStart[digit] != 0x20 && checkStart[digit] != '\n' && isdigit(checkStart[digit])) - result = ESStatus::Good; - else if (checkStart[digit] != 0x20 && checkStart[digit] != '\n') + // If we're still in a block comment, find the closing */ + if (inBlockComment) + { + char* blockClosing = strstr(currentSequence, "*/"); + if (!blockClosing) + break; + else + { + inBlockComment = false; + iteration = ((size_t)blockClosing - (size_t)currentSequence) + 2; + } + } + + // If we find a // sequence, simply skip this line + if (currentSequence[iteration] == '/' && currentSequence[iteration + 1] == '/') + break; + + // If we find a /* on this line but not a closing */, skip this line + if (currentSequence[iteration] == '/' && currentSequence[iteration + 1] == '*') + { + // Is there a closing */ on this line? + char* blockClosing = strstr(currentSequence, "*/"); + + if (!blockClosing) + { + inBlockComment = true; + break; + } + else + { + iteration = ((size_t)blockClosing - (size_t)currentSequence) + 2; + inBlockComment = false; + continue; + } + } + + if (iteration >= sequenceLength) + break; + + // If we got to this point, we should be able to read only a number on this line + for (size_t checkIteration = 0; checkIteration < sequenceLength; checkIteration++) + if (currentSequence[checkIteration] != '\n' && currentSequence[checkIteration] != 0x20 && !isdigit(currentSequence[checkIteration])) { - // If this occurs, then the first non-whitespace line we read wasn't a number. result = ESStatus::Error; break; } + else if (currentSequence[checkIteration] != '\n' && currentSequence[checkIteration] != 0x20) + result = ESStatus::Good; - break; + free(temporaryBuffer); + if (result == ESStatus::Good) + _fInput = FOpen(filename, "r"); + + return result; } - + } + while(currentSequence = strtok(NULL, "\n")); free(temporaryBuffer); if (result == ESStatus::Good)