/// <summary> /// Checks to ensure we haven't extracted too many bytes, or taken too long. This exists primarily /// to mitigate the risks of quines (archives that contain themselves) and zip bombs (specially /// constructed to expand to huge sizes). /// Ref: https://alf.nu/ZipQuine /// </summary> /// <param name="additionalBytes"> </param> internal void CheckResourceGovernor(long additionalBytes = 0) { Logger.ConditionalTrace("CheckResourceGovernor(duration={0}, bytes={1})", GovernorStopwatch.Elapsed.TotalMilliseconds, CurrentOperationProcessedBytesLeft); if (options.EnableTiming && GovernorStopwatch.Elapsed > options.Timeout) { throw new TimeoutException(string.Format($"Processing timeout exceeded: {GovernorStopwatch.Elapsed.TotalMilliseconds} ms.")); } if (CurrentOperationProcessedBytesLeft - additionalBytes < 0) { throw new OverflowException("Too many bytes extracted, exceeding limit."); } }
/// <summary> /// Applique le formatage <paramref name="cf"/> aux caractères dans le <see cref="Range"/> /// <paramref name="toR"/> en utilisant la <see cref="Config"/> <paramref name="inConf"/>. /// </summary> /// <param name="cf">Le <see cref="CharFormatting"/> à appliquer. Attention: ne devrait pas /// l'être, mais il y a eu des cas où <paramref name="cf"/> était <c>null</c>.</param> /// <param name="toR">Le <see cref="Range"/> à formater.</param> /// <param name="inConf">La <see cref="Config"/> à utiliser le cas échéant.</param> private void ApplyCFToRange(CharFormatting cf, Range toR, Config inConf) { logger.ConditionalTrace("ApplyCFToRange"); // 24.01.2021: J'ai reçu une copie d'écran d'une erreur qui provenait visiblement de // l'incapacité de Word à appliquer une couleur. J'ai donc décidé d'intercepter de // telles erreurs directement ici. // 31.01.2021: Entre temps, j'ai une explication possible et j'ai changé la façon de // mettre en couleur. Je laisse quand même les try / catch. if (cf != null) { // **************************** GRAS ******************************** try { if (cf.bold) { toR.Bold = (int)Microsoft.Office.Core.MsoTriState.msoTrue; } else if (cf.ForceNonBold(inConf)) { toR.Bold = (int)Microsoft.Office.Core.MsoTriState.msoFalse; } } catch (Exception e) { ErrorMsgACTR(cf, toR, "gras", e); } // **************************** ITALIQUE ******************************** try { if (cf.italic) { toR.Italic = (int)Microsoft.Office.Core.MsoTriState.msoTrue; } else if (cf.ForceNonItalic(inConf)) { toR.Italic = (int)Microsoft.Office.Core.MsoTriState.msoFalse; } } catch (Exception e) { ErrorMsgACTR(cf, toR, "italique", e); } // **************************** SOULIGNÉ ******************************** try { if (cf.underline) { toR.Underline = WdUnderline.wdUnderlineSingle; } else if (cf.ForceNonUnderline(inConf)) { toR.Underline = WdUnderline.wdUnderlineNone; } } catch (Exception e) { ErrorMsgACTR(cf, toR, "souligné", e); } // if (cte.cf.caps) // capitalize // TBD // **************************** COULEUR ******************************** try { if (cf.changeColor) // set new { toR.Font.Color = (WdColor)(int)cf.color; // On peut aussi coloriser en utilisant Font.Fill: // toR.Font.Fill.ForeColor.RGB = cf.color; // L'avantage c'est qu'il s'agit d'un remplissage des caractères et qu'on peut // par exemple faire des fondus. L'inconvénient c'est que ça plante avec les anciens // fichiers .doc et que c'est plus lent. // J'ai d'abord fait une distinction entre les deux modes, en interceptant // l'exception, mais ça ne vaut pas la peine tant qu'on n'offre pas plus de // possibilités de formater. } else if (cf.ForceBlackColor(inConf)) { toR.Font.Color = (WdColor)(int)ColConfWin.predefinedColors[(int)PredefCol.black]; } } catch (Exception e) { ErrorMsgACTR(cf, toR, "mise en couleur", e); } // **************************** SURLIGNAGE ******************************** try { if (cf.changeHilight) { WdColorIndex wdCi; if (mapRGBtoColI.TryGetValue(cf.hilightColor, out wdCi)) { toR.HighlightColorIndex = wdCi; } } else if (cf.ForceHilightClear(inConf)) { // il y a un bug sur les espaces, on met donc d'abord du blanc partout // avant d'effacer. toR.HighlightColorIndex = WdColorIndex.wdWhite; toR.HighlightColorIndex = WdColorIndex.wdNoHighlight; } } catch (Exception e) { ErrorMsgACTR(cf, toR, "surlignage", e); } // **************************** ARC ******************************** try { if (cf.drawArc) { // Let's get rid of any special char before and after the effective text. // We could possibly do that for each case, but arcs seems to be the only // one requesting it, in the other cases, setting a color to an undisplayed // character does not really matter. Range ran = toR.Duplicate; MatchCollection matches = TheText.rxWords.Matches(ran.Text); if (matches.Count > 0) { // beg and end are zero based in ran.Text // beg is the first character in a word, end - 1 is the last character // in a word. string texte = ran.Text; int beg = matches[0].Index; Match m = matches[matches.Count - 1]; int end = m.Index + m.Length; //char after the match so that end-beg == length // Il peut semble-t-il arriver que des caractères spéciaux se trouvent au début de Text et // qu'ils soient comptés différemment pour Start que pour Text... Probablement qqch à voir // avec UTF-8 vs. UTF-16 ou un truc du genre... // On corrige donc beg pour qu'il corresponde bien au premier caractère voulu. end doit // aussi être corrigé, le cas échéant. string wishedChar = texte.Substring(beg, 1); int i = 0; foreach (Range c in ran.Characters) { if (c.Text == wishedChar) { break; } i++; } Debug.Assert(i < ran.Characters.Count); int delta = beg - i; beg = i; end = end - delta; ran.SetRange(ran.Start + beg, ran.Start + end); int pageNr = ran.Information[WdInformation.wdActiveEndPageNumber]; logger.ConditionalTrace("Page Number {0}", pageNr); if (lastPage == 0) { lastPage = pageNr; } else if (pageNr > lastPage) { lastPage = pageNr; ran.Select(); } _ = ran.Information[WdInformation.wdHorizontalPositionRelativeToPage]; // Ne me demandez pas pourquoi il faut le faire deux fois... Mais seul le // 2e appel donne le bon résultat... PAE 06.02.2021 float x0 = ran.Information[WdInformation.wdHorizontalPositionRelativeToPage]; float y0 = ran.Information[WdInformation.wdVerticalPositionRelativeToPage]; float fontHeight = ran.Font.Size; y0 += fontHeight; y0 += inConf.arcConf.Decalage; float lineheight = ran.ParagraphFormat.LineSpacing; float h = (inConf.arcConf.Hauteur / 100.0f) * (float)Math.Sqrt(20.0f * (Math.Max(1, lineheight - fontHeight))); Range endPosition = ran.Duplicate; endPosition.Collapse(WdCollapseDirection.wdCollapseEnd); float x1 = endPosition.Information[WdInformation.wdHorizontalPositionRelativeToPage]; float w = x1 - x0; // width float[,] thePoints0 = new float[4, 2] { { x0, y0 }, { x0 + (((float)(100 - inConf.arcConf.Ecartement) / 200.0f) * w), y0 + h }, { x0 + (((float)(100 + inConf.arcConf.Ecartement) / 200.0f) * w), y0 + h }, { x1, y0 }, }; Shape s = ColorizationMSW.thisAddIn.Application.ActiveDocument.Shapes.AddCurve( thePoints0); s.Line.ForeColor.RGB = cf.arcColor; s.Line.Weight = inConf.arcConf.Epaisseur; s.Name = "arc"; if (s.Anchor.Start <= ran.End) { nrArcs++; } } } } catch (Exception e) { ErrorMsgACTR(cf, toR, "arcs", e); } // **************************** EEFACER ARCS ******************************** try { if (cf.removeArcs) { List <Shape> toRemoveShapes = new List <Shape>(toR.ShapeRange.Count); foreach (Shape s in toR.ShapeRange) { if (s.Name == "arc") { toRemoveShapes.Add(s); } } int i = 0; foreach (Shape s in toRemoveShapes) { if (i % 30 == 0) { ProgressNotifier.thePN.InProgress((int)(((float)i / (float)toRemoveShapes.Count) * 100.0f)); } i++; s.Delete(); } } } catch (Exception e) { ErrorMsgACTR(cf, toR, "effecer arcs", e); } } else { logger.Error("ApplyCFToRange with cf == null"); Debug.Assert(false); } }
/// <summary> /// Calcule les syllabes avec la <see cref="Config"/> donnée. La liste 'syls' est remplie. /// </summary> /// <param name="forceDierese">Indique s'il faut forcer la diérèse. Si <c>true</c> les /// 'i' suivis de voyelle comme dans 'hier' sont considérés comme une syllabe à part: /// 'hi-er'. Si <c>false</c> 'hier' correspond à une seule syllabe.</param> public void ComputeSyls(bool forceDierese = false) { logger.ConditionalTrace(ConfigBase.cultF, "ComputeAndColorSyls {0}", GetWord()); SylInW siw; int i, j; SylConfig sylConfig = theConf.sylConf; // Algorithme de Marie-Pierre syls = new List <SylInW>((Last - First) / 2); // créons une syllabe pour chaque phonème for (i = 0; i < phons.Count; i++) { syls.Add(new SylInW(phons[i])); } logger.ConditionalTrace("Etape 1 {0} --> {1}, {2}", GetWord(), Syllabes(), GetPhonSyllabes()); if (syls.Count > 1) { // Si le décodage est standard dupliquer les phonèmes qui comportent des consonnes doubles if (sylConfig.DoubleConsStd) { for (i = 0; i < syls.Count; i++) { if (syls[i].EstConsonneRedoublee()) { siw = new SylInW(syls[i]); syls[i].ReduitADerniereLettre(); siw.ReduitAPremiereLettre(); syls.Insert(i, siw); } } } logger.ConditionalTrace("Etape 2 {0} --> {1}, {2}", GetWord(), Syllabes(), GetPhonSyllabes()); // Il y a une série de cas spéciaux où deux sons ne forment qu'une syllabe // par exemple [bkptgdfv][lR] ou [y][i] ou [u]([i]|[e_tilda]|[o_tilda]) // (la notation est un peu libre :-) for (i = 0; i < syls.Count - 1; i++) { if (FusionnerSyllabes(syls, i, i + 1, forceDierese)) { // mixer les deux phonèmes puis raccourcir la chaîne syls[i].AbsorbeSuivant(syls[i + 1]); syls.RemoveAt(i + 1); logger.ConditionalTrace("Etape 3-{0} {1} --> {2}, {3}", i, GetWord(), Syllabes(), GetPhonSyllabes()); i--; // faire en sorte que la prochaine itération considère le nouveau // phonème fusionné et son successeur } } // construire les syllabes par association de phonèmes consonnes et voyelles // Les syllabes sont constituées de tout ce qui précède un phonème voyelle // jusqu'à la syllabe précédente ou le début du mot. // De plus si le phonème voyelle est suivi de deux consonnes, la première fait // partie de la première syllabe. i = 0; j = 0; // début de la syllabe while (i < syls.Count) { logger.ConditionalTrace("Etape fusion consonnes et voyelles i:{0}, j:{1} {2} --> {3}, {4}" , i, j, GetWord(), Syllabes(), GetPhonSyllabes()); if (syls[i].EstVoyelle(forceDierese)) { // fusionner les syllabes de j à i for (int k = 0; k < (i - j); k++) { syls[j].AbsorbeSuivant(syls[j + 1]); syls.RemoveAt(j + 1); } i = j; j++; logger.ConditionalTrace("Etape 4A i:{0}, j:{1} {2} --> {3}, {4}", i, j, GetWord(), Syllabes(), GetPhonSyllabes()); // si les deux lettres qui suivent sont des consonnes, la première fait partie de la syllabe que nous venons de créer // A condition qu'elles ne soient pas toutes les deux dans la même syllabe. if (j < syls.Count) { int pos = syls[j].First; // position de la lettre suivante dans le texte sous-jacent if (syls[j].Last == syls[j].First && pos < this.Last && EstConsonne(GetChar(pos)) && EstConsonne(GetChar(pos + 1))) { syls[j - 1].EtendDroite(1); if (!syls[j].ReduitGauche(1)) { syls.RemoveAt(j); } } } logger.ConditionalTrace("Etape 4B i:{0}, j:{1} {2} --> {3}, {4}", i, j, GetWord(), Syllabes(), GetPhonSyllabes()); } i++; } // while logger.ConditionalTrace("Etape 5 i:{0}, j:{1} {2} --> {3}, {4}", i, j, GetWord(), Syllabes(), GetPhonSyllabes()); // précaution de base : si pas de syllabes reconnues, on concatène simplement les phonèmes if (j == 0) { // le mot ne comprend pas de voyelles --> une seule syllabe syls.Clear(); siw = new SylInW(this, this.First, this.Last, Phonemes.firstPhon); syls.Add(siw); logger.ConditionalTrace("Etape 6A i:{0}, j:{1} {2} --> {3}, {4}", i, j, GetWord(), Syllabes(), GetPhonSyllabes()); } else { // il ne doit rester à la fin que les lettres muettes ou des consonnes qu'on ajoute à la dernière syllabe while (j < syls.Count) { syls[j - 1].AbsorbeSuivant(syls[j]); syls.RemoveAt(j); j++; } logger.ConditionalTrace("Etape 6B i:{0}, j:{1} {2} --> {3}, {4}", i, j, GetWord(), Syllabes(), GetPhonSyllabes()); } // ############################################################################### // # Traitement spécial de de la dernière syllabe dans les modes oral et poésie. # // ############################################################################### if ((syls.Count > 1) && (syls[syls.Count - 1].P == Phonemes.q_caduc)) { // s'il y a plus d'une syllabe, il y a aussi plus d'un phonème if (sylConfig.mode == SylConfig.Mode.oral) { // si nous sommes en mode oral, les e caducs des dernières syllabes // doivent être concaténés avec la syllabe précédente syls[syls.Count - 2].AbsorbeSuivant(syls[syls.Count - 1]); syls.RemoveAt(syls.Count - 1); logger.ConditionalTrace("Etape 7A {0} --> {1}, {2}", GetWord(), Syllabes(), GetPhonSyllabes()); } else if (sylConfig.mode == SylConfig.Mode.poesie) { logger.ConditionalTrace("Mode poésie. Syllabes avant le traitement: {0}", Syllabes()); // voir http://mamiehiou.over-blog.com/article-versification-comment-compter-les-pieds-syllabes-d-un-vers-97149081.html // dont nous nous inspirons ici. Il faut toutefois noter que quand le // "e" ne compte pas pour un pied, nous le relions simplement avec la // syllabe précédente, ce qui n'est pas tout à fait correct au niveau // de la prononciation. // En gros on peut dire que si le mot suivant commence par une voyelle // (ou équivalent), le e-caduc ne se prononce pas, sauf s'il y a une laison. // Si le mot suivant commence par une consonne (ou équivalent) le e-caduc // se prononce. string txt = T.ToLowerString(); string wrd = ToLowerString(); ComportementMotSuivant cms = ComportementMotSuivant.undef; int startNextWord = Last + 1; // cherchons le début du prochain mot (ou la fin de ligne...) while (startNextWord < txt.Length && (txt[startNextWord] == ' ' || txt[startNextWord] == '\t' || txt[startNextWord] == ',' || // la virgule n'empêche pas l'influence du mot suivant. txt[startNextWord] == '!' || // ça pourrait dépendre des situations... txt[startNextWord] == '?' || // ça pourrait dépendre des situations... txt[startNextWord] == '.' || // ça pourrait dépendre des situations... txt[startNextWord] == '"' || txt[startNextWord] == '«' || txt[startNextWord] == '»' || txt[startNextWord] == '“' || txt[startNextWord] == '”' || txt[startNextWord] == '‘' || txt[startNextWord] == '’' || txt[startNextWord] == '-' || txt[startNextWord] == '—' || txt[startNextWord] == ';' || txt[startNextWord] == ':' // ça pourrait dépendre des situations... )) { startNextWord++; } // cherchons la fin du mot suivant int endNextWord = startNextWord; while (endNextWord < txt.Length && (EstConsonne(txt[endNextWord]) || EstVoyelle(txt[endNextWord]))) { endNextWord++; } // startNextWord est l'index du début du mot suivant. S'il y a des // lettres, endNextWord est celui de la lettre qui suit le mot. // S'il n'y a pas de lettres, endNextWord == startNextWord string nextWord = null; if (endNextWord > startNextWord) { nextWord = txt.Substring(startNextWord, endNextWord - startNextWord); logger.ConditionalTrace("nextWord: {0}", nextWord); } if (startNextWord < txt.Length) { // il peut y avoir un mot suivant. if (Disjonction(nextWord)) { cms = ComportementMotSuivant.consonne; } else if (Liaison(nextWord)) { cms = ComportementMotSuivant.voyelle; } else if (txt[startNextWord] == 'y') { // Le cas normal est que le y se comporte comme une consonne // et le e-caduc forme une syllabe). Les exceptions sont // interceptées par "Liaison" cms = ComportementMotSuivant.consonne; } else if (TextEl.EstVoyelle(txt[startNextWord])) { cms = ComportementMotSuivant.voyelle; } else if (txt[startNextWord] == 'h') { // Le 'h' mérite un dictionnaire à lui tout seul if (HAspire(nextWord)) { cms = ComportementMotSuivant.consonne; } else { // h muet cms = ComportementMotSuivant.voyelle; } } else if (TextEl.EstConsonne(txt[startNextWord])) { cms = ComportementMotSuivant.consonne; } else { // Il ne s'agit pas d'un lettre. Donc soit de la ponctuation, // une fin de ligne ou autre chose... On traite ce cas comme // une fin de vers. cms = ComportementMotSuivant.fin; } } else { // C'est la fin du texte. cms = ComportementMotSuivant.fin; } logger.ConditionalTrace("cms: {0}", cms.ToString()); switch (cms) { case ComportementMotSuivant.consonne: // la syllabe est prononcée, on la laisse. break; case ComportementMotSuivant.voyelle: if (wrd[wrd.Length - 1] == 's' || wrd[wrd.Length - 1] == 't') { // il y a une liaison, la syllabe se prononce. // L'existence d'un eliaison est probablement plus compliquée // à identifier (il y certainement une foule d'exceptions) // :-) Commençons quand même comme ça... } else { // la syllabe ne se prononce pas. syls[syls.Count - 2].AbsorbeSuivant(syls[syls.Count - 1]); syls.RemoveAt(syls.Count - 1); } break; case ComportementMotSuivant.fin: // la syllabe ne se prononce pas. syls[syls.Count - 2].AbsorbeSuivant(syls[syls.Count - 1]); syls.RemoveAt(syls.Count - 1); break; default: logger.Error("ComportementMotSuivant {0} non traité", cms); break; } logger.ConditionalTrace("Etape 7A {0} --> {1}, {2}", GetWord(), Syllabes(), GetPhonSyllabes()); } } } // if (syls.Count > 1) logger.ConditionalTrace("Résultat {0} --> {1}, {2}", GetWord(), Syllabes(), GetPhonSyllabes()); }