[mirc scripting] les variables binaires (&binvar)

= = Tutorial sur les &binvar sous mIRC 6.12 ==

(Attention ce topic est uniquement pour les bons scripteurs) Vous les avez sûrement déjà croisés au détour d'un recoin de l'aide de mirc, mais comme ce n'était pas ca que vous cherchiez, vous avez tout simplement ignoré l'information. Et vous aviez sûrement eut raison ! Car en faite les variables binaires (pour &binvar) sont destinées à un usage très particulier.

I - La problématique

Ciblons le problème en utilisant la commande :

//set %temp a $+ $chr(13) $+ b $+ $chr(0) $+ c | echo -a " $+ %temp $+ " (len= $+ $len(%temp) $+ )

== =
Ce qui nous donne a l'écran :
===

"abc" (len=4)

== =
Bon, je suppose que vous connaissez tous l'effet de "$+" et des fonctions "$chr()" et "$len()" donc vous devriez savoir que %temp devait avoir pour longueur 5 et pas 4. En faite c le $chr(0) qui n'a pas eu d'effet, vous pouvez le vérifier facilement avec la commande : //echo -a $len($chr(0)) =
Qui renvois 0, autrement dis la fonction $chr(0) a renvoyé le caractère de fin de chaîne en première position (il s'agit de l'ascii 0 justement, c'est comme en C/C++, le language de réalisation de mirc). D'autres languages contournent le problème du caractère terminal en mémorisant la taille de la chaîne (C'est ce que font les &binvar !).

Mis à part le problème de l'ascii 0, le retour à la ligne ($cr ou $chr(13) que l'on fait normalement suivre d'un $lf ou $chr(10) quand on travail sous windob) dans une variable globale classique est une véritable hérésie, pour en avoir la preuve ouvrez votre fichier de variables vous verrez la ligne qui a été ajoutée : %temp a =
Autrement dis le $cr a coupé l'affichage de la variable ! Vous pouvez bien sûr compter sur le scripteur quelconque pour détruire par mégarde votre $cr et tout ce qui suit (il ne les voit pas, alors il risque pas de s'apercevoir de son erreur). Et les ascii 0 et 13 ne sont pas les seuls à poser ce genre de problèmes.
Note : Ceci ne concerne que les variables GLOBALES autrement dis si vous passez par des variables locales ca passe sans problème (excepté l'ascii 0). Mais les variables locales de ce type ne disposant d'aucunes méthode d'enregistrement adaptées, vos variables locales avec des $chr(13) seront perdues à la fin de l'execution du script !
Maintenant imaginons que vous vouliez une variable capable de gérer sans défaut les caractères spéciaux et même les fameux ascii 0, pour ca deux solutions : le bricolage -souvent foireux- ou les variables binaires. II - Mais qui comprend les &binvar ? ==

Rappelons tout d'abord que la taille maximale d'une &binvar est de 4096 octets (soit 2^12).
Récapitulatif des fonctions capables de gérer les &binvar : * $crc $md5 $encode $decode --> Calcul d'un identificateur d'intégrité et encodage/décodage d'une &binvar

  • /fwrite $fread --> Lecture/écriture d'une &binvar dans un fichier ouvert par

/fopen * /hadd $hget --> Lecture/écriture d'une &binvar dans une table de hachage.

  • /sockwrite /sockread /sockudp --> Lecture/écriture d'une &binvar dans un sockettcpip ou udp.
  • /bread /bwrite --> Lecture/écriture d'une &binvar dans un fichier binaire.
  • /bset /bunset /bcopy /breplace $bvar $bfind --> Et voici pour finir les 6 fonctions clés qui sont le sujet du chapitre suivant !

===
En excluant les variables binaires créés par le scripteur lui-même, vous remarquerez qu'il n'existe que 2 sources de variables binaires : Les fichiers binaires et les sockets.
Il faut savoir que la plupart des fichiers ne contiennent pas d'ascii 0 et peuvent donc être lus sans problèmes par les fonctions standards de mirc. Néanmoins si vous voulez mémoriser de nombreux nombres entiers ou flottants, il est plus judicieux d'employer des fichiers binaires et il est possible que vous vouliez lire un fichier de ce type. En ce qui concerne les sockets, il faut savoir que la plupart des protocoles interdisent l'ascii 0 pour simplifier la création de programes dans les languages dérivés du C/C++ (les scripts mirc en font parti vu que mirc est fait en C/C++). Mais si vous travaillez sur un protocole qui travail sur des données binaires, il vous faudra probablement accepter cette valeur, d'où la necessité de savoir travailler sur des &binvar. III - Modifier des &binvar. ==

mIRC ne nous fournis aucune manière simple de transmettre des &binvar à des dlls. Et cela pour une raison simple : avec le standard de dll recommandé par le concepteur de mIRC, celles-ci sont incapables de distinguer l'ascii 0 d'une &binvar d'une fin de chaîne. Ce qui veux dire que vous aurez beau chercher sur internet personne ne vous donnera de dll permettant de gérer plus efficacement les &binvar. Il ne nous reste plus qu'a nous cantonner aux fonctions de base :

/bset <&binvar> <N> <valeurascii> [valeurascii ... valeurascii *
== = Initialise une variable binaire à partir de la position N ===

/bset -t <&binvar> <N> <text>

== = -t permet d'enregistrer <text> directement dans la &binvar toujours à la position N.
/bunset <&binvar> [&binvar ... &binvar * = === Efface une liste de variables binaires.

/bcopy [-zc * <&binvardest> <&binvarsource> <N>

== = === Copie <N> octets depuis la variable binaire source dans la destination. Il est possible de spécifier la même &binvar les 2 fois si les intervals sont disjoints.
-z met a zéro les octets copiés de la source.
-c coupe la variable de destination à la fin de la copie (sa taille devient alors $calc( + <N>))
/breplace <&binvar>
<new_ascii> [old_ascii new_ascii... *

== = === Replace certaines valeurs d'octets par d'autres. Par exemple "/breplace &temp 0 1 1 0" permute les valeurs ascii 0 et 1 entre elles.

$bvar(&binvar, N, M) [.text, .word, .nword, .long, .nlong *

== = === Retourne M valeurs ascii à partir du Nième byte.

=== Si N <= 0, cette fonction retourne la longueur de la variable binaire (quel que soit la valeur de M). ===

=== Si M n'est pas donné, sa valeur par défaut est de 1. Si M <= 0, cette fonction retourne $null. ===
L'attribut ".text" coupe la chaîne au premier ascii 0 rencontré, ce qui permet de remettre ca dans une variable locale classique (toujours hors variables globales). Ceci implique bien sûr que vous utilisiez l'ascii 0 comme séparateur.
Les autres attributs concernent la lecture des entiers longs (sur plus d'un octet). J'en parle dans le chapitre suivant.

$bfind(&binvar, N, item) [.text *

== = === Cette fonction recherche item à partir de la position N où item est un ascii seul ou une suite de valeurs ascii séparées par des espaces. Si N n'est pas un nombre supérieur à 1, il est considéré comme égal à 1. La valeur de retour est une position (nombre) supérieure ou égale à N si la recherche aboutie ou 0 si la fonction n'a rien trouvée.
L'attribut ".text" permet de spécifier l'item sous forme d'un texte ou d'une variable normale. Il est possible (mais fortement déconseillé) de ne pas mettre cet attribut si vous êtes sûr que l'item contient au moins un caractère qui ne soit ni un chiffre ni un espace.

IV - Le problème "endian".

=== Je ne vais pas pas épiloguer sur le mot "endian", sachez juste qu'il a été inventé pour ce problème et qu'il existe d'autres mots pouvant faire réferance au même problème.

Déjà une courte introduction :

vous pourquoi en français on écrit les chiffres d'un nombre dans l'ordre décroissant des puissances ? Par exemple on écrit bien l'année "2004" alors qu'on aurait pu aussi choisir de l'écrire dans l'ordre inverse "4002" en commancant par le plus petit. Hé bien moi non plus je ne sais pas, d'ailleurs ca m'a jamais vraiment affecté jusqu'a qu'on me presente le problème "endian".

A la base un nombre sur un octet peut varier de 0 à 255, pour representer des nombres plus grand, on est obligé d'utiliser plusieurs octets. Par exemple, pour representer une année, on pourrait utiliser 2 octets : on obtiendrait ainsi un nombre variant de 0 à 65535 (soit 255 * 256^0 + 255 * 256^1 ou "255;255" en base 256). Avec cette méthode 2004 est constitué des chiffres 212 et 7 (car 2004 = 212 * 256^0 + 7 * 256^1) soit "7;212" en base 256.
Mais rien n'indique dans quel ordre l'ordinateur doit mémoriser ces puissances de 256, c'est au programmeur le choix de les mettre dans l'ordre qu'il souhaite. Ainsi l'ordre croissant des puissances est appelé "little-endian" car on commance par les petites puissances. A l'inverse l'ordre décroissant (qui est l'ordre normal de lecture des chiffres en français) est appelé "big-endian" car il commence par la grande puissance. On a donc 2 ordre possible des puissances :
0 1 = l'ordre little-endian sur 16 bits
1 0 = l'ordre big-endian sur 16 bits

Si le problème reste assez simple pour les entiers codés sur 16 bits il devient encore plus compliqué avec l'apparition des processeurs 32 bits. Il faut dire que certains petits malin se sont amusés a mélanger les 2 versions sur certains systèmes, sympa. Ces représentations hybrides sont nommés "middle-endian"
0 1 2 3 = l'ordre little-endian sur 32 bits
3 2 1 0 = l'ordre big-endian sur 32 bits
2 3 0 1 = un ordre middle-endian sur 32 bits
1 0 3 2 = un ordre middle-endian sur 32 bits

Ca peut vous paraître plus logique d'utiliser notre sens de lecture habituel mais sachez que notre pote à tous Windob est en "little-endian" alors forcément beaucoups d'autres ont suivis le mouvement (Les processeurs Intel -exemple : les pentiums- entre autres).

Et une conclusion :
Heureusement mirc est là pour vous simplifier la vie ! En utilisant $bvar, ainsi : $bvar(&binvar, N) [.word, .nword, .long, .nlong *
Vous pouvez lire un word (entier sur 2 octets, soit 16 bits) ou un long (entier sur 4 octets, soit 32 bits) à la position N (attention N est donné en octets, il faut donc l'incrementer de 2 ou 4 pour lire plusieurs entiers longs à la suite). En laissant le soins à mirc de trouver lui-même en quel "endian" est votre système d'exploitation.
Voici tout de même l'aide de mirc sur le sujet (c plus court que mon paragraphe :p) :
"Les attributs word, nword, long, et nlong retourne les bytes en ordre d'hôte ou de réseau."
Ps : En utilisant ces attributs, faîtes tout de même gaffe à ceux qui pourraient utiliser plusieurs partitions avec plusieurs OS : je vois d'ici les bugs du mec qui est en windob + linux + OS2 + je-sais-pas-koi. Réservez l'usage de ces attributs aux fichiers que vous avez vous-même créé dans votre script, ainsi vous êtes sûr de ne pas avoir de bug. V - Où utiliser les &binvar ? ==

Je vous conseille de les utiliser le moins possible. En effet, mirc possède de nombreuses fonctions pour modifier librement les variables classiques, ce qui n'est pas le cas pour les variables binaires. De plus on ne sait jamais trop ce qui est dans une variable binaire alors qu'on sait souvent tout de suite ce que contient une variable normale (il suffit de faire un /echo).

Les variables binaires devraient donc être employés en tant que variables temporaires, en attendant d'être transformées en variables classiques ; ou réciproquement, juste avant d'être redirigées sur un fichier ou un un socket. D'ailleurs les variables binaires sont toujours LOCALES ca devrait vous inciter d'autant plus à le faire.
Voilà c'est tout pour aujourd'hui, j'espère que ca pourra vous être utile, je l'ai fait surtout parsque j'en avais besoin alors d'autres en profitent tant mieux.

Adresse d'origine

Ce document intitulé « [mirc scripting] les variables binaires (&binvar) » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.