<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://blog.mymind.fr/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>Mind... - Tag - Cpp</title>
  <link>http://blog.mymind.fr/</link>
  <atom:link href="http://blog.mymind.fr/feed/tag/Cpp/rss2" rel="self" type="application/rss+xml"/>
  <description></description>
  <language>fr</language>
  <pubDate>Thu, 01 Dec 2011 21:43:54 +0100</pubDate>
  <copyright>© 2007-2008 Florent Bruneau</copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Templates en C</title>
    <link>http://blog.mymind.fr/post/2007/08/16/Templates-en-C</link>
    <guid isPermaLink="false">urn:md5:305c30979642387ee13cea31a6b77855</guid>
    <pubDate>Thu, 16 Aug 2007 22:53:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>C</category><category>Cpp</category><category>Devel</category>    
    <description>&lt;p&gt;En C++, il existe un mécanisme extrêmement pratique pour généré du code générique&amp;nbsp;: les templates. Une fonction templatée est une fonction dont le code comporte un trou qui sera remplacé à la compilation par le nom d'un type, ou une valeur... Par exemple&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
template &amp;lt;class T&amp;gt; 
T read(const char *buffer) 
{
    T val;
    memcpy(&amp;amp;val, buffer, sizeof(T));
    return val;
} 
&lt;/pre&gt;


&lt;p&gt;Cette fonction lit un objet de type T sur un buffer. L'intérêt de cette fonction est très compréhensible&amp;nbsp;: quel que soit le type qu'on fournit à la fonction, elle va fonctionner, en adaptant la taille à lire au type. C'est donc beaucoup plus rapide que d'écrire une fonction pour chaque type... et l'utilisation est également très simple&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
read&amp;lt;int&amp;gt;(const char* buffer) // lit un entier sur le buffer
read&amp;lt;double&amp;gt;(const char* buffer) // lit un double sur le buffer
read&amp;lt;MaClass&amp;gt;(const char* buffer) // lit un objet de type &amp;quot;MaClass&amp;quot;
&lt;/pre&gt;


&lt;p&gt;Mais cette syntaxe n'est qu'un sucre syntaxique, car en fait, on peut également faire des templates en C...&lt;/p&gt;    &lt;h3&gt;Comment fonctionne les templates&amp;nbsp;?&lt;/h3&gt;


&lt;p&gt;En fait un template est, comme son nom l'indique, qu'un modèle de fonction. Lors de la compilation d'un programme qui utilise des templates, le compilateur regarde la liste des instances de cette fonction qui sont utilisées et les génère. Plus explicitement, si j'appelle read&amp;lt;double&amp;gt;(), le compilateur va générer cette fonction&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[cpp]
double read&amp;lt;double&amp;gt;(const char *buffer) 
{
    double val;
    memcpy(&amp;amp;val, buffer, sizeof(double));
    return val;
}
&lt;/pre&gt;


&lt;p&gt;Ainsi, l'appel à read&amp;lt;double&amp;gt; devient un appel de fonction classique.&lt;/p&gt;


&lt;h3&gt;Jeu de préprocesseur&lt;/h3&gt;


&lt;p&gt;Le préprocesseur en C possède des outils sympathique... Nous nous attarderons particulièrement sur le ##. Il s'agit tout simplement d'un opérateur de concaténation. Donc&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
#define Truc(Machin) Truc ## Machin

Truc(Bidule) /* génère TrucBidule */
&lt;/pre&gt;


&lt;p&gt;C'est donc très pratique. On peut facilement par exemple, imaginer une petite macro du genre&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
#define maFonction(Type) maFonction_ ## Type
&lt;/pre&gt;


&lt;p&gt;Si dans ce cas, on défini par exemple maFonction_int, maFonction_double, maFonction_MaStruct (oui, les classes n'existent pas en C), on pourra faire&lt;/p&gt;

&lt;pre&gt;
[c]
maFonction(int)(args); /* appelle maFonction_int */
maFonction(double)(args); /* appelle maFonction_double */
maFonction(MaStruct)(args); /* appelle maFonction_MaStruct */
&lt;/pre&gt;


&lt;p&gt;Maintenant, il ne reste plus qu'à générer les fonctions... sans avoir à toutes les écrire une à une. Pour ceci, nous allons encore une fois profiter de la présence du préprocesseur.&lt;/p&gt;

&lt;pre&gt;
[c]
#define maFonctionBuild(Type) \\
  Type maFonction_ ## Type(const char* buffer) { \\
    Type val; \\
    memcpy(&amp;amp;val, buffer, sizeof(Type)); \\
    return val; \\
  } 

maFonctionBuild(int) /* génère maFonction_int */
maFonctionBuild(double) /* génère maFonction_double */
maFonctionBuild(MaStruct) /* génère maFonction_MaStruct */
&lt;/pre&gt;


&lt;p&gt;Il ne reste donc qu'à appeler maFonctionBuild(Type) sur chacun des types pour lesquels nous avons besoin d'instancier la fonction, et d'appeler maFonction(Type) chaque fois qu'on veut appeler maFonction pour le type en question. D'une certaine manière on peut dès lors dire que les fonctions sont&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
Type maFonction(Type)(const char* buffer);
&lt;/pre&gt;


&lt;h3&gt;Et voilà&amp;nbsp;!&lt;/h3&gt;


&lt;p&gt;Nous avons donc une implémentation générique grâce au préprocesseur associé à un appel typé. Ce n'est évidemment qu'une astuce de préprocesseur, mais cela donne une souplesse syntaxique agréalble&amp;nbsp;: &quot;J'appelle maFonction appliquée sur les entiers avec les arguments args&quot;.&lt;/p&gt;


&lt;p&gt;Tout ceci est certes, moins souple que les templates C++&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;il n'y a pas d'auto-instanciation par le compilateur&amp;nbsp;: il faut &quot;manuellement&quot; instancier la fonction pour tous les types pour lesquels ont l'appelle&lt;/li&gt;
&lt;li&gt;il n'y a pas de &quot;type check&quot;&amp;nbsp;: les seules limites sont celle de la compilation&lt;/li&gt;
&lt;li&gt;le correction des erreurs de compilation est fastidieuse car toutes les erreurs apparaissent comme étant à la ligne d'appel à maFonctionBuild&lt;/li&gt;
&lt;li&gt;il est rapidement fastidieux de rajouter l'antislash à la fin de chaque ligne de la définition de la fonction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comme on le voit dans les choix de l'exemple, pour les entrées/sorties, ça permet d'avoir une seule fonction à écrire tout en gardant la flexibilité d'une fonction par type de données.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/08/16/Templates-en-C#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/08/16/Templates-en-C#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/34</wfw:commentRss>
      </item>
    
  <item>
    <title>A croire que certains le font exprès !</title>
    <link>http://blog.mymind.fr/post/2007/03/10/A-croire-que-certains-le-font-expres</link>
    <guid isPermaLink="false">urn:md5:d6e16a34562220853a6bcc75151964c7</guid>
    <pubDate>Sat, 10 Mar 2007 19:57:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Cpp</category><category>Devel</category><category>khtml2png</category><category>Qt</category><category>Sécurité</category>    
    <description>&lt;p&gt;Depuis trois jours, je travaille sur la mise ne place d'un outil permettant de faire des aperçus graphiques de site web (des vignettes façon &lt;a href=&quot;http://www.exalead.fr&quot;&gt;Exalead&lt;/a&gt; par exemple). C'est une fonctionnalité très à la mode... et c'est aussi un bon moyen d'avoir un aperçu d'un site. Donc dans ce cadre, j'ai commencé à travailler sur &lt;a href=&quot;http://khtml2png.sourceforge.net&quot;&gt;khtml2png&lt;/a&gt;. Malheureusement, comme il ne correspondait pas exactement à mes besoins, j'ai commencé à en modifier le code source... et j'ai eu quelques surprises&amp;nbsp;!&lt;/p&gt;    &lt;h3&gt;Strings&lt;/h3&gt;


&lt;p&gt;Ma première (mauvaise) surprise a été de constater que le code était loin d'être propre. Il s'agit d'un programme écrit avec la bibliothèque &lt;a href=&quot;http://www.trolltech.com/qt&quot;&gt;Qt&lt;/a&gt; (KHTML oblige), et pourtant la gestion des chaînes de caractère est faite pour moitié avec QString, pour moitié avec l'API C... sans vérification de la taille des buffers.&lt;/p&gt;


&lt;p&gt;Par exemple&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
[cpp]
QString filename = &amp;quot;/tmp/khtml2png.png&amp;quot;;
int g = sprintf(nrStr,&amp;quot;_x%iy%i&amp;quot;,xNr,yNr);
nrStr[g]='\\0';
filename+=QString(nrStr);
&lt;/pre&gt;


&lt;p&gt;Quitte à utiliser l'API C autant le faire proprement, en vérifiant la taille du buffer (dans le cas présent, le buffer nrStr avait une taille de 10)... mais en plus pourquoi faire ça de cette manière alors que Qt fournit l'API suffisant pour coder ces 4 lignes sans le moindre risque de buffer overflow&amp;nbsp;?&lt;/p&gt;


&lt;p&gt;//
&lt;a href=&quot;http://blog.mymind.fr/post/2007/03/10/cpp&quot; title=&quot;cpp&quot;&gt;cpp&lt;/a&gt;
QString filename = QString( &quot;/tmp/khtml2png.png_x%1y%2&quot;).arg(xNr).arg(yNr);
//&lt;/p&gt;


&lt;p&gt;Ensuite (toujours dans la gestion des chaînes de caractères), la méthode pour éviter le buffer overflow était le &quot;Je fais un gros buffer, au moins je suis sûr que ça ne débordera pas&quot;... mais le problème, c'est que ça peut déborder&amp;nbsp;!&lt;/p&gt;

&lt;pre&gt;
[cpp]
char 	[5000], //command line string

memset(cmd,0,sizeof(cmd));

//append the row images from top to bottom to one image
strcpy(cmd,&amp;quot;convert &amp;quot;);

for (int y=0; y &amp;lt; yNr; y++)
    sprintf(cmd,&amp;quot;%s /tmp/khtml2png.png_r%i&amp;quot;,cmd,y);
		
sprintf(cmd,&amp;quot;%s -append %s&amp;quot;,cmd,args-&amp;gt;arg(1));
system(cmd);
&lt;/pre&gt;


&lt;p&gt;Dans ce cas précis, &lt;code&gt;args-&amp;gt;arg(1)&lt;/code&gt; est contrôlé par l'utilisateur (c'est en fait le fichier destination de la capture demandée... le &lt;code&gt;sprintf&lt;/code&gt; est donc une &lt;strong&gt;erreur impardonnable&lt;/strong&gt;... sans compter qu'en plus cet argument qui est passé à un exécutable externe sans le moindre check sur le contenu de la chaîne. On risque non seulement le buffer overflow, mais également l'injection de code dans le &lt;code&gt;system&lt;/code&gt; (par exemple, je peux appeler mon fichier &lt;code&gt;fichier;sh&lt;/code&gt;, ça me lancera un shell avec les droits de l'utilisateur qui a lancé le programme.&lt;/p&gt;


&lt;p&gt;Une solution (non testée) pourrait être&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[cpp]
QProcess process(&amp;quot;convert&amp;quot;);
for (int y=0 ; y &amp;lt; yNr ; y++) {
    process.addArgument(QString(&amp;quot;/tmp/khtml2png.png_r%i&amp;quot;).arg(y);
}
process.addArgument(&amp;quot;-append&amp;quot;);
process.addArgument(args-&amp;gt;arg(1));
process.start();
while (process.isRunning()) {
    wait(10); // nombre choisi aléatoirement
}
&lt;/pre&gt;


&lt;p&gt;Cette solution a le mérite&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;d'être safe car elle ne permet pas d'injecter des commandes dans notre code&lt;/li&gt;
&lt;li&gt;d'être safe car elle ne permet pas de buffer overflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bien sûr ceci repose sur la confiance qu'on peut avoir en Qt...&lt;/p&gt;



&lt;h3&gt;Images&lt;/h3&gt;


&lt;p&gt;Pour générer le screenshot, khtml2png fait plusieurs captures dans une fenêtre en scrollant à l'intérieur de manière à recouvrir une zone aillant la taille demandée par l'utilisateur. C'est très bien... malheureusement, encore une fois je me demande quel est l'intérêt d'utiliser Qt dans le cas présent. La technique de khtml2png (version 2.5.0) est de faire une capture d'écran à chaque fois... puis de la stocker dans un fichier temporaire indexé avec le numéro du morceau en X et en Y.&lt;/p&gt;


&lt;p&gt;Une fois tous les morceaux obtenus, le programme utilise &lt;code&gt;convert&lt;/code&gt; de ImageMagick pour coller les morceaux de chaque ligne, puis une deuxième fois (enfin, ce n'est pas la deuxième fois, mais la deuxième boucle) pour coller les différentes lignes et convertir dans le format voulu (c'est en fait le dernier morceau de code que j'ai collé ci-dessus).&lt;/p&gt;


&lt;p&gt;Pourquoi faire si compliqué&amp;nbsp;?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On ne peut pas lancer deux fois khtml2png en même temps (le programme utilisant toujours le même nom pour les fichiers temporaires)&lt;/li&gt;
&lt;li&gt;Qt aussi est capable d'enregistrer les fichiers dans différents formats... pas besoin de ImageMagick pour ça&lt;/li&gt;
&lt;li&gt;khtml2png dépend d'un programme extérieur qu'il n'est pas certain de trouver sur les machines des utilisateurs...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ma technique est beaucoup plus simple, ne nécessite de lancer &lt;strong&gt;aucun&lt;/strong&gt; programme externe... et en plus se révèle plus légère en quantité de mémoire (parce que j'utilise des pointeurs au lieu de recopier les images dans tous les sens en en créant plusieurs instances à chaque fois)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;tout d'abord je crée une image vierge de la taille voulue par l'utilisateur&lt;/li&gt;
&lt;li&gt;je fais les captures du site et au lieu de les stockers dans un fichier, je les colle au bon endroit dans mon image&lt;/li&gt;
&lt;li&gt;j'utilise Qt pour enregistrer l'image au format désiré par l'utilisateur (en fonction de l'extension)...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ainsi, j'ai supprimé la &lt;em&gt;totalité&lt;/em&gt; du code qui utilisait des traitements de chaînes de caractères (qui n'étaient autres que les appels à &lt;code&gt;convert&lt;/code&gt;), ce qui supprime toutes les failles dont j'ai parlé ci-dessus... en gardant les mêmes fonctionnalités que la version publique du programme.&lt;/p&gt;



&lt;h3&gt;Besoins particuliers&lt;/h3&gt;


&lt;p&gt;J'ai également rencontré un besoin qui a mon avis n'était pas prévu par les développeurs du programme&amp;nbsp;: étant donné que je le fais tourner dans un environnement graphique inaccessible (en fait dans un &lt;code&gt;vncserver&lt;/code&gt;), je ne vois pas ce qu'il se passe. Or, KHTML déclenche automatiquement une boîte de dialogue modale dès qu'il rencontre un objet d'un type mime inconnu... dans mon cas il s'agissait d'un applet active-x qui traîne sur le &lt;a href=&quot;http://www.polytechnique.fr&quot;&gt;site de l'Ecole Polytechnique&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;J'ai donc cherché pendant 2 jours comment contourner le programme&amp;nbsp;: il me faut pouvoir avoir accès à la boîte de dialogue créée, et la supprimer puisque l'API de &lt;a href=&quot;http://api.kde.org/3.1-api/khtml/html/classKHTMLPart.html&quot;&gt;KHML&lt;/a&gt; ne permet pas de désactiver ces intrusions directement depuis le programme.&lt;/p&gt;


&lt;p&gt;Tout d'abord j'ai cru qu'en réimplémentant la méthode &lt;code&gt;showError&lt;/code&gt; ça marcherait... mais en fait non, elle n'est pas appelée dans le cas présent, c'est uniquement généré à l'intérieur du moteur KHTML... la classe &lt;code&gt;KHTMLPart&lt;/code&gt; n'est jamais notifiée de l'apparition de cette boîte de dialogue.&lt;/p&gt;


&lt;p&gt;J'ai donc cherché qui pouvait bien être le père de ce &lt;code&gt;QMessageBox&lt;/code&gt;... et en fait, c'est le &lt;code&gt;KHTMLPart::view()&lt;/code&gt;. N'ayant pas vraiment la possibilité de substituer à cet objet, un objet de mon choix, j'ai ajouté un &lt;code&gt;eventFilter&lt;/code&gt; qui filtre les messages reçus par la fenêtre de rendu... et lorsque apparaît un &lt;code&gt;QDialog&lt;/code&gt; (classe mère de &lt;code&gt;QMessageBox&lt;/code&gt;), je me charge directement de le rendre non modal, de le découpler du view et de le détruire)... et là, victoire !!!&lt;/p&gt;


&lt;p&gt;Je comprends parfaitement que les développeurs n'aient pas pensé que ces boîtes de dialogues puissent être gênantes car ils doivent travailler dans un environnement graphique et les voir... moi non&amp;nbsp;! Mais en fait, ce que je comprends moins bien c'est qu'ils ont clairement déjà rencontré le problème dans le cadre de la réalisation du screenshot. En effet, on y trouve le code (pour sélectionner les fenêtres-filles qui méritent d'apparaître dans le screenshot)&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[cpp]
if ( child-&amp;gt;isWidgetType() &amp;amp;&amp;amp;
    ((QWidget *)child)-&amp;gt;geometry().intersects( w-&amp;gt;rect() ) &amp;amp;&amp;amp;
    ! child-&amp;gt;inherits( &amp;quot;QDialog&amp;quot; ) ) {
&lt;/pre&gt;


&lt;p&gt;Les développeurs ont donc déjà rencontré des QDialog... pourquoi ne pas déjà les avoir désactivés&amp;nbsp;?&lt;/p&gt;



&lt;h3&gt;Conclusion&lt;/h3&gt;


&lt;p&gt;J'ai donc maintenant un khtml2png adapté à mes besoins. Je vais soumettre mon code aux développeurs du projet.&lt;/p&gt;


&lt;p&gt;À savoir qu'à l'heure actuelle (et je n'ai pas fini le nettoyage), mon code fait 80 lignes de moins que le code dont je suis parti... et ce malgré l'ajout de fonctionnalités.&lt;/p&gt;


&lt;p&gt;&lt;a href=&quot;http://blog.mymind.fr/mind/public/khtml2png/khtml2png-fru-last.tar.bz2&quot;&gt;Télécharger la dernière version&lt;/a&gt;&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/10/A-croire-que-certains-le-font-expres#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/10/A-croire-que-certains-le-font-expres#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/9</wfw:commentRss>
      </item>
    
</channel>
</rss>
