Removed the unnecessary extra conversion of "\r\n".
[people/mcb30/basetools.git] / Source / Python / AutoGen / UniClassObject.py
1 # Copyright (c) 2007, Intel Corporation\r
2 # All rights reserved. This program and the accompanying materials\r
3 # are licensed and made available under the terms and conditions of the BSD License\r
4 # which accompanies this distribution.  The full text of the license may be found at\r
5 # http://opensource.org/licenses/bsd-license.php\r
6 #\r
7 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
8 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
9 \r
10 #\r
11 #This file is used to collect all defined strings in multiple uni files\r
12 #\r
13 \r
14 ##\r
15 # Import Modules\r
16 #\r
17 import os, codecs, re\r
18 import Common.EdkLogger as EdkLogger\r
19 from Common.BuildToolError import *\r
20 \r
21 ##\r
22 # Static definitions\r
23 #\r
24 UNICODE_WIDE_CHAR = u'\\wide'\r
25 UNICODE_NARROW_CHAR = u'\\narrow'\r
26 UNICODE_NON_BREAKING_CHAR = u'\\nbr'\r
27 UNICODE_UNICODE_CR = '\r'\r
28 UNICODE_UNICODE_LF = '\n'\r
29 \r
30 NARROW_CHAR = u'\uFFF0'\r
31 WIDE_CHAR = u'\uFFF1'\r
32 NON_BREAKING_CHAR = u'\uFFF2'\r
33 CR = u'\u000D'\r
34 LF = u'\u000A'\r
35 NULL = u'\u0000'\r
36 TAB = u'\t'\r
37 BACK_SPLASH = u'\\'\r
38 \r
39 gIncludePattern = re.compile("^#include +[\"<]+([^\"< >]+)[>\"]+$", re.MULTILINE | re.UNICODE)\r
40 \r
41 ## Convert a python unicode string to a normal string\r
42 #\r
43 # Convert a python unicode string to a normal string\r
44 # UniToStr(u'I am a string') is 'I am a string'\r
45 #\r
46 # @param Uni:  The python unicode string\r
47 #\r
48 # @retval:     The formatted normal string \r
49 #\r
50 def UniToStr(Uni):\r
51     return repr(Uni)[2:-1]\r
52 \r
53 ## Convert a unicode string to a Hex list\r
54 #\r
55 # Convert a unicode string to a Hex list\r
56 # UniToHexList('ABC') is ['0x41', '0x00', '0x42', '0x00', '0x43', '0x00']\r
57 #\r
58 # @param Uni:    The python unicode string\r
59 #\r
60 # @retval List:  The formatted hex list \r
61 #\r
62 def UniToHexList(Uni):\r
63     List = []\r
64     for Item in Uni:\r
65         Temp = '%04X' % ord(Item)\r
66         List.append('0x' + Temp[2:4])\r
67         List.append('0x' + Temp[0:2])\r
68     return List\r
69 \r
70 ## ConvertISO639ToRFC3066\r
71 #\r
72 # Convert a ISO639 language name to RFC3066\r
73 #\r
74 # @param LangName:   LangName in ISO639\r
75 #\r
76 # @retval LangName:  LangName in RFC3066\r
77 #\r
78 def ConvertISO639ToRFC3066(LangName):\r
79     if LangName == 'eng':\r
80         LangName = 'en-US'\r
81     if LangName == 'fra':\r
82         LangName = 'fr-FR'\r
83     if LangName == 'spa':\r
84         LangName = 'es-ES'\r
85         \r
86     return LangName\r
87 \r
88 ## StringDefClassObject\r
89 #\r
90 # A structure for language definition\r
91 #\r
92 class StringDefClassObject(object):\r
93     def __init__(self, Name = None, Value = None, Referenced = False, Token = None, UseOtherLangDef = ''):\r
94         self.StringName = ''\r
95         self.StringNameByteList = []\r
96         self.StringValue = ''\r
97         self.StringValueByteList = ''\r
98         self.Token = 0\r
99         self.Referenced = Referenced\r
100         self.UseOtherLangDef = UseOtherLangDef\r
101         self.Length = 0\r
102 \r
103         if Name != None:\r
104             self.StringName = Name\r
105             self.StringNameByteList = UniToHexList(Name)\r
106         if Value != None:\r
107             self.StringValue = Value + u'\x00'        # Add a NULL at string tail\r
108             self.StringValueByteList = UniToHexList(self.StringValue)\r
109             self.Length = len(self.StringValueByteList)\r
110         if Token != None:\r
111             self.Token = Token\r
112 \r
113     def __str__(self):\r
114         return repr(self.StringName) + ' ' + \\r
115                repr(self.Token) + ' ' + \\r
116                repr(self.Referenced) + ' ' + \\r
117                repr(self.StringValue) + ' ' + \\r
118                repr(self.UseOtherLangDef)\r
119 \r
120 ## UniFileClassObject\r
121 #\r
122 # A structure for .uni file definition\r
123 #\r
124 class UniFileClassObject(object):\r
125     def __init__(self, FileList = []):\r
126         self.FileList = FileList\r
127         self.Token = 2\r
128         self.LanguageDef = []                   #[ [u'LanguageIdentifier', u'PrintableName'], ... ]\r
129         self.OrderedStringList = {}             #{ u'LanguageIdentifier' : [StringDefClassObject]  }\r
130 \r
131         if len(self.FileList) > 0:\r
132             self.LoadUniFiles(FileList)\r
133 \r
134     #\r
135     # Get Language definition\r
136     #\r
137     def GetLangDef(self, Line):\r
138         Lang = Line.split()\r
139         if len(Lang) != 3:\r
140             EdkLogger.error("Unicode File Parser", PARSER_ERROR, "Wrong language definition",\r
141                             ExtraData="""%s\n\t*Correct format is '#langdef eng "English"'""" % Line)\r
142         else:\r
143             LangName = ConvertISO639ToRFC3066(Lang[1])\r
144             LangPrintName = Lang[2][1:-1]\r
145         \r
146         IsLangInDef = False\r
147         for Item in self.LanguageDef:\r
148             if Item[0] == LangName:\r
149                 IsLangInDef = True\r
150                 break;\r
151         \r
152         if not IsLangInDef:\r
153             self.LanguageDef.append([LangName, LangPrintName])\r
154 \r
155         #\r
156         # Add language string\r
157         #\r
158         self.AddStringToList(u'$LANGUAGE_NAME', LangName, LangName, 0, True)\r
159         self.AddStringToList(u'$PRINTABLE_LANGUAGE_NAME', LangName, LangPrintName, 1, True)\r
160 \r
161         return True\r
162 \r
163     #\r
164     # Get String name and value\r
165     #\r
166     def GetStringObject(self, Item):\r
167         Name = ''\r
168         Language = ''\r
169         Value = ''\r
170 \r
171         Name = Item.split()[1]\r
172         LanguageList = Item.split(u'#language ')\r
173         for IndexI in range(len(LanguageList)):\r
174             if IndexI == 0:\r
175                 continue\r
176             else:\r
177                 Language = LanguageList[IndexI].split()[0]\r
178                 Value = LanguageList[IndexI][LanguageList[IndexI].find(u'\"') + len(u'\"') : LanguageList[IndexI].rfind(u'\"')] #.replace(u'\r\n', u'')\r
179                 self.AddStringToList(Name, Language, Value)\r
180     \r
181     #\r
182     # Get include file list and load them\r
183     #\r
184     def GetIncludeFile(self, Item, Dir):\r
185         FileName = Item[Item.find(u'#include ') + len(u'#include ') :Item.find(u' ', len(u'#include '))][1:-1]\r
186         self.LoadUniFile(FileName)\r
187 \r
188     #\r
189     # Pre-process before parse .uni file\r
190     #\r
191     def PreProcess(self, File):\r
192         if not os.path.exists(File) or not os.path.isfile(File):\r
193             EdkLogger.error("Unicode File Parser", FILE_NOT_FOUND, ExtraData=File)\r
194 \r
195         Dir = os.path.dirname(File)\r
196         FileIn = codecs.open(File, mode='rb', encoding='utf-16').readlines()\r
197         Lines = []\r
198         #\r
199         # Use unique identifier\r
200         #\r
201         for Line in FileIn:\r
202             Line = Line.strip()\r
203             #\r
204             # Ignore comment line and empty line\r
205             #\r
206             if Line == u'' or Line.startswith(u'//'):\r
207                 continue\r
208             Line = Line.replace(u'/langdef', u'#langdef')\r
209             Line = Line.replace(u'/string', u'#string')\r
210             Line = Line.replace(u'/language', u'#language')\r
211             Line = Line.replace(u'/include', u'#include')\r
212 \r
213             Line = Line.replace(UNICODE_WIDE_CHAR, WIDE_CHAR)\r
214             Line = Line.replace(UNICODE_NARROW_CHAR, NARROW_CHAR)\r
215             Line = Line.replace(UNICODE_NON_BREAKING_CHAR, NON_BREAKING_CHAR)\r
216             Line = Line.replace(u'\\r\\n', CR + LF)\r
217             Line = Line.replace(u'\\n', CR + LF)\r
218             Line = Line.replace(u'\\r', CR)\r
219             Line = Line.replace(u'\\t', u'\t')\r
220             Line = Line.replace(u'\\\\', u'\\')\r
221             Line = Line.replace(u'''\"''', u'''"''')\r
222             Line = Line.replace(u'\t', u' ')\r
223 #           if Line.find(u'\\x'):\r
224 #               hex = Line[Line.find(u'\\x') + 2 : Line.find(u'\\x') + 6]\r
225 #               hex = "u'\\u" + hex + "'"\r
226 \r
227             IncList = gIncludePattern.findall(Line)\r
228             if len(IncList) == 1:\r
229                 Lines.extend(self.PreProcess(os.path.join(Dir, IncList[0])))\r
230                 continue\r
231 \r
232             Lines.append(Line)\r
233 \r
234         return Lines\r
235 \r
236     #\r
237     # Load a .uni file\r
238     #\r
239     def LoadUniFile(self, File = None):\r
240         if File == None:\r
241             EdkLogger.error("Unicode File Parser", PARSER_ERROR, 'No unicode file is given')\r
242         #\r
243         # Process special char in file\r
244         #\r
245         Lines = self.PreProcess(File)\r
246 \r
247         #\r
248         # Get Unicode Information\r
249         #\r
250         for IndexI in range(len(Lines)):\r
251             Line = Lines[IndexI]\r
252             if (IndexI + 1) < len(Lines):\r
253                 SecondLine = Lines[IndexI + 1]\r
254             if (IndexI + 2) < len(Lines):\r
255                 ThirdLine = Lines[IndexI + 2]\r
256 \r
257             #\r
258             # Get Language def information\r
259             #\r
260             if Line.find(u'#langdef ') >= 0:\r
261                 self.GetLangDef(Line)\r
262                 continue\r
263 \r
264             Name = ''\r
265             Language = ''\r
266             Value = ''\r
267             #\r
268             # Get string def information format 1 as below\r
269             #\r
270             #     #string MY_STRING_1\r
271             #     #language eng\r
272             #     My first English string line 1\r
273             #     My first English string line 2\r
274             #     #string MY_STRING_1\r
275             #     #language spa\r
276             #     Mi segunda secuencia 1\r
277             #     Mi segunda secuencia 2\r
278             #\r
279             if Line.find(u'#string ') >= 0 and Line.find(u'#language ') < 0 and \\r
280                 SecondLine.find(u'#string ') < 0 and SecondLine.find(u'#language ') >= 0 and \\r
281                 ThirdLine.find(u'#string ') < 0 and ThirdLine.find(u'#language ') < 0:\r
282                 Name = Line[Line.find(u'#string ') + len(u'#string ') : ].strip(' ')\r
283                 Language = SecondLine[SecondLine.find(u'#language ') + len(u'#language ') : ].strip(' ')\r
284                 for IndexJ in range(IndexI + 2, len(Lines)):\r
285                     if Lines[IndexJ].find(u'#string ') < 0 and Lines[IndexJ].find(u'#language ') < 0:\r
286                         Value = Value + Lines[IndexJ]\r
287                     else:\r
288                         IndexI = IndexJ\r
289                         break\r
290                 # Value = Value.replace(u'\r\n', u'')\r
291                 self.AddStringToList(Name, Language, Value)\r
292                 continue\r
293 \r
294             #\r
295             # Get string def information format 2 as below\r
296             #\r
297             #     #string MY_STRING_1     #language eng     "My first English string line 1"\r
298             #                                               "My first English string line 2"\r
299             #                             #language spa     "Mi segunda secuencia 1"\r
300             #                                               "Mi segunda secuencia 2"\r
301             #     #string MY_STRING_2     #language eng     "My first English string line 1"\r
302             #                                               "My first English string line 2"\r
303             #     #string MY_STRING_2     #language spa     "Mi segunda secuencia 1"\r
304             #                                               "Mi segunda secuencia 2"\r
305             #\r
306             if Line.find(u'#string ') >= 0 and Line.find(u'#language ') >= 0:\r
307                 StringItem = Line\r
308                 for IndexJ in range(IndexI + 1, len(Lines)):\r
309                     if Lines[IndexJ].find(u'#string ') >= 0 and Lines[IndexJ].find(u'#language ') >= 0:\r
310                         IndexI = IndexJ\r
311                         break\r
312                     elif Lines[IndexJ].find(u'#string ') < 0 and Lines[IndexJ].find(u'#language ') >= 0:\r
313                         StringItem = StringItem + Lines[IndexJ]\r
314                     elif Lines[IndexJ].find(u'\"') >= 2:\r
315                         StringItem = StringItem[ : StringItem.rfind(u'\"')] + Lines[IndexJ][Lines[IndexJ].find(u'\"') + len(u'\"') : ]\r
316                 self.GetStringObject(StringItem)\r
317 \r
318     #\r
319     # Load multiple .uni files\r
320     #\r
321     def LoadUniFiles(self, FileList = []):\r
322         if len(FileList) > 0:\r
323             for File in FileList:\r
324                 self.LoadUniFile(File)\r
325 \r
326     #\r
327     # Add a string to list\r
328     #\r
329     def AddStringToList(self, Name, Language, Value, Token = None, Referenced = False, UseOtherLangDef = '', Index = -1):\r
330         Language = ConvertISO639ToRFC3066(Language)\r
331         if Language not in self.OrderedStringList:\r
332             self.OrderedStringList[Language] = []\r
333 \r
334         IsAdded = False\r
335         for Item in self.OrderedStringList[Language]:\r
336             if Name == Item.StringName:\r
337                 IsAdded = True\r
338                 break\r
339         if not IsAdded:\r
340             Token = len(self.OrderedStringList[Language])\r
341             if Index == -1:\r
342                 self.OrderedStringList[Language].append(StringDefClassObject(Name, Value, Referenced, Token, UseOtherLangDef))\r
343             else:\r
344                 self.OrderedStringList[Language].insert(Index, StringDefClassObject(Name, Value, Referenced, Token, UseOtherLangDef))\r
345                 \r
346     #\r
347     # Set the string as referenced\r
348     #\r
349     def SetStringReferenced(self, Name):\r
350         for Lang in self.OrderedStringList:\r
351             for Item in self.OrderedStringList[Lang]:\r
352                 if Name == Item.StringName:\r
353                     Item.Referenced = True\r
354                     break\r
355     #\r
356     # Search the string in language definition by Name\r
357     #\r
358     def FindStringValue(self, Name, Lang):\r
359         for Item in self.OrderedStringList[Lang]:\r
360             if Item.StringName == Name:\r
361                 return Item\r
362 \r
363         return None\r
364     \r
365     #\r
366     # Search the string in language definition by Token\r
367     #\r
368     def FindByToken(self, Token, Lang):\r
369         for Item in self.OrderedStringList[Lang]:\r
370             if Item.Token == Token:\r
371                 return Item\r
372 \r
373         return None\r
374 \r
375     #\r
376     # Re-order strings and re-generate tokens\r
377     #\r
378     def ReToken(self):\r
379         #\r
380         # Search each string to find if it is defined for each language\r
381         # Use secondary language value to replace if missing in any one language\r
382         #\r
383         for IndexI in range(0, len(self.LanguageDef)):\r
384             LangKey = self.LanguageDef[IndexI][0]\r
385             for Item in self.OrderedStringList[LangKey]:\r
386                 Name = Item.StringName\r
387                 Value = Item.StringValue[0:-1]\r
388                 Referenced = Item.Referenced\r
389                 Index = self.OrderedStringList[LangKey].index(Item)\r
390                 for IndexJ in range(0, len(self.LanguageDef)):\r
391                     LangFind = self.LanguageDef[IndexJ][0]\r
392                     if self.FindStringValue(Name, LangFind) == None:\r
393                         EdkLogger.debug(EdkLogger.DEBUG_5, Name)\r
394                         Token = len(self.OrderedStringList[LangFind])\r
395                         self.AddStringToList(Name, LangFind, Value, Token, Referenced, LangKey, Index)\r
396 \r
397         #\r
398         # Retoken\r
399         #\r
400         # First re-token the first language\r
401         LangName = self.LanguageDef[0][0]\r
402         ReferencedStringList = []\r
403         NotReferencedStringList = []\r
404         Token = 0\r
405         for Item in self.OrderedStringList[LangName]:\r
406             if Item.Referenced == True:\r
407                 Item.Token = Token\r
408                 ReferencedStringList.append(Item)\r
409                 Token = Token + 1\r
410             else:\r
411                 NotReferencedStringList.append(Item)\r
412         self.OrderedStringList[LangName] = ReferencedStringList\r
413         for Index in range(len(NotReferencedStringList)):\r
414             NotReferencedStringList[Index].Token = Token + Index\r
415             self.OrderedStringList[LangName].append(NotReferencedStringList[Index])\r
416             \r
417         #\r
418         # Adjust the orders of other languages\r
419         #\r
420         for IndexOfLanguage in range(1, len(self.LanguageDef)):\r
421             for OrderedString in self.OrderedStringList[LangName]:\r
422                 for UnOrderedString in self.OrderedStringList[self.LanguageDef[IndexOfLanguage][0]]:\r
423                     if OrderedString.StringName == UnOrderedString.StringName:\r
424                         UnOrderedString.Token = OrderedString.Token\r
425                         break\r
426 \r
427     #\r
428     # Show the instance itself\r
429     #\r
430     def ShowMe(self):\r
431         print self.LanguageDef\r
432         #print self.OrderedStringList\r
433         for Item in self.OrderedStringList:\r
434             print Item\r
435             for Member in self.OrderedStringList[Item]:\r
436                 print str(Member)\r
437 \r
438 # This acts like the main() function for the script, unless it is 'import'ed into another\r
439 # script.\r
440 if __name__ == '__main__':\r
441     EdkLogger.SetLevel(EdkLogger.DEBUG_0)\r
442     a = UniFileClassObject(['C:\\Edk\\Strings.uni', 'C:\\Edk\\Strings2.uni'])\r
443     a.ReToken()\r
444     a.ShowMe()\r