Page 1 of 1

Construction of resident-files.

Posted: Tue Aug 29, 2006 2:01 am
by Hroudtwolf
Hello people,

Do anyone knows how are the residentfiles constructed ?
I need this information for a little tool i want to create for myself.

If I try to understand a logic in the pattern of such a file, i fail.




A lot of thanks for your answers.

Best regards

Hroudtwolf

Posted: Tue Aug 29, 2006 6:32 pm
by Denis
I've spend many hours, days and days to understand rersident structure files (Thanks to Fred for our discussion about padding -due to C :wink: )

There is 4 residents types

I give you a code i use to read the residents files. All values are in the linked list. I do not read macros and prototype for last version (4) because i don't need them.
Here is the code i use in my project. Only the procedure, no exmple to use it. Sorry, it's french commented.

Hope it will help you. Try to understand it step by step.

You must call only and once procedure LectureResident(), the other procedure are called by LectureResident()

Code: Select all

; Author : Denis
; Version de PB : 4.00
; Date : August 29, 2006


;- ---  Enumeration Type résident  -----------------
Enumeration
     #res1 = 1 ; codage du type de réside, de la version 1 à 4
     #res2
     #res3
     #res4
EndEnumeration

;- ---  Enumeration des types CT  -----------------
Enumeration ; type codé des constantes dans les résidents de type 4
     #CT_Byte = 0 ; codage des types de constantes stockée dans le res
     #CT_Word = 1
     #CT_Long = 2
     #CT_Quad = 3
     #CT_Float_Double = 5 ; c'est un double précision
     #CT_String = 6
EndEnumeration

;- ---  Enumeration des types CT res3 -----------------
Enumeration ; type codé des constantes dans les résidents de type 3
     #CT_Long_Res3 = 0 ; codage sur un long pour les byte, word et long
     #CT_Float_Simple_Res3 = 4 ; c'est un simple précision
     #CT_String_Res3 = 8
EndEnumeration

;- ---  Enumeration des chaînes Type  -----------------
#CT_Byte_String = "byte"
#CT_String_Char_A = "caractère ascii"
#CT_String_Char_U = "caractère unicode"
#CT_Word_String = "word"
#CT_Long_String = "long"
#CT_Quad_String = "quad"
#CT_Float_String = "float"
#CT_Double_String = "double"
#CT_String_String = "string"
#CT_Interface_String = "interface"
#CT_Structure_String = "structure"
#CT_ListeChainer_String = "liste chainée"

;- ---  Enumeration des types  -----------------
Enumeration ; type utilisé pour coder les éléments dans les structures
     #ST_Byte = 1 ; codage des types de constantes stockée dans le res
     #ST_Word = 2
     #ST_Long = 4
     #ST_Quad = 8
     #ST_Float = 16 ; simple précision
     #ST_Double = 32 ; double précision
     #ST_String = 64
     #ST_Structure = 128
     #ST_Interface = 256
     #ST_Char = 512
     #ST_CharUnicode = 1024
     #ST_tableau = 2048
     #ST_Non_tableau = 4096
     #ST_Pointeur = 8192
     #ST_NonPointeur = 16384
     #ST_ListeChainer = 32768
EndEnumeration


Structure ListDeParametres
     Nom_parametre$ ; > le nom du paramètre
     Type_Parametre.l ; le type
     Nom_Structure$
     Nom_Interface$
EndStructure

Structure ListDeVariables
     Nom_Variable$ ; le nom de la variable
     Type_Variable.l ; le type
     Nom_Structure$
     Nom_Interface$
     Taille.l ; à remplir lorsque l'on crée une string sur la pile, correspond
     ; à la taille réelle de la chaine sans les 4 octets pour stocker
     ; l'adresse de la variable elle-même
     Type .l ; à #Global si global sinon à #local
     Argument_AdresseVar$ ; utilisé uniquement lorsque le registre d'accès est différent de
     ; esp, par ex l'adresse de la var est dword [ebp+32] donc lorsque
     ; l'on génère le code pour charger l'adresse effective en local
     ; on stocke 'dword [ebp + 36]' soit ebp +32 + 4
EndStructure

Structure StructureCourante
     Element$ ; l'élément courant
     Type_Variable.l ; le type long, word, structure etc de l'élément courant stocké sous forme d'une constante
     ; #ST_tableau     = %10000000
     ; #ST_Non_tableau = %01000000
     ; #ST_Pointeur    = %00100000
     ; #ST_NonPointeur = %00010000
     
     Type_Variable$ ; la chaine lue du type dans le res, ex : 'c' , 'd' , ou le npm de la structure ou interface
     TailleElement.l ; Taille de l'élément courant en octets
     TailleTableau.l ; Taille du tableau (valeur entre crochets) en octets, non utilisé si pas tableau
     Offset.l ; déplacement par rapport au début structure
EndStructure

Structure ListeStructures
     Nom_Structure$ ; stocke le nom de la structure
     FichierOrigine$ ; le nom du fichier res ou est déclarée la structure
     TailleStructure.l ; la taille de la structure
     Nb_ElementsStructure.l ; le nombre d’éléments de la structure
     IndexStructureDansListe.l ; stocke l'adresse dans la liste globale pour atteindre directement l'élément
     ; dans la liste chaînée StructureCourante
EndStructure


Structure Constante
     Nom_Constante$
     FichierResident$
     StructureUnion
     ValeurL.l ; utilisé pour les byte, word, Long
     ValeurQ.q ; utilisé pour les quad
     ValeurF.f ; utilisé pour les float simple précision version #res3 (pas de double)
     ValeurD.d ; utilisé pour les float double précision, pas de simple codé pour #res4
     ValeurS.s ; utilisé pour les  constantes de texte
     EndStructureUnion
     Type.l ; type = #CT_String  ou #CT_Float sinon c'est une valeur
     Selection.b ; élément sélectionné ou non
EndStructure


Structure PB_InterfaceMethod
     TailleElement.l
     NbParameters.l
     ; TypeElement.l   ; 8 types à coder
     ; #ST_Byte = 1 ; codage des types de constantes stockée dans le res
     ; #ST_Word = 2
     ; #ST_Long = 4
     ; #ST_Quad = 8
     ; #ST_Float = 16 ; simple précision
     ; #ST_Double = 32 ; double précision
     ; #ST_String = 64
     ; #ST_Structure = 128
EndStructure

Structure InterfaceInfos
     ; Adresse_InfosElement.l ; adresse de la zone mémoire allouée par PB pour stocker les infos des éléménts
     NomMethode$ ; le nom de la méthode
     Nb_Args.b ; le nombre d'arguments pour chaque méthode
     ArgsMethode.s ; la chaine représentant les types d'arguments de la méthode
EndStructure


Structure Nom_ListeInterfaces
     Nom_Interface$ ; le nom de l'interface
     FichierOrigine$ ; le nom du fichier res ou est déclarée l'interface
     TailleInterface.l ; la taille de l'interface
     Nb_Methodes.l ; le nombre de méthodes de l'interface
     IndexInterfaceDansListe.l ; stocke l'adresse dans la liste globale pour atteindre directement l'élément
EndStructure


;- ---  listes chaînées  -----------------
Global NewList ListParametres.ListDeParametres()
Global NewList ListeVariables.ListDeVariables()
Global NewList Constantes.Constante()
Global NewList Nom_Structure.ListeStructures() ; la liste des noms de structures
Global NewList Structures.StructureCourante() ; le détails pour chaque élément de la Structure
; ; dans la liste chainée détaillée
Global NewList Nom_ListeInterfaces.Nom_ListeInterfaces() ; la liste des noms de structures
Global NewList Interfaces.InterfaceInfos() ; le détails pour chaque élément de la Structure
Global NewList Methode.PB_InterfaceMethod()


Procedure ExtractionConstantes(ResType.l, *PointeurDebut.l)
     Protected *ConstantsEnd, Type.b
     Protected CT_String.b, CT_Long.b
     
     ; ici, le pointeur doit être sur le 1er caractère qui suit le long 'TSNC'
     If PeekL(*PointeurDebut) = 0
          ProcedureReturn *PointeurDebut + 4
     EndIf
     
     *ConstantsEnd = *PointeurDebut + PeekL(*PointeurDebut) + 4
     *PointeurDebut + 4
     
     While *PointeurDebut < *ConstantsEnd
          If AddElement(Constantes())
               
               Constantes()\Nom_Constante$ = PeekS(*PointeurDebut) ; lecture nom constante
               Constantes()\FichierResident$ = DirectoryEntryName(0)
               *PointeurDebut + Len(Constantes()\Nom_Constante$) + 1 ; déplacement du pointeur
               
               ; Debug Constantes()\Nom$
               
               Type.b = PeekB(*PointeurDebut)
               
               ; #CT_Byte = 0 ; codage des types de constantes stockée dans le res
               ; #CT_Word = 1
               ; #CT_Long = 2
               ; #CT_Quad = 3
               ; #CT_Float_Double = 5 ; c'est un double précision
               ; #CT_String = 6
               ;
               ; Enumeration ; type codé des constantes dans les résidents de type 3
               ; #CT_Long_Res3 = 0 ; codage sur un long pour les byte, word et long
               ; #CT_Float_Simple_Res3 = 4 ; c'est un simple précision
               ; #CT_String_Res3 = 8
               
               Select ResType
                    Case #res4
                         CT_String = #CT_String
                         CT_Long = #CT_Long
                         
                    Case #res3, #res2
                         CT_String = #CT_String_Res3
                         CT_Long = 0
                         
                    Case #res1
                         Type = 0
                         CT_Long = Type
                         *PointeurDebut - 1 ;- 1 car il n'y a pas de type codé, donc
                         ; il faut revenir en arrière du au Type.b = PeekB(*PointeurDebut)
               EndSelect
               
               Select Type
                         
                    Case CT_Long
                         *PointeurDebut + 1
                         Constantes()\ValeurL = PeekL(*PointeurDebut)
                         *PointeurDebut + 4 ; on arrive sur la nouvelle chaine
                         Select ResType
                              Case #res4
                                   Constantes()\Type = #CT_Long
                                   
                              Case #res3, #res2, #res1
                                   Select Constantes()\ValeurL
                                        Case 0 To 255
                                             Constantes()\Type = #CT_Byte
                                        Case 256 To 65535
                                             Constantes()\Type = #CT_Word
                                        Default
                                             Constantes()\Type = #CT_Long
                                   EndSelect
                         EndSelect
                         
                    Case CT_String
                         *PointeurDebut + 1
                         Constantes()\ValeurS = PeekS(*PointeurDebut)
                         *PointeurDebut + Len(Constantes()\ValeurS) + 1
                         Constantes()\Type = #CT_String
                         
                    Case #CT_Float_Double ; c'est un flottant double précision
                         *PointeurDebut + 1
                         Constantes()\ValeurD = PeekD(*PointeurDebut)
                         *PointeurDebut + 8
                         Constantes()\Type = #CT_Float_Double
                         
                    Case #CT_Float_Simple_Res3 ; c'est un flottant simple précision
                         *PointeurDebut + 1
                         Constantes()\ValeurF = PeekF(*PointeurDebut)
                         *PointeurDebut + 4
                         Constantes()\Type = #CT_Float_Simple_Res3
                         
                    Case #CT_Byte
                         *PointeurDebut + 1
                         Constantes()\ValeurL = PeekB(*PointeurDebut)
                         *PointeurDebut + 1 ; on arrive sur la nouvelle chaine
                         Constantes()\Type = #CT_Byte
                         
                    Case #CT_Word
                         *PointeurDebut + 1
                         Constantes()\ValeurL = PeekW(*PointeurDebut)
                         *PointeurDebut + 2 ; on arrive sur la nouvelle chaine
                         Constantes()\Type = #CT_Word
                         
                    Case #CT_Quad
                         *PointeurDebut + 1
                         Constantes()\ValeurQ = PeekQ(*PointeurDebut)
                         *PointeurDebut + 8 ; on arrive sur la nouvelle chaine
                         Constantes()\Type = #CT_Quad
               EndSelect
          EndIf
     Wend
     ProcedureReturn * PointeurDebut
EndProcedure


Procedure Extraction_Structure_Interface(ResType.l, *PointeurDebut.l)
     Protected TotalCaracteresToutesStructures.l, *DernierSymbol.l
     Protected NomStructure_Interface.s, TailleStructure_Interface.l, Nb_Elements.l
     Protected TypeStructure_Interface.l, Nom_Element.s, k.l, i.l
     
     ; on commence par des structure ou interface
     ; Le pointeur  *PointeurDebut est sur le 1er caractère du fichier
     ; *PointeurDebut + 20
     TotalCaracteresToutesStructures = PeekL(*PointeurDebut - 4)
     *DernierSymbol = *PointeurDebut + TotalCaracteresToutesStructures - 1
     ; #Res_Structure = 16
     #Res_Interface = 4
     Repeat
          NomStructure_Interface = PeekS(*PointeurDebut)
          ; MessageRequester("",NomStructure_Interface,16)
          *PointeurDebut + Len(NomStructure_Interface) + 1
          TailleStructure_Interface = PeekL(*PointeurDebut)
          Nb_Elements = PeekW(*PointeurDebut + 4)
          *PointeurDebut + 6
          TypeStructure_Interface = PeekB(*PointeurDebut)
          If TypeStructure_Interface & #Res_Interface
               ; c'est une interface
               ;- Debut Interface
               If AddElement(Nom_ListeInterfaces()) = 0
                    Break
               EndIf
               With Nom_ListeInterfaces()
                     \Nom_Interface$ = NomStructure_Interface
                     \FichierOrigine$ = DirectoryEntryName(0)
                     \TailleInterface = 4 * Nb_Elements
                     \Nb_Methodes = Nb_Elements
               EndWith
               
               *PointeurDebut + 9
               
               ClearList(Methode())
               For k = 1 To Nb_Elements
                    If AddElement(Methode()) = 0
                         Break
                    EndIf
                    Methode()\NbParameters = PeekB(*PointeurDebut)
                    *PointeurDebut + 16
               Next k
               
               FirstElement(Methode())
               *PointeurDebut - 8 ; début du nom de la 1ere méthode
               For k = 1 To Nb_Elements
                    AddElement(Interfaces())
                    If Nom_ListeInterfaces()\IndexInterfaceDansListe = 0
                         Nom_ListeInterfaces()\IndexInterfaceDansListe = @Interfaces()
                    EndIf
                    
                    Interfaces()\NomMethode$ = PeekS(*PointeurDebut)
                    *PointeurDebut + Len(Interfaces()\NomMethode$) + 1
                    If Methode()\NbParameters > 0
                         Interfaces()\Nb_Args = Methode()\NbParameters
                         Interfaces()\ArgsMethode = ""
                         For i = 1 To Methode()\NbParameters
                              Select PeekB(*PointeurDebut)
                                   Case 1 ; byte
                                        Interfaces()\ArgsMethode + "b"
                                   Case 3 ; word
                                        Interfaces()\ArgsMethode + "w"
                                   Case 5 ; long
                                        Interfaces()\ArgsMethode + "l"
                                        
                                   Case 8 ; string
                                        Interfaces()\ArgsMethode + "s"
                                   Case 9 ; float
                                        Interfaces()\ArgsMethode + "f"
                                   Case 11 ; char
                                        Interfaces()\ArgsMethode + "c"
                                   Case 12 ; double
                                        Interfaces()\ArgsMethode + "d"
                                   Case 13 ; quad
                                        Interfaces()\ArgsMethode + "q"
                                        
                              EndSelect
                              *PointeurDebut + 1
                         Next i
                    ElseIf Methode()\NbParameters < 0
                         MessageRequester("Erreur", "Methode()\NbParameters < 0  -->" + Str(Methode()\NbParameters), 16)
                    EndIf
                    NextElement(Methode())
               Next k
               
          Else
               ; c'est une structure
               ;- Debut Structures
               If AddElement(Nom_Structure())
                    With Nom_Structure()
                          \Nom_Structure$ = NomStructure_Interface ; stocke le nom de la structure
                          \FichierOrigine$ = DirectoryEntryName(0) ; le nom du fichier res ou est déclarée la structure
                          \TailleStructure = TailleStructure_Interface ; la taille de la structure
                          \Nb_ElementsStructure = Nb_Elements ; le nombre d’éléments de la structure
                    EndWith
                    If ResType = #res1
                         *PointeurDebut + 1
                    EndIf
                    ; lecture de la structure
                    For i = 1 To Nb_Elements
                         If AddElement(Structures()) ; lecture des éléments de la structure
                              If Nom_Structure()\IndexStructureDansListe = 0
                                   Nom_Structure()\IndexStructureDansListe = @Structures()
                              EndIf
                              ; on passe le long qui donne la taille à partir de là jusqu'à
                              ; la fin de la chaîne
                              ; on passe 2 long qui correspondent à (?)
                              ; on arrive sur un long qui donne l'offset de l'élément
                              If ResType = #res1
                                   *PointeurDebut + 6
                              ElseIf ResType = #res2
                                   *PointeurDebut + 6 + 4
                              Else
                                   *PointeurDebut + 10
                              EndIf
                              
                              With Structures()
                              Select PeekB(*PointeurDebut)
                                   Case 1 ; c'est un pointeur
                                        \Type_Variable | #ST_Pointeur
                                        
                                   Default ; ce n'est pas un pointeur
                                        \Type_Variable | #ST_NonPointeur
                              EndSelect
                              
                              *PointeurDebut + 3
                              ; If RES = #res2::EndIf
                              
                              Select ResType
                                   Case #res2
                                        *PointeurDebut - 4
                                        \TailleTableau = PeekW(*PointeurDebut + 10)
                                        \Offset = PeekW(*PointeurDebut + 4) ; déplacement par rapport au début structure
                                        \TailleElement = PeekW(*PointeurDebut + 6) ; Taille de l'élément courant en octets
                                        
                                   Case #res1
                                        \TailleTableau = PeekW(*PointeurDebut + 10)
                                        
                                        \Offset = PeekW(*PointeurDebut + 4) ; déplacement par rapport au début structure
                                        \TailleElement = PeekW(*PointeurDebut + 6) ; Taille de l'élément courant en octets
                                        
                                   Default
                                        \TailleTableau = PeekL(*PointeurDebut + 8)
                                        \Offset = PeekW(*PointeurDebut) ; déplacement par rapport au début structure
                                        \TailleElement = PeekL(*PointeurDebut + 4) ; Taille de l'élément courant en octets
                              EndSelect
                              
                              
                              Select \TailleTableau
                         Case -1
                              \Type_Variable | #ST_Non_tableau
                              ; dans le cas #ST_Non_tableau, \TailleTableau n'est pas utilisé
                              
                         Default
                              \Type_Variable | #ST_tableau
                    EndSelect
                    
                    \Element$ = PeekS(*PointeurDebut + 12) ; l'élément courant
                    *PointeurDebut + Len(\Element$) + 13
                    
                    \Type_Variable$ = PeekS(*PointeurDebut)
                    
                    Select \Type_Variable$
                        Case "b"
                             \Type_Variable | #ST_Byte
                        Case "w"
                             \Type_Variable | #ST_Word
                        Case "l"
                             \Type_Variable | #ST_Long
                        Case "q"
                             \Type_Variable | #ST_Quad
                        Case "f"
                             \Type_Variable | #ST_Float
                        Case "d"
                             \Type_Variable | #ST_Double
                        Case "s"
                             \Type_Variable | #ST_String
                        Case "c"
                             \Type_Variable | #ST_Char
                             ; Default ; le nom de la structure ou interface
                             ; toutes les structures ou interfaces ne sont pas encore chargé, on ne
                             ; peut pas affecter tout de suite le type structure ou interface à
                             ; l'élément , on le fera après la lecture des résidents
                   EndSelect
               *PointeurDebut + Len(\Type_Variable$) + 1 - 1
               EndWith
                         EndIf
               Next i
               *PointeurDebut + 1
               EndIf
          EndIf
     Until *PointeurDebut >= *DernierSymbol
ProcedureReturn * PointeurDebut
EndProcedure


Procedure LectureResident()
      Protected PbConstantFolder$, CheminDir.l, TailleFichier.l
      Protected * ConstantsHeader.l, *SymbolCourant.l, *ConstantsEnd.l, RES.l
      Protected TotalCaracteresToutesStructures.l, *DernierSymbol.l
      Protected NomStructure_Interface.s, TailleStructure_Interface.l, Nb_Elements.l
      Protected TypeStructure_Interface.l, Nom_Element.s
      Protected i.l, k.l, LongueurInfos.l
      Protected Symbole$
      
      
      PbConstantFolder$ = #PB_Compiler_Home + "Residents\"
      If ExamineDirectory(0, PbConstantFolder$, "*.res")
            ClearList(Nom_Structure()) : ClearList(Structures())
            ClearList(Nom_ListeInterfaces()) : ClearList(Interfaces())
            ClearList(Methode()) : ClearList(Constantes())
            chemindir = NextDirectoryEntry(0)
            While chemindir
                  If CheminDir
                  If ReadFile(0, PbConstantFolder$ + DirectoryEntryName(0))
                       TailleFichier = Lof(0)
                       *ConstantsHeader = AllocateMemory(TailleFichier)
                       ReadData(0, *ConstantsHeader, TailleFichier)
                       CloseFile(0)
                       *ConstantsEnd = *ConstantsHeader + TailleFichier
                       *SymbolCourant = *ConstantsHeader
                       If CompareMemory(*SymbolCourant, ?Fichier_Res4, 16)
                            RES = #res4
                       ElseIf CompareMemory(*SymbolCourant, ?Fichier_Res3, 16)
                            RES = #res3
                       ElseIf CompareMemory(*SymbolCourant, ?Fichier_Res2, 16)
                            RES = #res2
                       ElseIf CompareMemory(*SymbolCourant, ?Fichier_Res1, 16)
                            RES = #res1
                       Else
                            RES = 0
                       EndIf
                       
                       If res
                            *SymbolCourant + 20
                            While *SymbolCourant < * ConstantsEnd
                                 If PeekL(*SymbolCourant) = 'CNST' ; c'est les cosntantes seules
                                      *SymbolCourant + 4
                                      *SymbolCourant = ExtractionConstantes(RES, *SymbolCourant)
                                      
                                      ; sinon c'est une constantes ou interface
                                 ElseIf PeekL(*SymbolCourant) = 'RCAM' ; c'est les macro
                                      *SymbolCourant + PeekL(*SymbolCourant + 4) + 8
                                      
                                 ElseIf PeekL(*SymbolCourant) = 'TORP' ; c'est les prototypes
                                      *SymbolCourant + PeekL(*SymbolCourant + 4) + 8
                                      
                                 Else
                                      ; c'est une structure ou interface
                                      *SymbolCourant = Extraction_Structure_Interface(RES, *SymbolCourant)
                                 EndIf
                            Wend
                       EndIf
                  Else
                       MessageRequester("Erreur", "Le fichier " + DirectoryEntryName(0) + " n'est pas au format resident PureBasic", 16)
                  EndIf
                  EndIf
                  FreeMemory(*ConstantsHeader)
                  
                  
                  CheminDir = NextDirectoryEntry(0)
            Wend
            FinishDirectory(0)
       EndIf
            
       ; Tri des interfaces
       Nb_Interfaces = CountList(Nom_ListeInterfaces())
       If Nb_Interfaces > 0
            SortStructuredList(Nom_ListeInterfaces(), 2, OffsetOf(Nom_ListeInterfaces\Nom_Interface$), #PB_Sort_String)
       Else
            Nb_Interfaces = 0
       EndIf
            
       ; Tri des structures
       Nb_Structures = CountList(Nom_Structure())
       If Nb_Structures > 0
            SortStructuredList(Nom_Structure(), 2, 0, #PB_Sort_String)
       Else
            Nb_Structures = 0
       EndIf
            
       ; Tri des constantes
       Nb_Constantes = CountList(Constantes())
       If Nb_Constantes > 0
            SortStructuredList(Constantes(), 2, OffsetOf(Constante\Nom_Constante$), #PB_Sort_String)
       Else
            Nb_Constantes = 0
       EndIf
      ClearList(Methode())
EndProcedure


DataSection
      Fichier_Res4 :
      Data .b $45, $52, $55, $50, $00, $00, $00, $00, $34, $53, $45, $52, $54, $43, $52, $53
      
      Fichier_Res3 :
      Data .b $45, $52, $55, $50, $00, $00, $00, $00, $33, $53, $45, $52, $54, $43, $52, $53
      
      Fichier_Res2 :
      Data .b $45, $52, $55, $50, $00, $00, $00, $00, $32, $53, $45, $52, $54, $43, $52, $53
      
      Fichier_Res1 :
      Data .b $45, $52, $55, $50, $00, $00, $00, $00, $31, $53, $45, $52, $54, $43, $52, $53
EndDataSection

Posted: Tue Aug 29, 2006 9:27 pm
by Hroudtwolf
Hey, Thank you very much :-)