1/** @file
2Calculate Crc32 value and Verify Crc32 value for input data.
3
4Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19#include "ParseInf.h"
20#include "EfiUtilityMsgs.h"
21#include "CommonLib.h"
22#include "Crc32.h"
23
24#define UTILITY_NAME            "GenCrc32"
25#define UTILITY_MAJOR_VERSION   0
26#define UTILITY_MINOR_VERSION   2
27
28#define CRC32_NULL              0
29#define CRC32_ENCODE            1
30#define CRC32_DECODE            2
31
32VOID
33Version (
34  VOID
35  )
36/*++
37
38Routine Description:
39
40  Displays the standard utility information to SDTOUT
41
42Arguments:
43
44  None
45
46Returns:
47
48  None
49
50--*/
51{
52  fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
53}
54
55VOID
56Usage (
57  VOID
58  )
59/*++
60
61Routine Description:
62
63  Displays the utility usage syntax to STDOUT
64
65Arguments:
66
67  None
68
69Returns:
70
71  None
72
73--*/
74{
75  //
76  // Summary usage
77  //
78  fprintf (stdout, "Usage: GenCrc32 -e|-d [options] <input_file>\n\n");
79
80  //
81  // Copyright declaration
82  //
83  fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");
84
85  //
86  // Details Option
87  //
88  fprintf (stdout, "optional arguments:\n");
89  fprintf (stdout, "  -h, --help            Show this help message and exit\n");
90  fprintf (stdout, "  --version             Show program's version number and exit\n");
91  fprintf (stdout, "  --debug [DEBUG]       Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\
92                        - 9 (max)\n");
93  fprintf (stdout, "  -v, --verbose         Print informational statements\n");
94  fprintf (stdout, "  -q, --quiet           Returns the exit code, error messages will be\n\
95                        displayed\n");
96  fprintf (stdout, "  -s, --silent          Returns only the exit code; informational and error\n\
97                        messages are not displayed\n");
98  fprintf (stdout, "  -e, --encode          Calculate CRC32 value for the input file\n");
99  fprintf (stdout, "  -d, --decode          Verify CRC32 value for the input file\n");
100  fprintf (stdout, "  -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\
101                        Output file name\n");
102  fprintf (stdout, "  --sfo                 Reserved for future use\n");
103
104}
105
106int
107main (
108  int   argc,
109  CHAR8 *argv[]
110  )
111/*++
112
113Routine Description:
114
115  Main function.
116
117Arguments:
118
119  argc - Number of command line parameters.
120  argv - Array of pointers to parameter strings.
121
122Returns:
123  STATUS_SUCCESS - Utility exits successfully.
124  STATUS_ERROR   - Some error occurred during execution.
125
126--*/
127{
128  EFI_STATUS              Status;
129  CHAR8                   *OutputFileName;
130  CHAR8                   *InputFileName;
131  UINT8                   *FileBuffer;
132  UINT32                  FileSize;
133  UINT64                  LogLevel;
134  UINT8                   FileAction;
135  UINT32                  Crc32Value;
136  FILE                    *InFile;
137  FILE                    *OutFile;
138
139  //
140  // Init local variables
141  //
142  LogLevel       = 0;
143  Status         = EFI_SUCCESS;
144  InputFileName  = NULL;
145  OutputFileName = NULL;
146  FileAction     = CRC32_NULL;
147  InFile         = NULL;
148  OutFile        = NULL;
149  Crc32Value     = 0;
150  FileBuffer     = NULL;
151
152  SetUtilityName (UTILITY_NAME);
153
154  if (argc == 1) {
155    Error (NULL, 0, 1001, "Missing options", "no options input");
156    Usage ();
157    return STATUS_ERROR;
158  }
159
160  //
161  // Parse command line
162  //
163  argc --;
164  argv ++;
165
166  if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
167    Usage ();
168    return STATUS_SUCCESS;
169  }
170
171  if (stricmp (argv[0], "--version") == 0) {
172    Version ();
173    return STATUS_SUCCESS;
174  }
175
176  while (argc > 0) {
177    if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
178      if (argv[1] == NULL || argv[1][0] == '-') {
179        Error (NULL, 0, 1003, "Invalid option value", "Output File name is missing for -o option");
180        goto Finish;
181      }
182      OutputFileName = argv[1];
183      argc -= 2;
184      argv += 2;
185      continue;
186    }
187
188    if ((stricmp (argv[0], "-e") == 0) || (stricmp (argv[0], "--encode") == 0)) {
189      FileAction     = CRC32_ENCODE;
190      argc --;
191      argv ++;
192      continue;
193    }
194
195    if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--decode") == 0)) {
196      FileAction     = CRC32_DECODE;
197      argc --;
198      argv ++;
199      continue;
200    }
201
202    if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
203      SetPrintLevel (VERBOSE_LOG_LEVEL);
204      VerboseMsg ("Verbose output Mode Set!");
205      argc --;
206      argv ++;
207      continue;
208    }
209
210    if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
211      SetPrintLevel (KEY_LOG_LEVEL);
212      KeyMsg ("Quiet output Mode Set!");
213      argc --;
214      argv ++;
215      continue;
216    }
217
218    if (stricmp (argv[0], "--debug") == 0) {
219      Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
220      if (EFI_ERROR (Status)) {
221        Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
222        goto Finish;
223      }
224      if (LogLevel > 9) {
225        Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel);
226        goto Finish;
227      }
228      SetPrintLevel (LogLevel);
229      DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
230      argc -= 2;
231      argv += 2;
232      continue;
233    }
234
235    if (argv[0][0] == '-') {
236      Error (NULL, 0, 1000, "Unknown option", argv[0]);
237      goto Finish;
238    }
239
240    //
241    // Get Input file file name.
242    //
243    InputFileName = argv[0];
244    argc --;
245    argv ++;
246  }
247
248  VerboseMsg ("%s tool start.", UTILITY_NAME);
249
250  //
251  // Check Input parameters
252  //
253  if (FileAction == CRC32_NULL) {
254    Error (NULL, 0, 1001, "Missing option", "either the encode or the decode option must be specified!");
255    return STATUS_ERROR;
256  } else if (FileAction == CRC32_ENCODE) {
257    VerboseMsg ("File will be encoded by Crc32");
258  } else if (FileAction == CRC32_DECODE) {
259    VerboseMsg ("File will be decoded by Crc32");
260  }
261
262  if (InputFileName == NULL) {
263    Error (NULL, 0, 1001, "Missing option", "Input files are not specified");
264    goto Finish;
265  } else {
266    VerboseMsg ("Input file name is %s", InputFileName);
267  }
268
269  if (OutputFileName == NULL) {
270    Error (NULL, 0, 1001, "Missing option", "Output file are not specified");
271    goto Finish;
272  } else {
273    VerboseMsg ("Output file name is %s", OutputFileName);
274  }
275
276  //
277  // Open Input file and read file data.
278  //
279  InFile = fopen (LongFilePath (InputFileName), "rb");
280  if (InFile == NULL) {
281    Error (NULL, 0, 0001, "Error opening file", InputFileName);
282    return STATUS_ERROR;
283  }
284
285  fseek (InFile, 0, SEEK_END);
286  FileSize = ftell (InFile);
287  fseek (InFile, 0, SEEK_SET);
288
289  FileBuffer = (UINT8 *) malloc (FileSize);
290  if (FileBuffer == NULL) {
291    Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated!");
292    fclose (InFile);
293    goto Finish;
294  }
295
296  fread (FileBuffer, 1, FileSize, InFile);
297  fclose (InFile);
298  VerboseMsg ("the size of the input file is %u bytes", (unsigned) FileSize);
299
300  //
301  // Open output file
302  //
303  OutFile = fopen (LongFilePath (OutputFileName), "wb");
304  if (OutFile == NULL) {
305    Error (NULL, 0, 0001, "Error opening file", OutputFileName);
306    goto Finish;
307  }
308
309  //
310  // Calculate Crc32 value
311  //
312  if (FileAction == CRC32_ENCODE) {
313    Status = CalculateCrc32 (FileBuffer, FileSize, &Crc32Value);
314    if (Status != EFI_SUCCESS) {
315      Error (NULL, 0, 3000, "Invalid", "Calculate CRC32 value failed!");
316      goto Finish;
317    }
318    //
319    // Done, write output file.
320    //
321    fwrite (&Crc32Value, 1, sizeof (Crc32Value), OutFile);
322    VerboseMsg ("The calculated CRC32 value is 0x%08x", (unsigned) Crc32Value);
323    fwrite (FileBuffer, 1, FileSize, OutFile);
324    VerboseMsg ("the size of the encoded file is %u bytes", (unsigned) FileSize + sizeof (UINT32));
325  } else {
326    //
327    // Verify Crc32 Value
328    //
329    Status = CalculateCrc32 (FileBuffer + sizeof (UINT32), FileSize - sizeof (UINT32), &Crc32Value);
330    if (Status != EFI_SUCCESS) {
331      Error (NULL, 0, 3000, "Invalid", "Calculate CRC32 value failed!");
332      goto Finish;
333    }
334    VerboseMsg ("The calculated CRC32 value is 0x%08x and File Crc32 value is 0x%08x", (unsigned) Crc32Value, (unsigned) (*(UINT32 *)FileBuffer));
335    if (Crc32Value != *(UINT32 *)FileBuffer) {
336      Error (NULL, 0, 3000, "Invalid", "CRC32 value of input file is not correct!");
337      Status = STATUS_ERROR;
338      goto Finish;
339    }
340    //
341    // Done, write output file.
342    //
343    fwrite (FileBuffer + sizeof (UINT32), 1, FileSize - sizeof (UINT32), OutFile);
344    VerboseMsg ("the size of the decoded file is %u bytes", (unsigned) FileSize - sizeof (UINT32));
345  }
346
347Finish:
348  if (FileBuffer != NULL) {
349    free (FileBuffer);
350  }
351
352  if (OutFile != NULL) {
353    fclose (OutFile);
354  }
355
356  VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());
357
358  return GetUtilityStatus ();
359}
360
361
362
363
364