SHEL23
[mirror/efi/shell/.git] / EfiDecompress / Decompress.c
1 /*++
2
3 Copyright (c) 2005 - 2007, Intel Corporation                                                         
4 All rights reserved. This program and the accompanying materials                          
5 are licensed and made available under the terms and conditions of the BSD License         
6 which accompanies this distribution. The full text of the license may be found at         
7 http://opensource.org/licenses/bsd-license.php                                            
8                                                                                           
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
11
12 Module Name:
13
14   decompress.c
15   
16 Abstract:
17
18   EFI shell command "EfiDecompress" - decompress a file
19
20 Revision History
21
22 --*/
23
24 #include "EfiShellLib.h"
25 #include "decompress.h"
26
27 extern UINT8    STRING_ARRAY_NAME[];
28
29 //
30 // This is the generated header file which includes whatever needs to be exported (strings + IFR)
31 //
32 #include STRING_DEFINES_FILE
33
34 #include EFI_PROTOCOL_DEFINITION (decompress)
35
36 EFI_HII_HANDLE  HiiDecompressHandle;
37 EFI_GUID        EfiDecompressGuid = EFI_DECOMPRESS_GUID;
38 SHELL_VAR_CHECK_ITEM    DecompressCheckList[] = {
39   {
40     L"-b",
41     0x1,
42     0,
43     FlagTypeSingle
44   },
45   {
46     L"-?",
47     0x2,
48     0,
49     FlagTypeSingle
50   },
51   {
52     NULL,
53     0,
54     0,
55     0
56   }
57 };
58
59 //
60 // Function declarations
61 //
62 EFI_STATUS
63 InitializeDecompress (
64   IN EFI_HANDLE           ImageHandle,
65   IN EFI_SYSTEM_TABLE     *SystemTable
66   );
67
68 //
69 // Entry Point
70 //
71 EFI_BOOTSHELL_CODE(
72   EFI_APPLICATION_ENTRY_POINT(InitializeDecompress)
73 )
74
75 EFI_STATUS
76 InitializeDecompress (
77   IN EFI_HANDLE           ImageHandle,
78   IN EFI_SYSTEM_TABLE     *SystemTable
79   )
80 /*++
81
82 Routine Description:
83   Command entry point. Decompress the contents of a file.
84
85 Arguments:
86   ImageHandle     The image handle. 
87   SystemTable     The system table.
88
89 Returns:
90   EFI_SUCCESS             - The command completed successfully
91   EFI_INVALID_PARAMETER   - Command usage error
92   EFI_OUT_OF_RESOURCES    - Out of memory
93   EFI_UNSUPPORTED         - Protocols unsupported
94   Other value             - Unknown error
95    
96 --*/
97 {
98   EFI_LIST_ENTRY          File1List;
99   EFI_LIST_ENTRY          File2List;
100   SHELL_FILE_ARG          *File1Arg;
101   SHELL_FILE_ARG          *File2Arg;
102   EFI_FILE_HANDLE         File2Handle;
103   UINTN                   SourceSize;
104   UINTN                   DestinationSize;
105   UINTN                   ScratchSize;
106   UINT8                   *File1Buffer;
107   UINT8                   *File2Buffer;
108   UINT8                   *Scratch;
109   EFI_STATUS              Status;
110   EFI_DECOMPRESS_PROTOCOL *Decompress;
111   SHELL_VAR_CHECK_CODE    RetCode;
112   CHAR16                  *Useful;
113   SHELL_ARG_LIST          *Item;
114   BOOLEAN                 DstFileExist;
115   SHELL_VAR_CHECK_PACKAGE ChkPck;
116   
117   //
118   // Local variable initializations
119   //
120   DstFileExist  = FALSE;
121   File1Buffer   = NULL;
122   File2Buffer   = NULL;
123   Scratch       = NULL;
124   InitializeListHead (&File1List);
125   InitializeListHead (&File2List);
126   ZeroMem (&ChkPck, sizeof (SHELL_VAR_CHECK_PACKAGE));
127   //
128   // We are not being installed as an internal command driver, initialize
129   // as an nshell app and run
130   //
131   EFI_SHELL_APP_INIT (ImageHandle, SystemTable);
132   
133   //
134   // Enable tab key which can pause the output
135   //
136   EnableOutputTabPause();
137   
138   //
139   // Register our string package with HII and return the handle to it.
140   // If previously registered we will simply receive the handle
141   //
142   EFI_SHELL_STR_INIT (HiiDecompressHandle, STRING_ARRAY_NAME, EfiDecompressGuid);
143
144   if (!EFI_PROPER_VERSION (0, 99)) {
145     PrintToken (
146       STRING_TOKEN (STR_SHELLENV_GNC_COMMAND_NOT_SUPPORT),
147       HiiDecompressHandle,
148       L"efidecompress",
149       EFI_VERSION_0_99 
150       );
151     Status = EFI_UNSUPPORTED;
152     goto Quit;
153   }
154
155   LibFilterNullArgs ();
156   //
157   // Parse command line arguments
158   //
159   RetCode = LibCheckVariables (SI, DecompressCheckList, &ChkPck, &Useful);
160   if (VarCheckOk != RetCode) {
161     switch (RetCode) {
162     case VarCheckUnknown:
163       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_UNKNOWN_FLAG), HiiDecompressHandle, L"efidecompress", Useful);
164       break;
165
166     default:
167       break;
168     }
169
170     Status = EFI_INVALID_PARAMETER;
171     goto Quit;
172   }
173
174   if (LibCheckVarGetFlag (&ChkPck, L"-b")) {
175     EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
176   }
177
178   if (LibCheckVarGetFlag (&ChkPck, L"-?")) {
179     if (ChkPck.ValueCount > 0 ||
180         ChkPck.FlagCount > 2 ||
181         (2 == ChkPck.FlagCount && !LibCheckVarGetFlag (&ChkPck, L"-b"))
182         ) {
183       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_TOO_MANY), HiiDecompressHandle, L"efidecompress");
184       Status = EFI_INVALID_PARAMETER;
185     } else {
186       PrintToken (STRING_TOKEN (STR_EFIDECOMPRESS_VERBOSEHELP), HiiDecompressHandle);
187       Status = EFI_SUCCESS;
188     }
189
190     goto Quit;
191   }
192   //
193   //
194   //
195   Status = LibLocateProtocol (&gEfiDecompressProtocolGuid, &Decompress);
196   if (EFI_ERROR (Status)) {
197     PrintToken (STRING_TOKEN (STR_DECOMPRESS_PROTOCOL_NOT_FOUND), HiiDecompressHandle, L"efidecompress");
198     Status = EFI_UNSUPPORTED;
199     goto Quit;
200   }
201   //
202   // verify number of arguments
203   //
204   if (ChkPck.ValueCount > 2) {
205     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_TOO_MANY), HiiDecompressHandle, L"efidecompress");
206     Status = EFI_INVALID_PARAMETER;
207     goto Quit;
208   }
209
210   if (ChkPck.ValueCount < 2) {
211     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_TOO_FEW), HiiDecompressHandle, L"efidecompress");
212     Status = EFI_INVALID_PARAMETER;
213     goto Quit;
214   }
215   //
216   // validate first file
217   //
218   Item    = GetFirstArg (&ChkPck);
219   Status  = ShellFileMetaArg (Item->VarStr, &File1List);
220   if (EFI_ERROR (Status)) {
221     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE), HiiDecompressHandle, L"efidecompress", Item->VarStr);
222     goto Done;
223   }
224   //
225   // empty list
226   //
227   if (IsListEmpty (&File1List)) {
228     Status = EFI_NOT_FOUND;
229     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE), HiiDecompressHandle, L"efidecompress", Item->VarStr);
230     goto Done;
231   }
232   //
233   // multiple files
234   //
235   if (File1List.Flink->Flink != &File1List) {
236     PrintToken (STRING_TOKEN (STR_DECOMPRESS_FIRST_MULT_FILES), HiiDecompressHandle, L"efidecompress");
237     Status = EFI_INVALID_PARAMETER;
238     goto Done;
239   }
240
241   File1Arg = CR (File1List.Flink, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
242
243   //
244   // Open error
245   //
246   if (EFI_ERROR (File1Arg->Status) || !File1Arg->Handle) {
247     PrintToken (
248       STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE),
249       HiiDecompressHandle,
250       L"efidecompress",
251       File1Arg->FullName
252       );
253     Status = File1Arg->Status;
254     goto Done;
255   }
256   //
257   // directory
258   //
259   if (File1Arg->Info && (File1Arg->Info->Attribute & EFI_FILE_DIRECTORY)) {
260     PrintToken (STRING_TOKEN (STR_DECOMPRESS_FIRST_ARG_DIR), HiiDecompressHandle, L"efidecompress");
261     Status = EFI_INVALID_PARAMETER;
262     goto Done;
263   }
264   //
265   // Validate second file
266   //
267   Item    = GetNextArg (Item);
268   Status  = ShellFileMetaArg (Item->VarStr, &File2List);
269   if (EFI_ERROR (Status)) {
270     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE), HiiDecompressHandle, L"efidecompress", Item->VarStr);
271     goto Done;
272   }
273   //
274   // empty list
275   //
276   if (IsListEmpty (&File2List)) {
277     Status = EFI_NOT_FOUND;
278     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE), HiiDecompressHandle, L"efidecompress", Item->VarStr);
279     goto Done;
280   }
281   //
282   // multiple files
283   //
284   if (File2List.Flink->Flink != &File2List) {
285     PrintToken (STRING_TOKEN (STR_DECOMPRESS_SECOND_MULT_FILES), HiiDecompressHandle, L"efidecompress");
286     Status = EFI_INVALID_PARAMETER;
287     goto Done;
288   }
289
290   File2Arg = CR (
291               File2List.Flink,
292               SHELL_FILE_ARG,
293               Link,
294               SHELL_FILE_ARG_SIGNATURE
295               );
296
297   if (!File2Arg->Parent) {
298     PrintToken (
299       STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE),
300       HiiDecompressHandle,
301       L"efidecompress",
302       File2Arg->FullName
303       );
304     Status = File2Arg->Status;
305     goto Done;
306   }
307   //
308   // directory
309   //
310   if (File2Arg->Info && (File2Arg->Info->Attribute & EFI_FILE_DIRECTORY)) {
311     PrintToken (STRING_TOKEN (STR_DECOMPRESS_SECOND_DIR), HiiDecompressHandle, L"efidecompress");
312     Status = EFI_INVALID_PARAMETER;
313     goto Done;
314   }
315   //
316   // Allocate buffers for both files
317   //
318   SourceSize  = (UINTN) File1Arg->Info->FileSize;
319   File1Buffer = AllocatePool (SourceSize);
320   if (File1Buffer == NULL) {
321     PrintToken (STRING_TOKEN (STR_DECOMPRESS_OUT_OF_MEM), HiiDecompressHandle, L"efidecompress");
322     Status = EFI_OUT_OF_RESOURCES;
323     goto Done;
324   }
325
326   Status = File1Arg->Handle->Read (File1Arg->Handle, &SourceSize, File1Buffer);
327   if (EFI_ERROR (Status)) {
328     PrintToken (
329       STRING_TOKEN (STR_DECOMPRESS_READ_ERROR),
330       HiiDecompressHandle,
331       L"efidecompress",
332       File1Arg->FullName,
333       Status
334       );
335     goto Done;
336   }
337
338   DestinationSize = 0;
339   ScratchSize     = 0;
340   Status = Decompress->GetInfo (
341                         Decompress,
342                         File1Buffer,
343                         (UINT32) SourceSize,
344                         (UINT32 *) &DestinationSize,
345                         (UINT32 *) &ScratchSize
346                         );
347   if (EFI_ERROR (Status)) {
348     PrintToken (
349       STRING_TOKEN (STR_DECOMPRESS_COMPRESSED_DAMAGED),
350       HiiDecompressHandle,
351       L"eficompress",
352       File1Arg->FullName,
353       Status
354       );
355     goto Done;
356   }
357
358   File2Buffer = AllocatePool (DestinationSize);
359   if (File2Buffer == NULL) {
360     PrintToken (STRING_TOKEN (STR_DECOMPRESS_OUT_OF_MEM), HiiDecompressHandle, L"efidecompress");
361     Status = EFI_OUT_OF_RESOURCES;
362     goto Done;
363   }
364
365   Scratch = AllocatePool (ScratchSize);
366   if (Scratch == NULL) {
367     PrintToken (STRING_TOKEN (STR_DECOMPRESS_OUT_OF_MEM), HiiDecompressHandle, L"efidecompress");
368     Status = EFI_OUT_OF_RESOURCES;
369     goto Done;
370   }
371
372   Status = Decompress->Decompress (
373                         Decompress,
374                         File1Buffer,
375                         (UINT32) SourceSize,
376                         File2Buffer,
377                         (UINT32) DestinationSize,
378                         Scratch,
379                         (UINT32) ScratchSize
380                         );
381   if (EFI_ERROR (Status)) {
382     PrintToken (
383       STRING_TOKEN (STR_DECOMPRESS_ERROR),
384       HiiDecompressHandle,
385       L"efidecompress",
386       File1Arg->FullName,
387       Status
388       );
389     goto Done;
390   }
391
392   if (File2Arg->Status == EFI_SUCCESS &&
393       File2Arg->OpenMode & EFI_FILE_MODE_READ &&
394       File2Arg->OpenMode & EFI_FILE_MODE_WRITE
395       ) {
396     File2Handle               = File2Arg->Handle;
397     File2Arg->Info->FileSize  = 0;
398     Status = File2Handle->SetInfo (
399                             File2Handle,
400                             &gEfiFileInfoGuid,
401                             (UINTN) File2Arg->Info->Size,
402                             File2Arg->Info
403                             );
404     Status = File2Handle->Write (File2Handle, &DestinationSize, File2Buffer);
405     if (EFI_ERROR (Status)) {
406       PrintToken (
407         STRING_TOKEN (STR_DECOMPRESS_WRITE_ERROR),
408         HiiDecompressHandle,
409         L"efidecompress",
410         File2Arg->FullName,
411         Status
412         );
413       goto Done;
414     }
415
416     DstFileExist = TRUE;
417   } else {
418     Status = File2Arg->Parent->Open (
419                                 File2Arg->Parent,
420                                 &File2Handle,
421                                 File2Arg->FileName,
422                                 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
423                                 0
424                                 );
425     if (EFI_ERROR (Status)) {
426       PrintToken (
427         STRING_TOKEN (STR_DECOMPRESS_CREATE_ERROR),
428         HiiDecompressHandle,
429         L"efidecompress",
430         File2Arg->FullName,
431         Status
432         );
433       goto Done;
434     }
435
436     Status = File2Handle->Write (File2Handle, &DestinationSize, File2Buffer);
437     if (EFI_ERROR (Status)) {
438       PrintToken (
439         STRING_TOKEN (STR_DECOMPRESS_WRITE_ERROR),
440         HiiDecompressHandle,
441         L"efidecompress",
442         File2Arg->FullName,
443         Status
444         );
445       File2Handle->Close (File2Handle);
446       goto Done;
447     }
448   }
449
450   if (!DstFileExist) {
451     File2Handle->Close (File2Handle);
452   }
453
454   ASSERT (!EFI_ERROR (Status));
455   PrintToken (
456     STRING_TOKEN (STR_DECOMPRESS_SUCCESS),
457     HiiDecompressHandle,
458     L"efidecompress",
459     File1Arg->FullName,
460     File2Arg->FullName
461     );
462
463 Done:
464   if (File1Buffer) {
465     FreePool (File1Buffer);
466   }
467
468   if (File2Buffer) {
469     FreePool (File2Buffer);
470   }
471
472   if (Scratch) {
473     FreePool (Scratch);
474   }
475
476   ShellFreeFileList (&File1List);
477   ShellFreeFileList (&File2List);
478
479 Quit:
480   //
481   // Shell command always succeeds
482   //
483   LibUnInitializeStrings ();
484   LibCheckVarFreeVarList (&ChkPck);
485   return Status;
486 }
487
488 EFI_STATUS
489 InitializeDecompressGetLineHelp (
490   OUT CHAR16                  **Str
491   )
492 /*++
493
494 Routine Description:
495
496   Get this command's line help
497
498 Arguments:
499
500   Str - The line help
501
502 Returns:
503
504   EFI_SUCCESS   - Success
505
506 --*/
507 {
508   return LibCmdGetStringByToken (STRING_ARRAY_NAME, &EfiDecompressGuid, STRING_TOKEN (STR_EFIDECOMPRESS_LINEHELP), Str);
509 }