 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Michael Guest
|
Posted: Wed Feb 22, 2006 11:06 pm Post subject: Récupération des infos dans un fichier binaire C3D |
|
|
Bonsoir à tous,
pour un programme que je suis en train de développer, je dois extraire
des informations d'un fichier C3D écrit en binaire, et qui contient des
renseignements sur le résultat d'une capture de mouvement.
Le souci, c'est que je n'ai jamais eu à faire ce genre de lecture, et que
je sais pas comment m'y prendre.
Pour commencer, je voudrais juste pouvoir extraire les infos de l'entête
du fichier.
Dans la doc (http://www.c3d.org/HTML/default.htm), il y est dit que ce
fichier est composé de multiples blocs de 512 bytes.
//
All C3D files contain a minimum of three sections of information:
-----------------------------------------------------------------
A single, 512 byte, header section
-----------------------------------------------------------------
A parameter section consisting of one, or more, 512-byte blocks.
-----------------------------------------------------------------
3D point/analog data section consisting of one, or more, 512-byte blocks.
//
Cette page me donne les différentes composantes de cet entête:
http://www.c3d.org/HTML/description.htm
On m'a filé un code en C qui lit cet entête, mais j'y pipe rien du tout,
je vous la donne...
#define RECORD 512
typedef struct S_C3D {
int nbr_block_parameter;
int processor;
char **nom_block_parameter;
} C3D;
C3D c3d;
typedef struct matrice {
double **Mat;
} MATRICE;
typedef struct {
short cleffich; // w0 Clef du fichier
short nbmarqs; // w1 Nombre de marqueurs
short nbanalog; // w2 Nombre de donnees analogiques par image
video
short premimage; // w3 Premiere image
short dernimage; // w4 Derniere image
short maxinterpol; // w5 Interpolation maximum (nombre d'images)
float echelle; // w6-7 Facteur de conversion des donnees video
stockees sous forme d'entiers
short debutdonnees; // w8 Enregistrement de debut des donnees 1
enregistrement = 256 * word; 1 word = 16 bits
short freqanal; // w9 frequence d'echantillonage
analogique/donnees video
float freqvid; // w10-11 frequence d'echantillonage video
short x1[137]; // w12-w148 inutilise
short clef; // w149 mot clef (12345 octal typical value)
short nbevnttps; // w150 nb d'evenements temps definis
short x2; // w151 Number of defined time events
float fmtevnttps[18]; // w152-w187 dates evenements temporels (max
9-,pas 18!)
short fmtevntswitch[10];// w188-w197 byte switch de l evenement (0=on,1
=off)
char labelevnt[9][8]; // w198-w233 label de l evenement sur 4
caracteres
short x3[22]; // w234-w255 inutilise
}ENTETEC3D;
typedef union {
long lg;
float flt;
int in[2];
char ch[4];
}trans;
int LgLabel,NbTraj;
char *dim_label;
char **p_label; // Labels des points
trans tr;
short Nbimage;
char TempChar;
// Implémentation
float fltdecpc (char byt[4]) // fonction donnee par Oxford pour
transformer DEC en FLOAT .Recopiee integralement donc no comment !
{
long mantis;
short exp;
float flt;
float *f;
switch (proc) {
case 0:
f = (float *) byt;
flt = *f;
break;
case 1:
mantis = (byt[2] & 0xff) + ((byt[3] & 0xffl) << + (((byt[0] &
0x7fl) | 0x80) << 16);
exp = (byt[1] & 0x7f) * 2 + ((byt[0] & 0x80) ? 1 : 0);
if (byt[1] & 0x80) mantis = -mantis;
flt = (mantis || exp) ? ((float) ldexp (mantis, (exp - 128 - 24)))
: 0;
break;
}
return (flt);
}
void litentete (char *nomfich)
{
char H[sizeof(ENTETEC3D)];
ENTETEC3D *header;
FILE *fich;
int i;
int n, G, m, n2, G2, d;
char *GroupName=NULL;
char *GroupDescription=NULL;
char *ParamName=NULL;
int *Dimensions=NULL;
short offset2, offset1;
if ((fich = OuvreFichier (nomfich, "rb", 0))!=NULL) {
header = (ENTETEC3D *)H;
for (i=0; i<sizeof(ENTETEC3D); i++) H[i] = fgetc(fich);
tr.flt = header->echelle;
header->echelle = fltdecpc(tr.ch);
tr.flt = header->freqvid;
header->freqvid = fltdecpc(tr.ch);
Nbimage = header->dernimage - header->premimage + 1;
// Lecture des paramètres pour récuperer les noms des marqueurs
correspondants à chaque trajectoire*/
fread (&TempChar, sizeof(char), 1, fich); // Byte 1
fread (&TempChar, sizeof(char), 1, fich); // Byte 1
fread (&TempChar, sizeof(char), 1, fich); // Byte 1
fread (&TempChar, sizeof(char), 1, fich); // Byte 1
// header
// n
fread (&TempChar, sizeof(char), 1, fich);
n = (int)TempChar;
while (n!=0) {
// G
fread (&TempChar, sizeof(char), 1, fich);
G = (int)TempChar;
// Group Name
GroupName = calloc (n+1, sizeof(*GroupName));
for (i=0;i<n;i++)
fread ((GroupName+i), sizeof(char), 1, fich);
// offset
fread (&offset1, sizeof(short), 1, fich);
// m
fread (&TempChar, sizeof(char), 1, fich);
m = (int)TempChar;
if (m==0) fseek(fich,(offset1-3),SEEK_CUR);
else {
GroupDescription = calloc (m, sizeof(*GroupDescription)); //
Group Description
for (i=0;i<(m);i++)
fread ((GroupDescription+i), sizeof(char), 1, fich);
free (GroupDescription);
}
// Paramètres
// n2
fread (&TempChar, sizeof(char), 1, fich);
n2 = (int) TempChar;
// G2
fread (&TempChar, sizeof(char), 1, fich);
G2 = (int) TempChar;
while (G2 == -G) {
// Param Name
ParamName = calloc (n2+1, sizeof(*ParamName));
for (i=0; i<n2; i++)
fread (&ParamName[i], sizeof(ParamName[i]), 1, fich);
// offset2
fread (&offset2, sizeof(short), 1, fich);
if ((strcmp(GroupName, "POINT")==0) &&
(strcmp(ParamName, "LABELS")==0)) {
// T
fread (&TempChar, sizeof(char), 1, fich);
// d
fread (&TempChar, sizeof(char), 1, fich);
d = (int) TempChar;
// Dimensions
Dimensions = calloc (d, sizeof(*Dimensions));
for (i=0;i<d;i++) {
fread (&TempChar, sizeof(char), 1, fich);
Dimensions[i] = (int)TempChar;
}
// lecture des labels
LgLabel = Dimensions[0];
NbTraj = Dimensions[1];
free (Dimensions);
fseek (fich, LgLabel*NbTraj, SEEK_CUR); // on passe les labels
// m2
fread(&TempChar, sizeof(char), 1, fich);
fseek(fich, (int)TempChar, SEEK_CUR); // on passe m2
fread (&TempChar, sizeof(char), 1, fich); // n2
n2 = (int)TempChar;
fread (&TempChar, sizeof(char), 1, fich); // G2
G2 = (int)TempChar;
}
else {
free (ParamName);
// Passage au parametre suivant
fseek(fich,(offset2-2),SEEK_CUR);
fread (&TempChar, sizeof(char), 1, fich); // n2
n2 = (int)TempChar;
fread (&TempChar, sizeof(char), 1, fich); // G2
G2 = (int)TempChar;
}
}
fseek (fich,(-2),SEEK_CUR);
free (GroupName);
fread(&TempChar, sizeof(char), 1, fich); // n
n = (int) TempChar;
}
FermeFichier (&fich);
}
}
Comment je peux lire correctement cet entête en bon C++?
Merci d'avance
Mike |
|
| Back to top |
|
 |
Etienne Rousee Guest
|
Posted: Thu Feb 23, 2006 9:06 am Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
"Michael" <michael_delva.enlever (AT) hotmail (DOT) com> a écrit ...
A part modulariser un peu et remplacer les structures
par des classes et les calloc par des new, tu ne gagneras
pas grand chose à passer ce code en C++.
Il n'y a pas de façon simple de lire des données qui sont
structurellement compliquées, ce qui est presque
toujours le cas quand on tripatouille du binaire.
De plus, ce code ne me paraît pas si compliqué que ça,
sauf si tu as toi-même quelques problèmes en C.
Dans ce cas, extrais les lignes que tu ne comprends pas
et pose la question sur fclc.
--
Etienne |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Thu Feb 23, 2006 11:06 am Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
Michael wrote:
| Quote: | pour un programme que je suis en train de développer, je dois
extraire des informations d'un fichier C3D écrit en binaire,
et qui contient des renseignements sur le résultat d'une
capture de mouvement.
Le souci, c'est que je n'ai jamais eu à faire ce genre de
lecture, et que je sais pas comment m'y prendre.
|
Tu as choisi un format assez difficile pour commencer:-).
| Quote: | Pour commencer, je voudrais juste pouvoir extraire les infos
de l'entête du fichier. Dans la doc
(http://www.c3d.org/HTML/default.htm), il y est dit que ce
fichier est composé de multiples blocs de 512 bytes.
|
Il y est aussi dit que les données sont écrites en binaire, avec
trois formats flottants différents et deux formats entiers. Ce
qui rend la vie nettement plus compliquée.
| Quote: | //
All C3D files contain a minimum of three sections of information:
-----------------------------------------------------------------
A single, 512 byte, header section
-----------------------------------------------------------------
A parameter section consisting of one, or more, 512-byte blocks.
-----------------------------------------------------------------
3D point/analog data section consisting of one, or more, 512-byte blocks.
//
Cette page me donne les différentes composantes de cet entête:
http://www.c3d.org/HTML/description.htm
On m'a filé un code en C qui lit cet entête, mais j'y pipe
rien du tout,
|
Pas grave -- il n'est pas correct. Il suppose beaucoup de choses
qui ne sont pas garanties (et souvent même pas vraies). Il
pourrait marcher sur certains fichiers, quand il a été compilé
avec certains compilateurs, sur certaines plate-formes, mais ce
n'est vraiment pas comme ça qu'il faut s'y prendre.
Lire l'en-tête, c'est déjà pas trivial, parce que l'en-tête
contient des entiers (16 bits) et des flottants (32 bits), et
qu'il faut lire le premier bloc des paramètres pour en savoir le
format. En gros, ce qu'il faut, c'est :
-- ouvrir le fichier (évidemment) ;
-- lire le premier octet, qui donne le début des paramètres ;
-- lire le deuxième octet, si ce n'est pas 0x50, on pourrait
s'arrêter tout de suite ;
-- se positionner au début des paramètres, c-à-d gseek( 512 *
premier octet lu, ios::beg ),
-- lire quatre octets,
-- selon le dernier de ces quatre octets, installer les
routines de lecture, et finalement
-- se positionner de nouveau au début, et commencer réelement.
Ça donne quelque chose du genre :
typedef unsigned char
uchar ;
typedef unsigned short
ushort ;
std::ifstream file( filename, std::ios::binary ) ;
if ( ! file ) {
// Erreur...
}
char soh[ 2 ] ;
file.read( soh, 2 ) ;
if ( ! file ) {
// Erreur ...
}
if ( soh[ 1 ] != 0x50 ) {
// Erreur...
}
if ( ! file.gseek( 512 * static_cast< uchar >( soh[ 0 ] ),
std::ios::beg ) ) {
// Erreur (fichier trop court ?)...
}
char sop[ 4 ] ;
file.read( sop, 4 ) ;
if ( ! file ) {
// Erreur...
}
switch ( sop[ 3 ] ) {
case 84 :
dataHandler = &intelDataHandler ;
break ;
case 85 :
dataHandler = &decDataHandler ;
break ;
case 86 :
dataHandler = &mipsDataHandler ;
break ;
}
file.gseek( 0, std::ios::beg ) ;
Au fond, je verrais bien une classe C3DFile, avec le code
ci-dessus dans le constructeur. Et avec une classe abstraite
DataHandler :
class DataHandler
{
public:
virtual ~DataHandler() {}
virtual short readShort( istream& source ) const = 0 ;
virtual float readFloat( istream& source ) const = 0 ;
} ;
Ce sont les instances concrètes de cette classe où ça se corse.
Pour un IntelDataHandler, par exemple, ça serait quelque chose
comme :
short
IntelDataHandler::readShort(
istream& source ) const
{
unsigned char tmp[ 2 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 2 ) ) {
// Erreur...
}
// Je suppose ici que la machine cible utilise une
// représentation complément à deux, et gère la
// conversion unsigned -> signed de la façon classique.
return (tmp[ 1 ] << | tmp[ 0 ] ;
}
float
IntelDataHandler::readFloat(
istream& source ) const
{
unsigned char tmp[ 4 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 4) ) {
// Erreur...
}
float result
= ((tmp[ 2 ] & 0x7F) << 16) | (tmp[ 1 ] << | tmp[ 0 ] ;
int dummy ;
result = ldexp( frexp( result, &dummy ),
tmp[ 2 ] >> 7 | tmp[ 3 ] << 1 ) ;
return (tmp[ 3 ] & 0x80) != 0
? - result
: result ;
}
Ensuite, pour chaque bloc, tu lis les données dans l'ordre, au
moyen des functions ci-dessus. Si on imagine une classe
C3DEntete, par exmple, qui resemble un peu à :
class C3DHeader
{
public:
//! \pre
//! source est positionnée au début du fichier.
C3DInputFile& read( C3DInputFile& source ) ;
// ...
private:
long parameterOffset ;
int pointCount ;
int measurementCount ;
// ...
float frameRate ;
// ...
} ;
C3DInputFile&
C3DHeader::read(
C3DInputFile& source )
{
parameterOffset = 512 * source.readByte() ;
source.readByte() ; // sauter le 0x50.
pointCount = source.readShort() ;
measurementCount = source.readShort() ;
// ...
frameRate = source.readFloat() ;
// ...
}
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Thu Feb 23, 2006 11:06 am Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
"Etienne Rousee" <etienne (AT) rousee (DOT) org> wrote in news:43fd76f4$0$21278
$8fcfb975 (AT) news (DOT) wanadoo.fr:
| Quote: |
"Michael" <michael_delva.enlever (AT) hotmail (DOT) com> a écrit ...
Cette page me donne les différentes composantes de cet entête:
http://www.c3d.org/HTML/description.htm
On m'a filé un code en C qui lit cet entête, mais j'y pipe rien du tout,
A part modulariser un peu et remplacer les structures
par des classes et les calloc par des new, tu ne gagneras
pas grand chose à passer ce code en C++.
Il n'y a pas de façon simple de lire des données qui sont
structurellement compliquées, ce qui est presque
toujours le cas quand on tripatouille du binaire.
De plus, ce code ne me paraît pas si compliqué que ça,
sauf si tu as toi-même quelques problèmes en C.
Dans ce cas, extrais les lignes que tu ne comprends pas
et pose la question sur fclc.
|
Ben en gros tout...
Sachant que le fichier fonctionne par blocs de 512 bytes, ya pes moyen
d'utiliser la STL pour lire bloc par bloc et de convertir chaque bloc en
une structure adéquate?
Du genre remplir un buffer de 512 bytes et transtyper en ENTETEC3D? |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Thu Feb 23, 2006 12:06 pm Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
| Quote: | Tu as choisi un format assez difficile pour commencer:-).
|
Ben c'est à dire que là, je n'ai pas trop eu le choix
| Quote: | Pas grave -- il n'est pas correct. Il suppose beaucoup de choses
qui ne sont pas garanties (et souvent même pas vraies). Il
pourrait marcher sur certains fichiers, quand il a été compilé
avec certains compilateurs, sur certaines plate-formes, mais ce
n'est vraiment pas comme ça qu'il faut s'y prendre.
|
Bon, ben c'est déjà bon à savoir ça!
| Quote: | Lire l'en-tête, c'est déjà pas trivial, parce que l'en-tête
contient des entiers (16 bits) et des flottants (32 bits), et
.......
|
Merci beaucoup!
Je me penche là dessus cet après-midi, et je reviens en cas de souci...
(autant dire à bientôt ) |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Thu Feb 23, 2006 7:06 pm Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
Michael wrote:
| Quote: | "Etienne Rousee" <etienne (AT) rousee (DOT) org> wrote in news:43fd76f4$0$21278
$8fcfb975 (AT) news (DOT) wanadoo.fr:
"Michael" <michael_delva.enlever (AT) hotmail (DOT) com> a écrit ...
Cette page me donne les différentes composantes de cet entête:
http://www.c3d.org/HTML/description.htm
On m'a filé un code en C qui lit cet entête, mais j'y pipe
rien du tout,
A part modulariser un peu et remplacer les structures par des
classes et les calloc par des new, tu ne gagneras pas grand
chose à passer ce code en C++. Il n'y a pas de façon simple
de lire des données qui sont structurellement compliquées, ce
qui est presque toujours le cas quand on tripatouille du
binaire. De plus, ce code ne me paraît pas si compliqué que
ça, sauf si tu as toi-même quelques problèmes en C. Dans ce
cas, extrais les lignes que tu ne comprends pas et pose la
question sur fclc.
Ben en gros tout...
Sachant que le fichier fonctionne par blocs de 512 bytes, ya
pes moyen d'utiliser la STL pour lire bloc par bloc et de
convertir chaque bloc en une structure adéquate?
Du genre remplir un buffer de 512 bytes et transtyper en ENTETEC3D?
|
Lire par blocs de 512 octets, ce n'est pas difficile -- voir
std::istream::read(). Mais il n'y a pas de conversion implicite
de char[512] vers ENTETEC3D. Cette partie-là, il va falloir que
tu le tappes toi-même.
--
James Kanze kanze.james (AT) neuf (DOT) fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Thu Feb 23, 2006 7:06 pm Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
On 22 Feb 2006 22:57:31 GMT, Michael
<michael_delva.enlever (AT) hotmail (DOT) com>:
| Quote: | On m'a filé un code en C qui lit cet entête, mais j'y pipe rien du tout
|
Moi, j'ai reçu un code C pour créer un hash MD5 à partir d'un char*.
Je n'ai pas cherché à le comprendre ; je me suis contenté de
l'encapsuler, de telle sorte que je n'aie pas à l'utiliser
directement.
J'ai maintenant un joli .h qui contient grosso modo :
std::string CalculerMD5 (std::string const&)
ainsi que quelques .c et .cpp qui font ce qu'ils veulent dans leur
coin.
Je te conseille de faire pareil : si le code fonctionne, inutile de le
refaire. Contente-toi de faire une jolie interface C++ pour l'utiliser
sans te prendre la tête. |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Fri Feb 24, 2006 9:06 am Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
Fabien LE LEZ wrote:
| Quote: | On 22 Feb 2006 22:57:31 GMT, Michael
michael_delva.enlever (AT) hotmail (DOT) com>:
On m'a filé un code en C qui lit cet entête, mais j'y pipe
rien du tout
Moi, j'ai reçu un code C pour créer un hash MD5 à partir d'un
char*. Je n'ai pas cherché à le comprendre ; je me suis
contenté de l'encapsuler, de telle sorte que je n'aie pas à
l'utiliser directement.
J'ai maintenant un joli .h qui contient grosso modo :
std::string CalculerMD5 (std::string const&)
ainsi que quelques .c et .cpp qui font ce qu'ils veulent dans
leur coin.
Je te conseille de faire pareil : si le code fonctionne,
inutile de le refaire. Contente-toi de faire une jolie
interface C++ pour l'utiliser sans te prendre la tête.
|
Et comment est-ce que tu sais qu'il fonctionne, si tu ne le
comprends pas ? Dans le cas de MD5, il y a un fonctionnement
très précis et limité -- en fait, s'il calcule cinq ou six
hachages correctement, il y a de bonnes chances (prèsqu'une
certitude, en fait) qu'il est correct, et un survol rapide pour
vérifier qu'il n'y a pas de dépassement de buffer et des choses
de ce genre pourrait suffire. Sur ta machine, en tout cas --
passer sur une autre machine, et tu dois récommencer tous les
tests. Tandis que si tu jettes un coup d'oeil à son protocol...
tu verras que c'est plein d'options et de variantes. Le fait
d'avoir pu lire un fichier correctement, sur une machine, ne
prouve pas grand chose. Et en fait, un survol rapide m'a montré
qu'en effet, il ne traite pas les variantes ; il marchera sur
certains fichiers -- surtout ceux écrit sur la même machine --
et pas pour d'autres.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Fri Feb 24, 2006 7:06 pm Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
On 24 Feb 2006 00:09:10 -0800, "kanze" <kanze@gabi-soft.fr>:
| Quote: | Et comment est-ce que tu sais qu'il fonctionne, si tu ne le
comprends pas ?
|
Tout est dans le "on" de "On m'a filé un code[...]".
Si tu estimes que le "on" est digne de confiance, tu fais confiance au
code.
Sinon, si tu ne comprends pas le code, tu le jettes et tu le refais. |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Sun Feb 26, 2006 4:06 pm Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
| Quote: | Tout est dans le "on" de "On m'a filé un code[...]".
Si tu estimes que le "on" est digne de confiance, tu fais confiance au
code.
Sinon, si tu ne comprends pas le code, tu le jettes et tu le refais.
|
Tout est dit Je refais  |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Sun Feb 26, 2006 6:06 pm Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
| Quote: | class DataHandler
{
public:
virtual ~DataHandler() {}
virtual short readShort( istream& source ) const = 0 ;
virtual float readFloat( istream& source ) const = 0 ;
} ;
Ce sont les instances concrètes de cette classe où ça se corse.
Pour un IntelDataHandler, par exemple, ça serait quelque chose
comme :
short
IntelDataHandler::readShort(
istream& source ) const
{
unsigned char tmp[ 2 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 2 ) ) {
// Erreur...
}
// Je suppose ici que la machine cible utilise une
// représentation complément à deux, et gère la
// conversion unsigned -> signed de la façon classique.
return (tmp[ 1 ] << | tmp[ 0 ] ;
}
float
IntelDataHandler::readFloat(
istream& source ) const
{
unsigned char tmp[ 4 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 4) ) {
// Erreur...
}
float result
= ((tmp[ 2 ] & 0x7F) << 16) | (tmp[ 1 ] << | tmp[ 0 ] ;
int dummy ;
result = ldexp( frexp( result, &dummy ),
tmp[ 2 ] >> 7 | tmp[ 3 ] << 1 ) ;
return (tmp[ 3 ] & 0x80) != 0
? - result
: result ;
}
|
Quelles seraient les implémentations des classes permettant de lire des short
ou des floats pour des représentations DEC ou MIPS?
Je ne connais absolument rien à ce pan de la programmation... |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Sun Feb 26, 2006 8:06 pm Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
"kanze" <kanze@gabi-soft.fr> wrote in news:1140691900.559197.28400
@z34g2000cwc.googlegroups.com:
| Quote: | float
IntelDataHandler::readFloat(
istream& source ) const
{
unsigned char tmp[ 4 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 4) ) {
// Erreur...
}
float result
= ((tmp[ 2 ] & 0x7F) << 16) | (tmp[ 1 ] << | tmp[ 0 ] ;
int dummy ;
result = ldexp( frexp( result, &dummy ),
tmp[ 2 ] >> 7 | tmp[ 3 ] << 1 ) ;
return (tmp[ 3 ] & 0x80) != 0
? - result
: result ;
}
|
J'ai une erreur à l'éxécution sur la dernière ligne:
Débordement en virgule flottante
sur :
return (tmp[ 3 ] & 0x80) != 0 ? - result : result;
De où ça vient?
Question subsidiaire: avez-vous des liens qui pourraient me permettre de
comprendre le code ci-dessus, qui pour moi est du chinois le plus complet? |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Mon Feb 27, 2006 9:06 am Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
Michael wrote:
| Quote: | "kanze" <kanze@gabi-soft.fr> wrote in news:1140691900.559197.28400
@z34g2000cwc.googlegroups.com:
float
IntelDataHandler::readFloat(
istream& source ) const
{
unsigned char tmp[ 4 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 4) ) {
// Erreur...
}
float result
= ((tmp[ 2 ] & 0x7F) << 16) | (tmp[ 1 ] << | tmp[ 0 ] ;
int dummy ;
result = ldexp( frexp( result, &dummy ),
tmp[ 2 ] >> 7 | tmp[ 3 ] << 1 ) ;
return (tmp[ 3 ] & 0x80) != 0
? - result
: result ;
}
J'ai une erreur à l'éxécution sur la dernière ligne:
Débordement en virgule flottante
sur :
return (tmp[ 3 ] & 0x80) != 0 ? - result : result;
De où ça vient?
|
Du fait que j'ai oublié à « normaliser » l'exposant et la
mantisse dans ce code. Voir mon autre réponse.
| Quote: | Question subsidiaire: avez-vous des liens qui pourraient me
permettre de comprendre le code ci-dessus, qui pour moi est du
chinois le plus complet?
|
Oui et non? Avec quel aspect est-ce que tu as des problèmes :
-- Avec les opérateurs >>, <<, et | ? Ce sont des opérateurs
binaires de C++ (et de C). Il doit bien y avoir des pages
quelque part qui les expliquent en détail, mais je ne sais
pas où -- en venant du côté hardware, il me semble tellement
naturels que je n'ai jamais cherché une explication.
-- Avec les fonctions frexp() et ldexp() ? Ce sont des
fonctions standard de C (et donc de C++). Il faut les
chercher dans la documentation de C.
-- Avec le format des virgules flottants en général ? Il y a
beaucoup de liens à
http://cch.loria.fr/documentation/IEEE754/ (malheureusement,
beaucoup d'entre eux n'ont pas l'air de marcher -- et le
firewall ici me réfuse accès à d'autres !). D'après mes
souvenirs, www.validgh.com était un lien essentiel, mais
c'est celui dont le firewall ici me réfuse l'accès.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Mon Feb 27, 2006 9:06 am Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
Michael wrote:
| Quote: | class DataHandler
{
public:
virtual ~DataHandler() {}
virtual short readShort( istream& source ) const = 0 ;
virtual float readFloat( istream& source ) const = 0 ;
} ;
Ce sont les instances concrètes de cette classe où ça se corse.
Pour un IntelDataHandler, par exemple, ça serait quelque chose
comme :
short
IntelDataHandler::readShort(
istream& source ) const
{
unsigned char tmp[ 2 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 2 ) ) {
// Erreur...
}
// Je suppose ici que la machine cible utilise une
// représentation complément à deux, et gère la
// conversion unsigned -> signed de la façon classique.
return (tmp[ 1 ] << | tmp[ 0 ] ;
}
float
IntelDataHandler::readFloat(
istream& source ) const
{
unsigned char tmp[ 4 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 4) ) {
// Erreur...
}
float result
= ((tmp[ 2 ] & 0x7F) << 16) | (tmp[ 1 ] << | tmp[ 0 ] ;
int dummy ;
result = ldexp( frexp( result, &dummy ),
tmp[ 2 ] >> 7 | tmp[ 3 ] << 1 ) ;
return (tmp[ 3 ] & 0x80) != 0
? - result
: result ;
}
Quelles seraient les implémentations des classes permettant de
lire des short ou des floats pour des représentations DEC ou
MIPS?
|
Les short dans la représentation DEC, c'est identique aux short
Intel -- je crois (sans être 100% certain) que pour le MIPS, il
faut inverser le 1 et le 0 dans le return.
Quant aux floats... Il faudrait trouver de la documentation
quelque part sur leur format sur ces machines. Je ne le connais
pas. (J'ai lu quelque part que le format DEC -- c-à-d le format
PDP-11, je suppose, parce que DEC a fabriqué d'autres machines,
avec d'autres formats aussi -- est très proche du IEEE qui
utilise Intel. Reste à savoir aussi si l'ordre des octets est
1234, comme chez Intel, ou 3412, comme étaient les long, si mes
souvenirs sont exacts.)
| Quote: | Je ne connais absolument rien à ce pan de la programmation...
|
C'est un peu spécial:-). Je le connais moi-même surtout parce
que je viens du côté hardware, et que j'ai travaillé à ce niveau
il y a une vingtaine d'années.
En gros, en ce qui concerne les entiers, je crois qu'on ne prend
pas trop de risque en supposant une représentation en complément
à deux. Et c'est bien écrit que les entiers dans ton fichier
sont tous à 16 bits, c-à-d deux octets (ici, « octet » en
anglais, et non « byte »). Alors, la seule question, c'est
l'ordre des octets -- est-ce que c'est le premier ou le deuxième
qui est le poid fort.
En ce qui concerne les flottants, c'est bien plus complexe. En
gros, un flottant comporte trois champs : une mantisse, un
exposant et un bit de signe. Alors, pour commencer, il faut
savoir où se trouve les trois champs dans les quatre octets, et
la représentation de chaque champs. (Et en passant, j'ai écrit
le code ci-dessus à la volée, et en le regardant, je vois tout
de suite au moins deux erreurs.) Pour le format IEEE, on a un
exposant de 8 bits, en excès 126, une mantisse de 24 bits, dont
le bit de poids fort est toujours 1, et n'est pas représenté, et
une signe d'un bit. Chez Intel, on trouve la signe sur le bit de
poid fort du dernier octet, l'exposant sur les sept autres bits
de cet octet, plus le bit de poid fort de l'avant dernier octet,
et la mantisse sur les autres bits. Il s'agit alors de les
extraire, de les normaliser (ce que j'ai oublié dans le code
ci-dessus), et d'en recomposer le flottant dans le format natif,
à l'aide des fonctions du genre ldexp et frexp. (Si on ne tiens
pas à la portabilité, et qu'on sait bien ce qu'on fait, on peut
aussi composer le float directement en mémoire soi-même.)
Si j'ajoute les normalisations au code que j'ai posté, ça
ressemblerait à :
IntelDataHandler::readFloat(
istream& source ) const
{
unsigned char tmp[ 4 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 4) ) {
// Erreur...
}
float result
= (((tmp[ 2 ] & 0x7F) << 16 | 0x800000)) | (tmp[ 1 ] <<
| tmp[ 0 ] ;
int dummy ;
result = ldexp( frexp( result, &dummy ),
(tmp[ 2 ] >> 7 | tmp[ 3 ] << 1) - 126 ) ;
return (tmp[ 3 ] & 0x80) != 0
? - result
: result ;
}
Aussi, il faudrait faire un cas à part pour 0 -- si l'exposant
est 0, il ne faut pas faire le « | 0x800000 » sur la mantisse,
ni soustraire quoique ce soit de l'exposant.
Et finalement, j'ai ignoré complétement la question des valeurs
NaN et Inf. Encore des cas spéciaux, cette fois-ci si l'exposant
est 0xFF.
Dans la pratique, j'ai résolu le problème pour le format XDR,
qui correspond au format Intel sauf en ce qui concerne l'ordre
des octets. Vu que le format XDR comporte aussi des entiers
non-signé de quatre octets, j'ai pû travailler directement
là-dessus, mais ce n'est pas dit que ce soit une mauvaise idée
dans ton cas -- c'est peut-être un peu plus transparent ce qui
se passe. Enfin, ce que ça donne, c'est :
ixdrstream&
ixdrstream::operator>>(
GB_uint32_t& dest )
{
ByteGetter source( *this ) ;
GB_uint32_t tmp = source.get() << 24 ;
tmp |= source.get() << 16 ;
tmp |= source.get() << 8 ;
tmp |= source.get() ;
if ( *this ) {
dest = tmp ;
}
return *this ;
}
ixdrstream&
ixdrstream::operator>>(
float& dest )
{
GB_uint32_t tmp ;
operator>>( tmp ) ;
if ( *this ) {
float f = 0.0 ;
if ( (tmp & 0x7FFFFFFF) != 0 ) {
f = ldexp( ((tmp & 0x007FFFFF) | 0x00800000),
(int)((tmp & 0x7F800000) >> 23) - 126 - 24 )
;
}
if ( (tmp & 0x80000000) != 0 ) {
f = -f ;
}
dest = f ;
}
return *this ;
}
(Ici non plus, je n'ai pas encore traité tous les cas spéciaux,
genre Inf ou NaN. En revanche, le code est testé pour des cas
« normaux ».)
ByteGetter, c'est une classe assez simple qui s'occupe de gérer
les erreurs s'il n'y a pas d'octet disponible.
Pour Intel, il faudrait surtout inverser l'ordre des octets dans
l'extraction du uint32_t. Sinon, la reste doit marcher.
Note aussi que vue que je connais l'exposant après la conversion
de la mantisse en flottant, je triche sur l'offset de l'exposant
que je passe à ldexp, plutôt que d'appeler frexp.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Mon Feb 27, 2006 1:06 pm Post subject: Re: Récupération des infos dans un fichier binaire C3D |
|
|
"kanze" <kanze@gabi-soft.fr> wrote in news:1141029270.916616.10520
@u72g2000cwu.googlegroups.com:
| Quote: | IntelDataHandler::readFloat(
istream& source ) const
{
unsigned char tmp[ 4 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 4) ) {
// Erreur...
}
float result
= (((tmp[ 2 ] & 0x7F) << 16 | 0x800000)) | (tmp[ 1 ] <<
| tmp[ 0 ] ;
int dummy ;
result = ldexp( frexp( result, &dummy ),
(tmp[ 2 ] >> 7 | tmp[ 3 ] << 1) - 126 ) ;
return (tmp[ 3 ] & 0x80) != 0
? - result
: result ;
}
|
Il y a encore une erreur chez moi, avec tmp: { 0xCD, 0xCC, 0xCC, 0xBD }
depuis le fichier...
J'ai l'exception Débordement en virgule flottante...
La valeur qui devrait être retournée est -0,10
Par contre avec tmp: { 0x0, 0x0, 0x70, 0x42 } j'ai bien la bonne valeur, à
savoir 60
Je vais jeter un oeil sur de la doc sur internet. Je commence à piger
quelques trucs, mais c'est vraiment pas facile...
En tout cas, merci pour ton aide! |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|