1## @file
2# process FFS generation from FILE statement
3#
4#  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5#
6#  SPDX-License-Identifier: BSD-2-Clause-Patent
7#
8
9##
10# Import Modules
11#
12from __future__ import absolute_import
13from io import BytesIO
14from struct import pack
15from CommonDataClass.FdfClass import FileStatementClassObject
16from Common import EdkLogger
17from Common.BuildToolError import GENFDS_ERROR
18from Common.Misc import GuidStructureByteArrayToGuidString, SaveFileOnChange
19import Common.LongFilePathOs as os
20from .GuidSection import GuidSection
21from .FvImageSection import FvImageSection
22from .Ffs import FdfFvFileTypeToFileType
23from .GenFdsGlobalVariable import GenFdsGlobalVariable
24import shutil
25
26## generate FFS from FILE
27#
28#
29class FileStatement (FileStatementClassObject):
30    ## The constructor
31    #
32    #   @param  self        The object pointer
33    #
34    def __init__(self):
35        FileStatementClassObject.__init__(self)
36        self.CurrentLineNum = None
37        self.CurrentLineContent = None
38        self.FileName = None
39        self.InfFileName = None
40        self.SubAlignment = None
41
42    ## GenFfs() method
43    #
44    #   Generate FFS
45    #
46    #   @param  self         The object pointer
47    #   @param  Dict         dictionary contains macro and value pair
48    #   @param  FvChildAddr  Array of the inside FvImage base address
49    #   @param  FvParentAddr Parent Fv base address
50    #   @retval string       Generated FFS file name
51    #
52    def GenFfs(self, Dict = None, FvChildAddr=[], FvParentAddr=None, IsMakefile=False, FvName=None):
53
54        if self.NameGuid and self.NameGuid.startswith('PCD('):
55            PcdValue = GenFdsGlobalVariable.GetPcdValue(self.NameGuid)
56            if len(PcdValue) == 0:
57                EdkLogger.error("GenFds", GENFDS_ERROR, '%s NOT defined.' \
58                            % (self.NameGuid))
59            if PcdValue.startswith('{'):
60                PcdValue = GuidStructureByteArrayToGuidString(PcdValue)
61            RegistryGuidStr = PcdValue
62            if len(RegistryGuidStr) == 0:
63                EdkLogger.error("GenFds", GENFDS_ERROR, 'GUID value for %s in wrong format.' \
64                            % (self.NameGuid))
65            self.NameGuid = RegistryGuidStr
66
67        Str = self.NameGuid
68        if FvName:
69            Str += FvName
70        OutputDir = os.path.join(GenFdsGlobalVariable.FfsDir, Str)
71        if os.path.exists(OutputDir):
72            shutil.rmtree(OutputDir)
73        if not os.path.exists(OutputDir):
74            os.makedirs(OutputDir)
75
76        if Dict is None:
77            Dict = {}
78
79        Dict.update(self.DefineVarDict)
80        SectionAlignments = None
81        if self.FvName:
82            Buffer = BytesIO()
83            if self.FvName.upper() not in GenFdsGlobalVariable.FdfParser.Profile.FvDict:
84                EdkLogger.error("GenFds", GENFDS_ERROR, "FV (%s) is NOT described in FDF file!" % (self.FvName))
85            Fv = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(self.FvName.upper())
86            FileName = Fv.AddToBuffer(Buffer)
87            SectionFiles = [FileName]
88
89        elif self.FdName:
90            if self.FdName.upper() not in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
91                EdkLogger.error("GenFds", GENFDS_ERROR, "FD (%s) is NOT described in FDF file!" % (self.FdName))
92            Fd = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(self.FdName.upper())
93            FileName = Fd.GenFd()
94            SectionFiles = [FileName]
95
96        elif self.FileName:
97            if hasattr(self, 'FvFileType') and self.FvFileType == 'RAW':
98                if isinstance(self.FileName, list) and isinstance(self.SubAlignment, list) and len(self.FileName) == len(self.SubAlignment):
99                    FileContent = BytesIO()
100                    MaxAlignIndex = 0
101                    MaxAlignValue = 1
102                    for Index, File in enumerate(self.FileName):
103                        try:
104                            f = open(File, 'rb')
105                        except:
106                            GenFdsGlobalVariable.ErrorLogger("Error opening RAW file %s." % (File))
107                        Content = f.read()
108                        f.close()
109                        AlignValue = 1
110                        if self.SubAlignment[Index]:
111                            AlignValue = GenFdsGlobalVariable.GetAlignment(self.SubAlignment[Index])
112                        if AlignValue > MaxAlignValue:
113                            MaxAlignIndex = Index
114                            MaxAlignValue = AlignValue
115                        FileContent.write(Content)
116                        if len(FileContent.getvalue()) % AlignValue != 0:
117                            Size = AlignValue - len(FileContent.getvalue()) % AlignValue
118                            for i in range(0, Size):
119                                FileContent.write(pack('B', 0xFF))
120
121                    if FileContent.getvalue() != b'':
122                        OutputRAWFile = os.path.join(GenFdsGlobalVariable.FfsDir, self.NameGuid, self.NameGuid + '.raw')
123                        SaveFileOnChange(OutputRAWFile, FileContent.getvalue(), True)
124                        self.FileName = OutputRAWFile
125                        self.SubAlignment = self.SubAlignment[MaxAlignIndex]
126
127                if self.Alignment and self.SubAlignment:
128                    if GenFdsGlobalVariable.GetAlignment (self.Alignment) < GenFdsGlobalVariable.GetAlignment (self.SubAlignment):
129                        self.Alignment = self.SubAlignment
130                elif self.SubAlignment:
131                    self.Alignment = self.SubAlignment
132
133            self.FileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FileName)
134            #Replace $(SAPCE) with real space
135            self.FileName = self.FileName.replace('$(SPACE)', ' ')
136            SectionFiles = [GenFdsGlobalVariable.MacroExtend(self.FileName, Dict)]
137
138        else:
139            SectionFiles = []
140            Index = 0
141            SectionAlignments = []
142            for section in self.SectionList:
143                Index = Index + 1
144                SecIndex = '%d' %Index
145                # process the inside FvImage from FvSection or GuidSection
146                if FvChildAddr != []:
147                    if isinstance(section, FvImageSection):
148                        section.FvAddr = FvChildAddr.pop(0)
149                    elif isinstance(section, GuidSection):
150                        section.FvAddr = FvChildAddr
151                if FvParentAddr and isinstance(section, GuidSection):
152                    section.FvParentAddr = FvParentAddr
153
154                if self.KeepReloc == False:
155                    section.KeepReloc = False
156                sectList, align = section.GenSection(OutputDir, self.NameGuid, SecIndex, self.KeyStringList, None, Dict)
157                if sectList != []:
158                    for sect in sectList:
159                        SectionFiles.append(sect)
160                        SectionAlignments.append(align)
161
162        #
163        # Prepare the parameter
164        #
165        FfsFileOutput = os.path.join(OutputDir, self.NameGuid + '.ffs')
166        GenFdsGlobalVariable.GenerateFfs(FfsFileOutput, SectionFiles,
167                                         FdfFvFileTypeToFileType.get(self.FvFileType),
168                                         self.NameGuid,
169                                         Fixed=self.Fixed,
170                                         CheckSum=self.CheckSum,
171                                         Align=self.Alignment,
172                                         SectionAlign=SectionAlignments
173                                        )
174
175        return FfsFileOutput
176