Analyse/Synthèse
Sauf exceptions, les noms des types, structures, noeuds, listes... suivent ce formalisme:
Mot, Lettre | Définition |
---|---|
S | structure (déclarée par struct). |
T | type (déclarée par typedef). |
N | noeud (Node), lié à une structure contenant un champ "Next". |
L | liste (List), contient un champ "Head" qui est un Node. |
E | énumération (déclarée par enum). |
HT | table de hashage |
_Sdif | précompilé. |
e | valeur énuméré par un enum. |
g | variable global. |
M_ | types de matrice prédéfini. |
F_ | types de frame prédéfini. |
Sdiff | il y a un argument de type FILE *f. |
SdifF | SdifFileT* qui est la structure de plus haut niveau dans la librairie. |
U | unsigned. |
R et W | Read et Write. |
Size | Nombre de bytes (size_t) |
Hash | type bas niveau HashTableT*. |
Error | détection d'erreur grave (débugage essentiellement). |
MatrixType | type de matrice (prédéfini ou utilisateur). |
FrameType | type de frame (prédéfini ou utilisateur). |
Matrix | bloc de données matrice. |
Frame | bloc de données frame. |
Test | test d'erreur haut niveau sur un fichier SDIF (SdifFileT). |
File | fonctionnalité de haut niveau sur des instances de SdifFileT. |
Get et Put | lecture et écriture communes aux fichiers SDIF binaires et aux fichiers pseudo-SDIF textes. Ce sont aussi les lectures et les écritures de certaines structures. |
Read et Write | lecture et écriture exclusivement sur fichiers SDIF binaires. |
écriture texte. SdifFPrint pour un fichier pseudo-SDIF et SdifPrint pour des sorties sur stdout ou stderr (débugage). | |
Scan | lecture exclusivement sur fichiers pseudo-SDIF textes. |
TextConv | conversion de texte à binaire. |
ConvToText | conversion de binaire à texte. |
All | tous les éléments d'un certain type dans 1 niveau de structure de fichier SDIF (ex AllMatrix : toutes les matrices d'1 frame). |
One | 1 seul élément parmi une succession d'éléments de même sorte. |
TimePosition | position disque par rapport au temps. |
Create | construction d'un pointeur sur élément. |
Kill | destruction d'un pointeur. Dans le cas d'un noeud, la fonction retourne le Next |
Num | numéro (identification). |
Nb | nombre de... (cardinal). |
Head et Tail | 1er et dernier élément d'une liste. |
Curr | courant. Cela peut-être un noeud, une signature, une entête de bloc... |
iAAA | ième AAA (compteur) |
La seule dépendance liée au matériel ou au système indiquée par un
#ifdef
est la taille d'une adresse. La librairie fonctionne
sur les OS 32 et 64 bits (16 bits non prévu). On a ainsi:
/* dans SdifRWLowLevel.h*/ #if defined(__mips64) || defined(__alpha) #define _LONG64BITS_ #else #define _LONG32BITS_ #endif
Il y a une dépendance sur le compilateur au niveau du type C
fpos_t
. Certains compilateurs ont fpos_t
défini comme un long
. Pour d'autres, fpos_t
est une structure; on ne peut donc pas faire simplement des opérations
arithmétiques directement sur les variables (ex : Macintosh MacOS8,
CodeWarrior 10).
Dans SdifGlobals.h, on a un faux (précompilé)
type SdifFPosT qui permet d'avoir la position d'un fichier codé sur un
long. La taille de de ce type dépend donc du système : sur IRIX 5.3,
Macintosh... c'est 4 bytes, et sur IRIX64 et Alpha on a 8 bytes. Les
fonctions de positionnement sont donc toujours associés au système
automatiquement (pas de réduction de 8 bytes à 4 bytes sur les
machines 64 bits).
/* SdifGlobals.h fpos_t compatible sur Macintosh */ #ifdef MACINTOSH #define SdifFPosT long #define SdifFGetPos(f,p) ((((*(p)) = ftell(f)) == -1) ? -1 : 0) #define SdifFSetPos(f,p) fseek(f, (*(p)), SEEK_SET) #else #define SdifFPosT fpos_t #define SdifFGetPos(f,p) fgetpos((f),(p)) #define SdifFSetPos(f,p) fsetpos((f),(p)) #endif
SdifGlobals.h : Sont définis des types de très bas niveau représentant
les int
, float
(unsigned
) sur 2, 4,
8 bytes. Cela sous-entend que le matèriel satisfasse :
On a ainsi les types:
typedef short SdifInt2; typedef unsigned short SdifUInt2; typedef int SdifInt4; typedef unsigned int SdifUInt4; typedef float SdifFloat4; typedef double SdifFloat8;
Est associé aux différents types de bas niveau, un type d'énumération qui permet de représenter les différents types avec un codage sur 4 bytes.
float
,int
,char
signed
,unsigned
typedef enum SdifDataTypeE { eFloat4 = 0x20, eFloat8 = 0x40, eInt2 = 0x1010, eUInt2 = 0x1110, eInt4 = 0x1020, eUInt4 = 0x1120, eChar4 = 0x2020 } SdifDataTypeET;
Toujours dans SdifGlobals.h, est défini le type SdifSignature. Une signature
étant un mot de 4 bytes, les signatures sont représentées par un unsigned
int
. Est associée à ce type une énumération des signatures de base, qui
sont celles des chunks spéciaux. Les types de frames et de matrices prédéfinis
n'y sont pas car tous les types de données sont interprétés et évolutifs.
typedef unsigned int SdifSignature; typedef enum SdifSignatureE { eSDIF = 'SDIF' , /* SDIF header */ e1NVT = '1NVT' , /* Name Value Table */ e1TYP = '1TYP' , /* TYPe declarations */ e1MTD = '1MTD' , /* Matrix Type Declaration */ e1FTD = '1FTD' , /* Frame Type Declaration */ e1IDS = '1IDS' , /* ID Stream Table */ eSDFC = 'SDFC' , /* Start Data Frame Chunk (text files) */ eENDC = 'ENDC' , /* END Chunk (text files) */ eENDF = 'ENDF' , /* END File (text files) */ eFORM = 'FORM' , /* FORM for IFF compatibility (obsolete ?) */ eEmptySignature = '\0\0\0\0' } SdifSignatureET;
Quelques fonctions sont directements liées aux signatures:
#define _SdifNbMaxPrintSignature 8 char gSdifStringSignature[_SdifNbMaxPrintSignature][5]; char* SdifSignatureToString(SdifSignature Signature); short SdifSignatureCmpNoVersion(SdifSignature Signature1, SdifSignature Signature2);
SdifSignatureToString
permet de renvoyer un pointeur sur une
chaine de caractères contenant les caractères de la signature passée en argument
avec un caractère de fin de chaine. Ce pointeur est directement utilisable avec
les fonctions de sorties standarts formatées. _SdifNbMaxPrintSignature
(8) et gSdifStringSignature
servent uniquement à cette fonction.
gSdifStringSignature
est un tableau de 8 chaines de caractères,
chacune de taille 5. SdifSignatureToString
utilise ce tableau
de façon cyclique pour son résultat. On évite ainsi de s'occuper de la mémoire
pour ces convertions de signature en chaine de caractères. Toutefois, on ne peut pas
utiliser SdifSignatureToString
plus de 8 fois dans les paramètres d'une
fonctions. On ne pourra pas afficher 9 signatures avec la même instruction
printf
. La première affichié serait la 9ième car c'est la même
position mémoire. Actuellement, aucune utilisation de SdifSignatureToString
n'a dépassée 2 signatures sur une même instruction..
SdifSignatureCmpNoVersion
permet de comparer 2 signatures sans le
premier byte. Ainsi on peut tenter des lectures sur des matrices ou des frames de
version inconnu par le programme lecteur (la librairie doit tout de même connaître
les signatures).
SdifHash.h
SdifHash.c
SdifHashIndexUnion
est un type qui permet de définir
le type d'index d'une table de hashage. On peut en effet avoir des
tables indexée par des chaînes de caratères (méthode classique) et
d'autres directement par des entiers. Le type est défini par un
union
qui est soit un unsigned int
sur 4
bytes soit un tableau de 1 pointeur sur un chaine de caractère. La
représentation sous forme de tableau sert uniquement à fixer la taille
d'une variable de SdifHashIndexUnion
à 4 bytes (ou 8 si
la machine est 64 bits comme Dec Alpha).
typedef union SdifHashIndexU { char* Char[1]; /* tab of one pointer to fixe union size at 4 or 8 bytes */ unsigned int Int4; } SdifHashIndexUT;
SdifHashIndexTypeEnum
est un enum
qui permet
de dire quel type de l'union
est utilisé dans une table de hashage.
typedef enum SdifHashIndexTypeE { eHashChar, eHashInt4 } SdifHashIndexTypeET;
Le type table de hashage est défini comme suit:
typedef struct SdifHashNS SdifHashNT; struct SdifHashNS { SdifHashNT *Next; SdifHashIndexUT Index; void* Data; }; typedef struct SdifHashTableS { SdifHashNT* *Table; unsigned int HashSize; SdifHashIndexTypeET IndexType; void (*Killer)(); /* no verification of arguments */ unsigned int NbOfData; } SdifHashTableT;
Le champ Table
est un pointeur sur un tableau de noeuds de
donnée hashée SdifHashNT
. Le champ Data
du noeud
n'est pas typé. C'est à dire que l'on peut créer des tables de hashages
contenant des objets de type quelconque. Mais pour une table de hashage donnée,
tous les objets sont de même type et de même allocation (statique ou dynamique).
Le seul champ du type SdifHashTableT
contenant une information
sur le type de données de la table est Killer
qui est un pointeur
sur la fonction de destruction associée. Dans le cas d'une table à données statiques,
Killer
doit être NULL
. Les tables de hashages sont
souvent utilisées dans la librairie. Les fichiers SdifHash.* n'utilisent
aucunes informations des autres fichiers.
La taille d'une table de hashage doit être un nombre premier. C'est le
cas de beaucoup de nombres (2^n - 1).
Constantes Précompilées
Token | Valeur | Fichier | Définition |
---|---|---|---|
_SdifUnknownSize | 0xffffffff | SdifGlobals.h | Valeur donnée à un champ indiquant une taille de bloc inconnue. |
_SdifPadding | 8 | SdifGlobals.h | Nombre de bytes d'alignement : 8 bytes => alignement sur 64 bits. |
_SdifFloat8Error | 0xffffffff | SdifGlobals.h | Retour erronée de lecture d'un float (à modifier). |
_SdifStringLen | 1024 | SdifGlobals.h | Taille d'une chaine de caractère à memoire statique |
_SdifTypesFileName | "SdifTypes.STYP" | SdifGlobals.h | Nom du fichier contenant la base de données des types prédéfinis |
_SdifBSLittleE | 4096 | SdifRWLowLevel.h | Taille du buffer maximum pour les lectures, écritures binaires sur fichier. |
_SdifPaddingChar | '\0' | SdifRWLowLevel.h | Caractère utilisé pour le Padding |
_SdifReservedChars | ",;{}[]:" | SdifRWLowLevel.h | Chaine de caractères contenant les caractères résevés de Sdif |
_SdifFrameHeaderSize | 24 | SdifFrame.h | Taille de l'entête d'un frame (constant pour le format). |
_SdifGenHashSize | 127 | SdifGlobals.h | Taille des tables de hashage globales (doit être un nombre premier) |
_SdifNameValueHashSize | 31 | SdifNameValue.h | Taille des tables de hashage d'informations |
_SdifGranule | 1024 | SdifGlobals.h | Taille des blocs d'allocation pour le type SdifOneRowT |
_SdifFloatEps | 1.0e-20 | SdifGlobals.h | Valeur epsilon floattante |
Le type de la machine (BigEndian ou LittleEndian) est détermineé par
la librairie SDIF à l'exécution d'un programme et non en précompilation
des sources SDIF. Ainsi, on a une variable globale gSdifMachineType
accessible partout. Sa valeur est d'un type énuméré SdifMachineEnum
qui propose plusieurs type de machines (SdifRWLowLevel.h). Une fois que cette
variable est affectée, il n'est plus nécessaire de la modifier. La fonction
assiociée à la détermination du type de machine est SdifMachineEnum
SdifGetMachineType(void)
.
typedef enum SdifMachineE { eUndefinedMachine, eBigEndian, eLittleEndian, eBigEndian64, eLittleEndian64, ePDPEndian } SdifMachineET; extern SdifMachineET gSdifMachineType; extern SdifMachineET SdifGetMachineType(void); extern SdifMachineET SdifInitMachineType(void);
Il est souvent nécessaire de lire ou d'écrire des chaines de caractères
dans un fichier et de les recopier dans des pointeurs de char
alloués à la taille ajustée.
extern char gSdifString[_SdifStringLen]; extern char gSdifString2[_SdifStringLen]; extern char gSdifErrorMess[_SdifStringLen];
gSdifString
et gSdifString2
sont utilisées
pour les lectures essentiellement. Elle sont déclarées en taille
statique (_SdifStringLen == 1024
).
gSdifErrorMess
est déclarée comme les précédentes mais
est utilisée exclusivement pour les constructions de messages d'erreur
par des sprintf
.
SdifError.h
SdifError.c
typedef enum SdifErrorE { eFalse = 0, eTrue = 1, eFreeNull = 256, eAllocFail, eArrayPosition, eEof, eFileNotFound, eInvalidPreType, eAffectationOrder, eNoModifErr, eNotInDataTypeUnion, eNotFound, eExistYet, eWordCut, eTokenLength } SdifErrorEnum;
Il s'agit des erreurs dont la detection implique souvent une erreur
de programmation (Sauf pour les erreurs sur fichiers). Elles provoquent
souvent une sortie violante exit(1)
.
eFalse
et eTrue
ne sont qu'une autre représentation
de 0 ou 1. Les erreurs d'interprétation des fichiers dûes par exemple
à un type non défini sont gérées par les tests de haut niveau (SdifTest.*).
La librairie permet de contrôler plusieurs fichiers SDIF en lecture ou écriture
simultanément. Ils sont représentés par une structure de haut niveau
SdifFileS
défini dans SdifFileStruct.h. Ils ont en commun la base
des types prédéfinis (qui est elle-même considérée comme une structure SdifFileT).
Ils ont chacun :
SdifFileS
est de considérer:
SdifNameValuesLT* NameValues
Liste de tables de hashage de type SdifHashTableT*
, où chaque
table correspond à un chunk d'informations.
L'indexation des tables est par le nom de l'information et les données sont
du type SdifNameValueT*
dont le destructeur est
SdifKillNameValue(*)
. La taille de chaque petite table d'information
est _SdifNameValueHashSize
.
SdifHashTableT* MatrixTypesTable
Table contenant tout les types de matrices associées à un fichier.
L'indexation de la table est par un entier représentant le hashage de la signature.
Les données de cette table sont de type SdifMatrixTypeT*
dont le destructeur est SdifKillMatrixType(*)
(SdifMatrixType.*).
SdifHashTableT* FrameTypesTable
Table contenant tout les types de frames associés à un fichier.
L'indexation de la table est par un entier représentant le hashage de la signature.
Les données de cette table sont de type SdifFrameTypeT*
dont le destructeur est SdifKillFrameType(*)
(SdifFrameType.*).
SdifHashTableT* StreamIDsTable
Table contenant tous les Stream IDs associés à un fichier.
L'indexation est par l'entier numID
des Stream IDs.
La taille de la table de hashage est 1, donc il y a continuellement colision,
il s'agit ainsi d'une liste triée par les IDs. Ceci uniquement pour que les
fichiers SDIF est ses Stream IDs triés. Aussi, pour des renumérotations des IDs,
on pourrait préférer cette structure triée.
Les données de la table sont de type SdifStreamIDT*
dont
le destructeur est SdifKillStreamID(*)
(SdifStreamID.*).
Variable globale: SdifFileT *gSdifPredefinedTypes
Les types prédéfinis de SDIF sont interprétés par la librairie au même
titre que les types spécifiques à un fichier. Ceci pour deux raisons:
gSdifPredefinedTypes
est une instance (pointeur) de SdifFileT
dont le mode d'ouverture est la lecture texte seulement. Stream
est donc fermé et TextStream
est ouvert en lecture le temps
du chargement. Si le fichier texte contenant les types prédéfinis est introuvable,
alors la librairie charge les types précodés statiquement dans SdifPreType.*.
Dans ce cas un message sur stderr
indique que la base des types
prédéfinis peut être incomplète.
La liaison entre gSdifPredefinedTypes
et les autres fichiers se fait
à partir des types (C) SdifMatrixTypeT
et SdifFrameTypeT
dont les structures contiennent un lien ("Pre") sur les types prédéfinis.
Dans gSdifPredefinedTypes
les type sont tous dans les listes "Use"
et les liste "Pre" sont vides. La mise à jour des liens ce fait ainsi:
/* SdifF est un pointeur sur SdifFileT. * Signature est la signature du type de matrice. * SdifGetMatrixType(SdifF->MatrixTypesTable, Signature) ne recherche le type * que dans la table des types de matrices de SdifF et non dans celle * de gSdifPredefinedTypes. * Si le type n'existe pas déjà, alors on le recherche dans * gSdifPredefinedTypes->MatrixTypesTable. Si on le trouve, alors * on crée un type de matrice en donnant le type predefini en 2ième * argument de SdifCreateMatrixType puis on ajoute le type à la table de SdifF. */ if (! SdifGetMatrixType(SdifF->MatrixTypesTable, Signature)) { if (PredefinedMatrixType = SdifGetMatrixType(gSdifPredefinedTypes->MatrixTypesTable, Signature)) { SdifCreateMatrixType(Signature, PredefinedMatrixType); SdifPutMatrixType(SdifF->MatrixTypesTable, MatrixType); } else ; /* le type n'existe pas */ } else ; /* le type existe déjà */ /* idem pour les types de frame avec SdifGetFrameType et SdifPutFrameType. */
typedef struct SdifColumnDefS { char *Name; SdifUInt4 Num; } SdifColumnDefT; typedef struct SdifColumnDefNS SdifColumnDefNT; struct SdifColumnDefNS { SdifColumnDefNT *Next; SdifColumnDefT *ColumnDef; }; typedef struct SdifMatrixTypeS SdifMatrixTypeT; struct SdifMatrixTypeS { SdifSignature Signature; SdifMatrixTypeT *MatrixTypePre; SdifColumnDefNT *HeadUse; SdifColumnDefNT *TailUse; SdifUInt4 NbColumnDefUse; SdifUInt4 NbColumnDef; SdifModifModeET ModifMode; };
Un type de matrice est défini comme une signature associée à deux listes dont la concaténation est la suite des colonnes d'un bloc matrice. La première est la liste des colonnes du type prédéfini s'il existe. La seconde est la liste des colonnes de complétion.
Ainsi MatrixTypePre
est le lien sur le type prédéfini
qu'il faut mettre à jour à la rencontre de la signature dans les fichiers
Stream ou Stream ou lors d'ajout "manuel" de colonnes en complétion.
Ce lien est NULL
s'il n'y a pas de type prédéfini pour
la signature considérée.(cf.
Lien vers les types prédéfinis)
HeadUse
et TailUse
sont des acces sur les colonnes
de complétion. Ainsi on retrouve toutes les colonnes d'un type de matrice
en parcourant MatrixTypePre->HeadUse
jusqu'à
MatrixTypePre->TailUse
puis HeadUse
jusqu'à TailUse
.
NbColumnDef est le nombre total de colonnes du type de matrice.
La contruction des listes de colonnes se fait par insertion à la queue pour respecter l'ordonnancement des colonnes imposé par la norme.
typedef struct SdifComponentS { SdifSignature MatrixSignature; char *Name; SdifUInt4 Num; } SdifComponentT; typedef struct SdifComponentNS SdifComponentNT; struct SdifComponentNS { SdifComponentNT *Next; SdifComponentT *Component; }; typedef struct SdifFrameTypeS SdifFrameTypeT; struct SdifFrameTypeS { SdifSignature Signature; SdifFrameTypeT* FrameTypePre; SdifComponentNT *HeadUse; SdifComponentNT *TailUse; SdifUInt4 NbComponentUse; SdifUInt4 NbComponent; SdifModifModeET ModifMode; };
Les types de frames fonctionnent comme les types de matrices. Un type
de frames étant une signature associée à des composants réparties en deux listes,
celle du type de frame prédéfini FrameTypePre->HeadUse
et celle
du type de frame local HeadUse
.
Les composants sont une signature de type de matrice, et un nom. Il est donc nécessaire de mettre à jour les types de matrice, c'est à dire créer le lien vers le type prédéfini s'il existe, lorsque l'on ajoute un nouveau composant au type de frame.(cf. Lien vers les types prédéfinis)
Pour pouvoir créer manuellement et lire des fichiers SDIF, la librairie possède une gestion d'un format pseudo-SDIF texte. Toutes les données d'un fichier SDIF sont convertibles en texte exceptés les tailles de chunks. Les chunks ASCII ont un contenu identique pour les fichiers SDIF binaires et les fichiers texte