From 0e2eb6565d10ba6866d57d4594067d3ed4f5d974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Boull=C3=A9?= Date: Fri, 1 Dec 2023 17:38:44 +0100 Subject: [PATCH] Add TextLoadFile derivation rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nouvele regle de derivation TextLoadFile - input: un nom de fichier - output: une variable Text avec le contenu du fichier - comportement precis - il ne se passe rien s'il n'y a pas de nom de fichier specifie - on gere les fichiers avec URI, si les drivers sont installés - le contenu est traite comme quand il sera ecrit dans un fichier tabule en sortie - le champ est trime a droite et gauche - son contenu est limite a la taille max des Text (1000000 de caracteres) -b y compris en tenant compte des eventuels double-quotes dans le cas de text cntenant le separateur de champ - les erreurs de lectures sont traites comme des warning pour informer l'utilisateur, sans etre bloquant - impacts - KWDRKWDRTextLoadFile: nouvelle classe dans le fichier KWDRRuleLibrairy/KWDTText - Global::Set|GetErrorAsWarningMode - parametrage d'un mode de gestion des erreur comme des warning - active temporairement dans la classe KWDRKWDRTextLoadFile --- src/Learning/KWDRRuleLibrary/KWDRText.cpp | 140 ++++++++++++++++++++++ src/Learning/KWDRRuleLibrary/KWDRText.h | 25 ++++ src/Learning/MODL/MODL.cpp | 2 +- src/Norm/base/Ermgt.cpp | 23 +++- src/Norm/base/Ermgt.h | 9 ++ src/Norm/base/InputBufferedFile.cpp | 2 +- 6 files changed, 197 insertions(+), 4 deletions(-) diff --git a/src/Learning/KWDRRuleLibrary/KWDRText.cpp b/src/Learning/KWDRRuleLibrary/KWDRText.cpp index 81a159f0b..eda670941 100644 --- a/src/Learning/KWDRRuleLibrary/KWDRText.cpp +++ b/src/Learning/KWDRRuleLibrary/KWDRText.cpp @@ -6,6 +6,7 @@ void KWDRRegisterTextRules() { + KWDerivationRule::RegisterDerivationRule(new KWDRTextLoadFile); KWDerivationRule::RegisterDerivationRule(new KWDRTextLength); KWDerivationRule::RegisterDerivationRule(new KWDRTextLeft); KWDerivationRule::RegisterDerivationRule(new KWDRTextRight); @@ -31,6 +32,145 @@ void KWDRRegisterTextRules() ////////////////////////////////////////////////////////////////////////////////////// +KWDRTextLoadFile::KWDRTextLoadFile() +{ + SetName("TextLoadFile"); + SetLabel("Load the content of a file into a text value"); + SetType(KWType::Text); + SetOperandNumber(1); + GetFirstOperand()->SetType(KWType::Symbol); +} + +KWDRTextLoadFile::~KWDRTextLoadFile() {} + +KWDerivationRule* KWDRTextLoadFile::Create() const +{ + return new KWDRTextLoadFile; +} + +Symbol KWDRTextLoadFile::ComputeTextResult(const KWObject* kwoObject) const +{ + Symbol sLoadedText; + ALString sPathFileName; + InputBufferedFile inputFile; + boolean bOk; + longint lBeginPos; + const CharVector* cvFileCache; + char* sHugeBuffer; + int nTextLength; + int nDoubleQuoteNumber; + int nStart; + int nStop; + char c; + int i; + ALString sTmp; + + require(IsCompiled()); + + // Lecture du fichier si un path est specifie + sPathFileName = GetFirstOperand()->GetSymbolValue(kwoObject); + if (sPathFileName != "") + { + // On traite teporairement les error en warning, pour prevenir l'utilisateur d'un probleme + // sans que cela ne soit bloquant + Global::SetErrorAsWarningMode(true); + + // Parametrage du fichier, avec la taille maximum possible pour un champ de type Text + inputFile.SetFileName(sPathFileName); + inputFile.SetUTF8BomManagement(false); + inputFile.SetBufferSize(InputBufferedFile::nMaxFieldSize); + + // Lecture d'un fichier + bOk = inputFile.Open(); + if (bOk) + { + // Lecture + lBeginPos = 0; + bOk = inputFile.FillBytes(lBeginPos); + + // Remplissage d'un buffer de grande taille + // Permet de stocker tout le contenu du fichier en un seul blob memoire alloue efficacement + // afin de se preparer en le stocker sous forme de Symbol + if (bOk) + { + // Recherche d'un gros blob memoire en le terminaux par une fin de chaine de caracteres + nTextLength = inputFile.GetCurrentBufferSize(); + sHugeBuffer = GetHugeBuffer(nTextLength + 1); + sHugeBuffer[nTextLength] = '\0'; + + // Acces aux methodes de bas niveau du fichier pour transferer directement le contenu + // du cache du fichier vers le buffer + cvFileCache = inputFile.GetCache(); + assert(inputFile.GetBufferStartInCache() == 0); + nDoubleQuoteNumber = 0; + for (i = 0; i < nTextLength; i++) + { + c = cvFileCache->GetAt(i); + + // Comptage des double-quotes de la chaine pour ne pas depasser la taille limite des Text + if (sHugeBuffer[i] == '"') + nDoubleQuoteNumber++; + + // On remplace par des blancs les caracteres posant des problemes a l'ecriture d'un text + // sous la forme d'un champ d'une base de donnees + if (c == '\0' or c == '\n' or c == '\r') + c = ' '; + sHugeBuffer[i] = c; + } + + // On supprime les blancs en debut et fin de la chaine pour que le champ Text + // soit exactement le meme que celui qui serait relu depuis un fichier tabulaire, + // dont les champs sont "trimes" (cf. InputBufferedFile::GetNextField) + + // Supression des blancs en fin + nStart = 0; + while (nStart < nTextLength) + { + if (iswspace(sHugeBuffer[nStart])) + nStart++; + else + break; + } + nTextLength -= nStart; + + // S'il y a risque de depassement de la taille limites des Text en doublant les doubles quotes + // et en inserant la valeur entre 2 doubles-quote (cas ou la valeur contient le separateur + // de champ des fichiers tabulaires), on diminue la taille du texte en proportion + if (nTextLength + 2 + nDoubleQuoteNumber > InputBufferedFile::nMaxFieldSize) + nTextLength = InputBufferedFile::nMaxFieldSize - (2 + nDoubleQuoteNumber); + + // Supression des blancs en fin + nStop = nStart + nTextLength - 1; + while (nStop >= nStart) + { + if (iswspace(sHugeBuffer[nStop])) + nStop--; + else + break; + } + nStop++; + sHugeBuffer[nStop] = '\0'; + nTextLength = nStop - nStart; + + // Transformation du buffer en Symbol + sLoadedText = Symbol(&sHugeBuffer[nStart], nTextLength); + } + + // Fermeture du fichier + inputFile.Close(); + } + + // Si erreur, emission d'un warning permettant de localiser l'enreigistrement + if (not bOk) + AddWarning(sTmp + "Enable to load text file in record " + + LongintToReadableString(kwoObject->GetCreationIndex())); + + // Restittion du mode standard de traitement des erreurs + Global::SetErrorAsWarningMode(false); + } + return sLoadedText; +} + KWDRTextLength::KWDRTextLength() { TransformSymbolToTextRule(); diff --git a/src/Learning/KWDRRuleLibrary/KWDRText.h b/src/Learning/KWDRRuleLibrary/KWDRText.h index 2fba8f6c7..bbe1c5964 100644 --- a/src/Learning/KWDRRuleLibrary/KWDRText.h +++ b/src/Learning/KWDRRuleLibrary/KWDRText.h @@ -18,7 +18,9 @@ // Toutes les regles de KWDRString sont implementees de facon generique en sous-classes // de la classe KWDRStringRule, ce qui permet de redefinir tres simplement chaque // regle correspondante pour le type Text +// Seul la regle KWDRTextLoadFile est specifique au type Text +class KWDRTextLoadFile; class KWDRTextLength; class KWDRTextLeft; class KWDRTextRight; @@ -42,10 +44,33 @@ class KWDRTextHash; class KWDRTextEncrypt; #include "KWDRString.h" +#include "InputBufferedFile.h" +#include "HugeBuffer.h" // Enregistrement de ces regles void KWDRRegisterTextRules(); +//////////////////////////////////////////////////////////////////////////// +// Classe KWDRTextLoadFile +// Chargement d'un fichier sous forme d'une variable Text +// Le fichier peut etre local ou avoir un nom ayant une URI +// Le chargement se fait a concurrence de la taille max d'une variable de type Text +// Les caractere '\0', '\r' et '\n' sont remplace par des blancs pour ne pas poser +// de probleme quand on ecrit les base en sortie +class KWDRTextLoadFile : public KWDerivationRule +{ +public: + // Constructeur + KWDRTextLoadFile(); + ~KWDRTextLoadFile(); + + // Creation + KWDerivationRule* Create() const override; + + // Calcul de l'attribut derive + Symbol ComputeTextResult(const KWObject* kwoObject) const override; +}; + //////////////////////////////////////////////////////////////////////////// // Classe KWDRTextLength class KWDRTextLength : public KWDRLength diff --git a/src/Learning/MODL/MODL.cpp b/src/Learning/MODL/MODL.cpp index 4f9c52746..00afe053d 100644 --- a/src/Learning/MODL/MODL.cpp +++ b/src/Learning/MODL/MODL.cpp @@ -36,7 +36,7 @@ int main(int argc, char** argv) // Choix du repertoire de lancement pour le debugage sous Windows (a commenter apres fin du debug) // SetWindowsDebugDir("Standard", "IrisLight"); // SetWindowsDebugDir("Standard", "Iris2D"); - SetWindowsDebugDir("z_Work", "IrisLight"); + SetWindowsDebugDir("TextVariables", "TextLoadFile"); // Parametrage des logs memoires depuis les variables d'environnement, pris en compte dans KWLearningProject // KhiopsMemStatsLogFileName, KhiopsMemStatsLogFrequency, KhiopsMemStatsLogToCollect diff --git a/src/Norm/base/Ermgt.cpp b/src/Norm/base/Ermgt.cpp index c9c5b96a0..1330d8cca 100644 --- a/src/Norm/base/Ermgt.cpp +++ b/src/Norm/base/Ermgt.cpp @@ -30,8 +30,15 @@ void Global::AddWarning(const ALString& sCategoryValue, const ALString& sLocalis void Global::AddError(const ALString& sCategoryValue, const ALString& sLocalisationValue, const ALString& sLabelValue) { - bIsAtLeastOneError = true; - AddErrorObjectValued(Error::GravityError, sCategoryValue, sLocalisationValue, sLabelValue); + // Traitement de l'erreur comme un warning + if (GetErrorAsWarningMode()) + AddWarning(sCategoryValue, sLocalisationValue, sLabelValue); + // Traitement standard de l'erreur + else + { + bIsAtLeastOneError = true; + AddErrorObjectValued(Error::GravityError, sCategoryValue, sLocalisationValue, sLabelValue); + } } void Global::AddFatalError(const ALString& sCategoryValue, const ALString& sLocalisationValue, @@ -264,6 +271,16 @@ boolean Global::GetSilentMode() return bSilentMode; } +void Global::SetErrorAsWarningMode(boolean bValue) +{ + bErrorAsWarningMode = bValue; +} + +boolean Global::GetErrorAsWarningMode() +{ + return bErrorAsWarningMode; +} + // Les erreurs de l'allocateur sont redirigees sur la gestion centralisee des erreurs static int GlobalMemSetAllocErrorHandler() { @@ -364,6 +381,8 @@ longint Global::lErrorFlowErrorNumber = 0; boolean Global::bSilentMode = false; +boolean Global::bErrorAsWarningMode = false; + ALString Global::sErrorLogFileName; fstream Global::fstError; diff --git a/src/Norm/base/Ermgt.h b/src/Norm/base/Ermgt.h index 24eae6eaf..c2c09b965 100644 --- a/src/Norm/base/Ermgt.h +++ b/src/Norm/base/Ermgt.h @@ -121,6 +121,12 @@ class Global : public SystemObject static void SetSilentMode(boolean bValue); static boolean GetSilentMode(); + // Traitement des erreur comme des warning + // Par defaut: false + // Dans ce mode, les erreurs ne sont emises sous sorme de warning + static void SetErrorAsWarningMode(boolean bValue); + static boolean GetErrorAsWarningMode(); + // Gestion d'un fichier de log des erreurs // Par defaut: aucun // Quand on precise un fichier de log des erreurs, toute @@ -177,6 +183,9 @@ class Global : public SystemObject // Mode silencieux static boolean bSilentMode; + // Mode du traitement des erreurs comme des warning + static boolean bErrorAsWarningMode; + // Gestion du fichier d'erreur static ALString sErrorLogFileName; static fstream fstError; diff --git a/src/Norm/base/InputBufferedFile.cpp b/src/Norm/base/InputBufferedFile.cpp index 01d4b88ca..c866565f5 100644 --- a/src/Norm/base/InputBufferedFile.cpp +++ b/src/Norm/base/InputBufferedFile.cpp @@ -608,7 +608,7 @@ boolean InputBufferedFile::GetNextField(char*& sField, int& nFieldLength, int& n // Supression des blancs en fin (TrimRight) // Attention: on utilise iswspace et non isspace, systematiquement dans tous les sources // Une tentative de passage a isspace a entraine une degradation des performances de presque 25% - // dans un traitement complet impliquant des lecture de fichier + // dans un traitement complet impliquant des lectures de fichier i--; while (i >= 0) {