Probleme sur la structure des fichiers excels (office) [Résolu]

Signaler
Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
-
Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
-
Bonjour a tous,
Je suis en trein d'étudier la structure des fichiers excel pour voir si j'arrive a acceder aux cellules sans avoir excel sur le poste. Donc pas besoin de payer de licence ...

J'ai déja mainte fois étudié des contenus binairs de fichiers tel le java ...
mais jamais je ne me suis autant pris la tête ^_^
Pour l'exemple, les fichiers excels sont "encapsulés" dans un système FAT. Oui oui dans le fichier

Donc, avant même d'atteindre le codage du fichier excel , il me faut le "dé-encapsuler".

Vous pourrez trouver la spécification de la structure des fichiers office à cette adresse :
http://msdn.microsoft.com/en-us/library/dd941946(PROT.10).aspx

Mon problème :
Dès le début de la lecture du fichier en mode binaire, je ne suis pas d'accord avec la spécification.
A savoir : le header.

Voici mon code :

Public Type t_HEADER
    signature(1 To 8) As Byte                   ' magic number
    clsid(1 To 16) As Byte                      '
    minor_version As Integer                    '
    major_version As Integer                    '
    order As Integer                            '
    sector_shift As Integer                     ' sector size = 2^sector_shift (512 if 0x0009; 4096 if 0x000C ...)
    mini_sector_shift As Integer                ' sector size = 2^sector_shift (512 if 0x0009; 4096 if 0x000C ...)
    reserved(1 To 6) As Byte                    '
    number_of_directory_sectors As Long         '
    number_of_fat_sectors As Long               '
    first_directory_sector_location As Long     '
    transaction_signature_number As Long        '
    mini_stream_cutoff_size As Long             '
    first_mini_fat_sector_location As Long      ' index dans le difat ou code FAT SECTOR
    number_of_mini_fat_sectors As Long          '
    first_mini_difat_sector_location As Long    ' index dans le difat ou code FAT SECTOR
    number_of_difat_sectors As Long             ' nombre de secteurs de difat (si fichier > 7Mb)
    DIFAT(1 To 109) As Long                     ' les 109 premiers etats des secteurs (
End Type
Public Const Hsignature = "D0 CF 11 E0 A1 B1 1A E1"
Public Const Hclsid = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"    '16 zeros

Public Function Ouvrire(file As String) As String
On Error GoTo fin
    
    'déclarer et allouer un canal de flux disponible
    Ouvrire = "Alocation du canal de flux"
    Dim canal As Byte
        canal = FreeFile

    'ouvrire le fichier en mode binaire & lecture seule
    Ouvrire = "Ouverture du fichier"
    Open file For Binary Access Read As #canal

        'Entête
        Ouvrire = "Lecture de l'entête"
            Dim header As t_HEADER
            Get #canal, , header
            
            'vérification de la signature du document
            If (to_hex_str(header.signature) <> Hsignature) Then
                Ouvrire = "'Header Signature' non conforme."
                GoTo fin
            End If
            
            'vérification du clsid du doccument
            If (to_hex_str(header.clsid) <> Hclsid) Then
                Ouvrire = "'Header CLSID' non conforme."
                GoTo fin
            End If
[...]


Dans les valeurs chargées dans le header, tout semble bon sauf les données suivantes :
     header.first_directory_sector_location = 1
     header.first_mini_difat_sector_location = 13951
     header.first_mini_fat_sector_location = 26917


ce qui me choque c'est que j'ai nb de directory sector = 0 (donc pkoi a voir une location et que ensuite, minidifat et minifat location sont sensés être inférieurs au nombre de fat secteur soit 212 dans mon cas ...


J'ai bien conscience que c'est une question alaquelle très peu peuvent répondre. Néamoins, si quelqu'un a une piste je suis preneur

Merci d'avance et a bientôt


VB6, quand yen a plus yen a encore
Il y a tant a apprendre et seulement 24 heures dans une journée

9 réponses

Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
3
Bon ba ca y est, le mystère est résolu

les erreurs faites :

- number_of_fat_sector n'est pas le nombre de secteur fat dans le fichier mais le nombre de secteur fat contenant la table de chainage FAT
( franchement microsoft aurrait pu choisir des termes qui induisent moins en erreur )

- DIFAT contient, dans l'ordre, la liste des index des secteurs fat contenant la table de chainage FAT

- le secteur d'indice 0 n'est pas toujours le premier secteur contenant les données de chainage FAT

- en VB6 le type long est bien sur 4 octets mais il est également signé. il faut donc utiliser une bidouille pour lire des "unsigned long" apelés DWORD par microsoft
Public Type DWORD
    bytes(1 To 4) As Byte
End Type

Public Function Dbl_DWORD(DW As DWORD) As Double
    Dim i As Integer
    Dim tmp As String
    For i = 1 To 4
        Dbl_DWORD = Dbl_DWORD + CDbl(DW.bytes(i)) * (2 ^ (8 * (i - 1)))
    Next
End Function

Public Function Hex_DWORD(DW As DWORD) As String
    Dim i As Integer
    Dim tmp As String
    For i = 1 To 4
        tmp = Hex(DW.bytes(i))
        tmp = String(2 - Len(tmp), "0") & tmp
        
        Hex_DWORD = tmp & Hex_DWORD
    Next
End Function


Lorsque j'aurais terminé de mettre en forme tout ceci, je posterais une source (VB6)

amicalement,
Messages postés
14008
Date d'inscription
samedi 29 décembre 2001
Statut
Modérateur
Dernière intervention
28 août 2015
73
Je ne sais pas si ça t'avancera, mais voilà les valeurs hexa que je récupère sur un classeur Excel 2003 (composé de deux feuilles) :
.minor_version                            3E
.major_version                            3
.order                                    FFFE
.sector_shift                             9
.mini_sector_shift                        6
.number_of_directory_sectors              0
.number_of_fat_sectors                    2
.first_directory_sector_location          DC
.transaction_signature_number             0
.mini_stream_cutoff_size                  1000
.first_mini_fat_sector_location           FFFFFFFE
.number_of_mini_fat_sectors               0
.first_mini_difat_sector_location         FFFFFFFE
.number_of_difat_sectors                  0
.DIFat(1 to 109) :
(1)           DA DB FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
(10)          FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
(20)          FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
(30)          FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
(40)          FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
(50)          FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
(60)          FF FF FF FF FF FF FF FF FF FF FF FF FF 

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
3
Bonjour,
c'est toujours bien de pouvoir comparer
comment concidère tu les données que tu as ? sont elles bonne (entendre exploitables)

.first_directory_sector_location DC

Cette donnée me choque dans la mesure ou tu as tout comme moi :
.number_of_directory_sectors 0


.first_mini_difat_sector_location FFFFFFFE
= ENDOFCHAIN
est normal puisque tu as
.number_of_fat_sectors 2

2 étant < 110 les difats sont tous dans le header

ce qui m'embête le plus c'est
.first_mini_fat_sector_location FFFFFFFE

car pour moi, cette donnée est sensée donne l'index du premier secteur de type FATSECT et la c'est un end of chain...

.DIFat(1 to 109) :
(1) DA DB FF FF FF FF FF FF FF FF FF FF FF FF FF FF
(10) FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF

Quelle représentation est-ce là ?
normalement les DIFAT sont des long (soit 4 octets) --> 16 digits hexa donc

en tout les cas merci de ton aide, je me sens moins seul face a ces fichiers à la noix. Si les gens savaient comment les fichiers sont faits, il ésiteraient bien plus à le utiliser je pense

VB6, quand yen a plus yen a encore
Il y a tant a apprendre et seulement 24 heures dans une journée
Messages postés
14008
Date d'inscription
samedi 29 décembre 2001
Statut
Modérateur
Dernière intervention
28 août 2015
73
Oui, tu as raison, je suis allé un peu vite et j'ai loupé ce type Long
.DIFAT(1 To 109) :
(1) 00DA 00DB FFFF FFFF ...

Quant au .first_directory_sector_location, j'ai pris un autre fichier Excel (2003 avec 3 feuilles, une UserForm et des macros) pour tester, et j'obtiens :
.minor_version                            3E
.major_version                            3
.order                                    FFFE
.sector_shift                             9
.mini_sector_shift                        6
.number_of_directory_sectors              0
.number_of_fat_sectors                    3
.first_directory_sector_location          1
.transaction_signature_number             0
.mini_stream_cutoff_size                  1000
.first_mini_fat_sector_location           2
.number_of_mini_fat_sectors               3
.first_mini_difat_sector_location         FFFFFFFE
.number_of_difat_sectors                  0
.DIFAT(1 To 109) :
(1)           0000 007F 00FF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(11)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(21)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(31)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(41)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(51)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(61)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 

Un autre fichier 2003, 1 feuille, 1 Userform et des macros
.minor_version                            3E
.major_version                            3
.order                                    FFFE
.sector_shift                             9
.mini_sector_shift                        6
.number_of_directory_sectors              0
.number_of_fat_sectors                    1
.first_directory_sector_location          1
.transaction_signature_number             0
.mini_stream_cutoff_size                  1000
.first_mini_fat_sector_location           1F
.number_of_mini_fat_sectors               2
.first_mini_difat_sector_location         FFFFFFFE
.number_of_difat_sectors                  0
.DIFAT(1 To 109) :
(0)           0000 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(11)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(21)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(31)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(41)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(51)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 
(61)          FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF


Code utilisé pour cette présentation (si d'autres veulent tester)
(avec le typage du Header proposé en tête de ce topic)
    Dim header As t_HEADER
    Dim canal As Byte
    Dim r As Long
    
    canal = FreeFile
    Ouvrire = "Ouverture du fichier"
    Open file For Binary Access Read As #canal
        Get #canal, , header
    Close #canal

    With header
        Debug.Print Left$(".minor_version" & String(34, " "), 34); Hex(.minor_version)
        Debug.Print Left$(".major_version" & String(34, " "), 34); Hex(.major_version)
        Debug.Print Left$(".order" & String(34, " "), 34); Hex(.order)
        Debug.Print Left$(".sector_shift" & String(34, " "), 34); Hex(.sector_shift)
        Debug.Print Left$(".mini_sector_shift" & String(34, " "), 34); Hex(.mini_sector_shift)
        Debug.Print Left$(".number_of_directory_sectors" & String(34, " "), 34); Hex(.number_of_directory_sectors)
        Debug.Print Left$(".number_of_fat_sectors" & String(34, " "), 34); Hex(.number_of_fat_sectors)
        Debug.Print Left$(".first_directory_sector_location" & String(34, " "), 34); Hex(.first_directory_sector_location)
        Debug.Print Left$(".transaction_signature_number" & String(34, " "), 34); Hex(.transaction_signature_number)
        Debug.Print Left$(".mini_stream_cutoff_size" & String(34, " "), 34); Hex(.mini_stream_cutoff_size)
        Debug.Print Left$(".first_mini_fat_sector_location" & String(34, " "), 34); Hex(.first_mini_fat_sector_location)
        Debug.Print Left$(".number_of_mini_fat_sectors" & String(34, " "), 34); Hex(.number_of_mini_fat_sectors)
        Debug.Print Left$(".first_mini_difat_sector_location" & String(34, " "), 34); Hex(.first_mini_difat_sector_location)
        Debug.Print Left$(".number_of_difat_sectors" & String(34, " "), 34); Hex(.number_of_difat_sectors)
        Debug.Print ".DIFAT(1 To 109) :"
        Debug.Print "(1)",
        For r = 1 To 109
            Debug.Print Right$("0000" & Hex(.DIFAT(r)), 4) & " ";
            If r Mod 16 = 0 Then
                Debug.Print
                Debug.Print "("; Hex(r + 1); ")",
            End If
        Next r
        Debug.Print
    End With
Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
3
la specif complète est donnée dans le document "[MS-CFB].pdf"
Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
3
Aha !!! J'ai trouvé du nouveau.
les données suivantes me paraissaient bizzard.
.number_of_directory_sectors 0
.first_directory_sector_location 1

Et il semblerait que pour microsoft, ce qui n'est pas dit est évident.

J'ai été voir du côté du directory_sector et en effet, 2nd secteur (donc d'indice 1) contient des données exploitables.

voici ce que j'y ai trouvé :
'Le Directory Entry
Public Type t_DENTRY
    Directory_Entry_Name(1 To 32) As Integer    ' nul terminated string UTF-16 (2 octets par caractère)
    Directory_Entry_Name_Length As Integer      ' longueur de la chaine de caractère (comprenant le '\n')
    Object_Type As Byte                         ' type d'objet
    Color_Flag As Byte                          '
    Left_Sibling_ID As Long                     '
    Right_Sibling_ID As Long                    '
    Child_ID As Long                            '
    clsid(1 To 16) As Byte                      ' doivent être 0
    State_Bits As Long                          ' doit être 0
    Creation_Time As Date
    Modified_Time As Date
    Starting_Sector_Location As Long
    Stream_Size As Double
End Type

'Les types d'objets
    Public Const to_Unknown_or_unallocated = 0
    Public Const to_Storage_Object = 1
    Public Const to_Stream_Object = 2
    Public Const to_Root_Storage_Object = 5

'les color flags
    Public Const cf_red = 0
    Public Const cf_black = 1



Avec le code (a la suite du code présenté dans le post de début) :
'Directory Entry
Ouvrire = "Lecture du Directory Entry"
    Dim directory_entry() As t_DENTRY
    ReDim directory_entry(1 To (2 ^ header.sector_shift) / 128)
    Dim i As Integer
    For i = 1 To UBound(directory_entry)
        Get #canal, _
            (header.first_directory_sector_location + 1) * (2 ^ header.sector_shift) + 1 + ((i - 1) * 128), _
            directory_entry(i)
            
        Debug.Print "entry name " & i & " = '" & UTF_16(directory_entry(i).Directory_Entry_Name, directory_entry(i).Directory_Entry_Name_Length) & "'"
    Next


j'obtient des noms tout a fait plausibles :
entry name 1 = 'Root Entry'
entry name 2 = 'Workbook'
entry name 3 = '_VBA_PROJECT_CUR'
entry name 4 = 'Ctls'



Il est à noter que j'ai sauté le secteur FAT d'indice 0 qui se trouve entre le header et le directory entry (je ne sais pas encore ce qu'on y trouve pour le momment ...)

VB6, quand yen a plus yen a encore
Il y a tant a apprendre et seulement 24 heures dans une journée
Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
3
Le secteur 0 contient le premier secteur FAT.
Ce n'est pas marqué clairement dans la doc sauf dans l'exemple en fin de spécif. C'est vrai que c'est presque pas indispensable de le savoir
Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
3
je patauge toujours autant... c'est la première fois que ca m'arrive sur ce genre de code...

Si une personne au fait du codage FAT pouvait m'éclairer sut le comment décoder le FAT (ou au moins celui de microsoft) à l'aide des deux tables
FAT et DIFAT (que je n'arrive tjs pas à reconstituer d'ailleurs ...) je lui en serrait bien reconnaissant
Messages postés
300
Date d'inscription
lundi 17 juillet 2006
Statut
Membre
Dernière intervention
27 mai 2012
3