]>
Commit | Line | Data |
---|---|---|
4684b66f | 1 | /*++ |
2 | This file contains an 'Intel UEFI Application' and is | |
3 | licensed for Intel CPUs and chipsets under the terms of your | |
4 | license agreement with Intel or your vendor. This file may | |
5 | be modified by the user, subject to additional terms of the | |
6 | license agreement | |
7 | --*/ | |
8 | /*++ | |
9 | ||
10 | Copyright (c) 2011 Intel Corporation. All rights reserved | |
11 | This software and associated documentation (if any) is furnished | |
12 | under a license and may only be used or copied in accordance | |
13 | with the terms of the license. Except as permitted by such | |
14 | license, no part of this software or documentation may be | |
15 | reproduced, stored in a retrieval system, or transmitted in any | |
16 | form or by any means without the express written consent of | |
17 | Intel Corporation. | |
18 | ||
19 | --*/ | |
20 | ||
21 | /** @file | |
22 | HTTP processing for the web server. | |
23 | ||
24 | **/ | |
25 | ||
26 | #include <WebServer.h> | |
27 | ||
28 | /** | |
29 | Get a UTF-8 character from the buffer | |
30 | ||
31 | @param [in] pData The address of the buffer containing the character | |
32 | @param [out] ppData The address to receive the next character address | |
33 | ||
34 | @returns The character value | |
35 | ||
36 | **/ | |
37 | INTN | |
38 | HttpCharGet ( | |
39 | IN UINT8 * pData, | |
40 | IN UINT8 ** ppData | |
41 | ) | |
42 | { | |
43 | INTN Data; | |
44 | INTN Character; | |
45 | INTN Control; | |
46 | INTN Mask; | |
47 | ||
48 | // | |
49 | // Verify that there is some data left | |
50 | // | |
51 | if ( NULL == pData ) { | |
52 | // | |
53 | // No data to return | |
54 | // | |
55 | pData = NULL; | |
56 | Character = 0; | |
57 | } | |
58 | else { | |
59 | // | |
60 | // Get the first portion of the character | |
61 | // | |
62 | Character = *pData++; | |
63 | Control = Character; | |
64 | Mask = 0xc0; | |
65 | ||
66 | // | |
67 | // Append the rest of the character | |
68 | // | |
69 | if ( 0 != ( Control & 0x80 )) { | |
70 | while ( 0 != ( Control & 0x40 )) { | |
71 | Character &= Mask; | |
72 | Mask <<= 5; | |
73 | Control <<= 1; | |
74 | Character <<= 6; | |
75 | Data = *pData++ & 0x3f; | |
76 | if ( 0x80 != ( Data & 0xc0 )) { | |
77 | // | |
78 | // Invalid character | |
79 | // | |
80 | pData = NULL; | |
81 | Character = 0; | |
82 | break; | |
83 | } | |
84 | Character |= Data & 0x3f; | |
85 | } | |
86 | } | |
87 | } | |
88 | ||
89 | // | |
90 | // Return the next character location and the character | |
91 | // | |
92 | *ppData = pData; | |
93 | return Character; | |
94 | } | |
95 | ||
96 | ||
97 | /** | |
98 | Transmit a portion of the HTTP response | |
99 | ||
100 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
101 | @param [in] pPort The WSDT_PORT structure address | |
102 | ||
103 | @retval EFI_SUCCESS The request was successfully processed | |
104 | ||
105 | **/ | |
106 | EFI_STATUS | |
107 | HttpFlush ( | |
108 | IN int SocketFD, | |
109 | IN WSDT_PORT * pPort | |
110 | ) | |
111 | { | |
112 | INTN LengthInBytes; | |
113 | UINT8 * pBuffer; | |
114 | EFI_STATUS Status; | |
115 | ||
116 | DBG_ENTER ( ); | |
117 | ||
118 | // | |
119 | // Assume success | |
120 | // | |
121 | Status = EFI_SUCCESS; | |
122 | pBuffer = &pPort->TxBuffer[0]; | |
123 | do { | |
124 | // | |
125 | // Attempt to send the data | |
126 | // | |
127 | LengthInBytes = send ( SocketFD, | |
128 | pBuffer, | |
129 | pPort->TxBytes, | |
130 | 0 ); | |
131 | if ( -1 != LengthInBytes ) { | |
132 | // | |
133 | // Account for the data sent | |
134 | // | |
135 | pBuffer += LengthInBytes; | |
136 | pPort->TxBytes -= LengthInBytes; | |
137 | } | |
138 | else { | |
139 | // | |
140 | // Transmit error | |
141 | // | |
142 | Status = EFI_DEVICE_ERROR; | |
143 | break; | |
144 | } | |
145 | } while ( 0 < pPort->TxBytes ); | |
146 | ||
147 | // | |
148 | // Return the operation status | |
149 | // | |
150 | DBG_EXIT_STATUS ( Status ); | |
151 | return Status; | |
152 | } | |
153 | ||
154 | ||
155 | /** | |
156 | Convert the ANSI character to lower case | |
157 | ||
158 | @param [in] Character The character to convert to lower case. | |
159 | ||
160 | @returns The lower case character | |
161 | ||
162 | **/ | |
163 | INTN | |
164 | HttpLowerCase ( | |
165 | IN INTN Character | |
166 | ) | |
167 | { | |
168 | // | |
169 | // Determine if the character is upper case | |
170 | // | |
171 | if (( 'A' <= Character ) && ( 'Z' >= Character )) { | |
172 | Character += 'a' - 'A'; | |
173 | } | |
174 | ||
175 | // | |
176 | // Return the lower case value of the character | |
177 | // | |
178 | return Character; | |
179 | } | |
180 | ||
181 | ||
182 | /** | |
183 | Match a Unicode string against a UTF-8 string | |
184 | ||
185 | @param [in] pString A zero terminated Unicode string | |
186 | @param [in] pData A zero terminated UTF-8 string | |
187 | @param [in] bIgnoreCase TRUE if case is to be ignored | |
188 | ||
189 | @returns The difference between the last two characters tested. | |
190 | Returns -1 for error. | |
191 | ||
192 | **/ | |
193 | INTN | |
194 | HttpMatch ( | |
195 | IN UINT16 * pString, | |
196 | IN UINT8 * pData, | |
197 | IN BOOLEAN bIgnoreCase | |
198 | ) | |
199 | { | |
200 | INTN Character1; | |
201 | INTN Character2; | |
202 | INTN Difference; | |
203 | ||
204 | do { | |
205 | // | |
206 | // Get the character from the comparison string | |
207 | // | |
208 | Character1 = *pString++; | |
209 | ||
210 | // | |
211 | // Convert the character to lower case | |
212 | // | |
213 | if ( bIgnoreCase ) { | |
214 | Character1 = HttpLowerCase ( Character1 ); | |
215 | } | |
216 | ||
217 | // | |
218 | // Get the character from the request | |
219 | // | |
220 | Character2 = HttpCharGet ( pData, &pData ); | |
221 | if ( NULL == pData ) { | |
222 | // | |
223 | // Error getting character | |
224 | // | |
225 | Difference = -1; | |
226 | break; | |
227 | } | |
228 | ||
229 | // | |
230 | // Convert the character to lower case | |
231 | // | |
232 | if ( bIgnoreCase ) { | |
233 | Character2 = HttpLowerCase ( Character2 ); | |
234 | } | |
235 | ||
236 | // | |
237 | // Compare the characters | |
238 | // | |
239 | Difference = Character1 - Character2; | |
240 | if ( 0 != Difference ) { | |
241 | return Difference; | |
242 | } | |
243 | } while ( 0 != Character1 ); | |
244 | ||
245 | // | |
246 | // Return the difference | |
247 | // | |
248 | return Difference; | |
249 | } | |
250 | ||
251 | ||
252 | /** | |
253 | Buffer the HTTP page header | |
254 | ||
255 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
256 | @param [in] pPort The WSDT_PORT structure address | |
257 | @param [in] pTitle A zero terminated Unicode title string | |
258 | ||
259 | @retval EFI_SUCCESS The request was successfully processed | |
260 | ||
261 | **/ | |
262 | EFI_STATUS | |
263 | HttpPageHeader ( | |
264 | IN int SocketFD, | |
265 | IN WSDT_PORT * pPort, | |
266 | IN CONST CHAR16 * pTitle | |
267 | ) | |
268 | { | |
269 | EFI_STATUS Status; | |
270 | ||
271 | DBG_ENTER ( ); | |
272 | ||
273 | // | |
274 | // Build the page header | |
275 | // | |
276 | for ( ; ; ) { | |
277 | Status = HttpSendAnsiString ( SocketFD, | |
278 | pPort, | |
279 | "<!DOCTYPE " | |
280 | "HTML " | |
281 | "PUBLIC " | |
282 | "\"-//W3C//DTD HTML 4.01 Transitional//EN\" " | |
283 | "\"http://www.w3.org/TR/html4/loose.dtd\">\r\n" ); | |
284 | if ( EFI_ERROR ( Status )) { | |
285 | break; | |
286 | } | |
287 | Status = HttpSendAnsiString ( SocketFD, pPort, "<html lang=\"en-US\">\r\n" ); | |
288 | if ( EFI_ERROR ( Status )) { | |
289 | break; | |
290 | } | |
291 | if ( NULL != pTitle ) { | |
292 | Status = HttpSendAnsiString ( SocketFD, pPort, " <head>\r\n" ); | |
293 | if ( EFI_ERROR ( Status )) { | |
294 | break; | |
295 | } | |
296 | Status = HttpSendAnsiString ( SocketFD, pPort, " <title>" ); | |
297 | if ( EFI_ERROR ( Status )) { | |
298 | break; | |
299 | } | |
300 | Status = HttpSendUnicodeString ( SocketFD, pPort, pTitle ); | |
301 | if ( EFI_ERROR ( Status )) { | |
302 | break; | |
303 | } | |
304 | Status = HttpSendAnsiString ( SocketFD, pPort, "</title>\r\n" ); | |
305 | if ( EFI_ERROR ( Status )) { | |
306 | break; | |
307 | } | |
308 | Status = HttpSendAnsiString ( SocketFD, pPort, " </head>\r\n" ); | |
309 | if ( EFI_ERROR ( Status )) { | |
310 | break; | |
311 | } | |
312 | } | |
313 | Status = HttpSendAnsiString ( SocketFD, pPort, " <body>\r\n" ); | |
314 | break; | |
315 | } | |
316 | ||
317 | // | |
318 | // Return the operation status | |
319 | // | |
320 | DBG_EXIT_STATUS ( Status ); | |
321 | return Status; | |
322 | } | |
323 | ||
324 | ||
325 | /** | |
326 | Respond with an error indicating that the page was not found | |
327 | ||
328 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
329 | @param [in] pPort The WSDT_PORT structure address | |
330 | @param [out] pbDone Address to receive the request completion status | |
331 | ||
332 | @retval EFI_SUCCESS The request was successfully processed | |
333 | ||
334 | **/ | |
335 | EFI_STATUS | |
336 | HttpPageNotFound ( | |
337 | IN int SocketFD, | |
338 | IN WSDT_PORT * pPort, | |
339 | IN BOOLEAN * pbDone | |
340 | ) | |
341 | { | |
342 | EFI_STATUS Status; | |
343 | ||
344 | DBG_ENTER ( ); | |
345 | ||
346 | // | |
347 | // Send the page not found | |
348 | // | |
349 | for ( ; ; ) { | |
350 | // | |
351 | // Send the page header | |
352 | // | |
353 | Status = HttpPageHeader ( SocketFD, pPort, L"404 Not found" ); | |
354 | if ( EFI_ERROR ( Status )) { | |
355 | break; | |
356 | } | |
357 | ||
358 | // | |
359 | // Send the page body | |
360 | // | |
361 | Status = HttpSendAnsiString ( SocketFD, | |
362 | pPort, | |
363 | "ERROR <b>404</b><br />" | |
364 | "Requested page is not available\r\n" ); | |
365 | if ( EFI_ERROR ( Status )) { | |
366 | break; | |
367 | } | |
368 | ||
369 | // | |
370 | // Send the page trailer | |
371 | // | |
372 | Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); | |
373 | break; | |
374 | } | |
375 | ||
376 | // | |
377 | // Return the operation status | |
378 | // | |
379 | DBG_EXIT_STATUS ( Status ); | |
380 | return Status; | |
381 | } | |
382 | ||
383 | ||
384 | /** | |
385 | Buffer and send the HTTP page trailer | |
386 | ||
387 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
388 | @param [in] pPort The WSDT_PORT structure address | |
389 | @param [out] pbDone Address to receive the request completion status | |
390 | ||
391 | @retval EFI_SUCCESS The request was successfully processed | |
392 | ||
393 | **/ | |
394 | EFI_STATUS | |
395 | HttpPageTrailer ( | |
396 | IN int SocketFD, | |
397 | IN WSDT_PORT * pPort, | |
398 | IN BOOLEAN * pbDone | |
399 | ) | |
400 | { | |
401 | int RetVal; | |
402 | EFI_STATUS Status; | |
403 | socklen_t LengthInBytes; | |
404 | struct sockaddr_in LocalAddress; | |
405 | struct sockaddr_in RemoteAddress; | |
406 | ||
407 | DBG_ENTER ( ); | |
408 | ||
409 | // | |
410 | // Build the page header | |
411 | // | |
412 | for ( ; ; ) { | |
413 | LengthInBytes = sizeof ( LocalAddress ); | |
414 | RetVal = getsockname ( SocketFD, (struct sockaddr *)&LocalAddress, &LengthInBytes ); | |
415 | if ( 0 == RetVal ) { | |
416 | RetVal = getpeername ( SocketFD, (struct sockaddr *)&RemoteAddress, &LengthInBytes ); | |
417 | if ( 0 == RetVal ) { | |
418 | // | |
419 | // Seperate the body from the trailer | |
420 | // | |
421 | Status = HttpSendAnsiString ( SocketFD, pPort, " <hr>\r\n" ); | |
422 | if ( EFI_ERROR ( Status )) { | |
423 | break; | |
424 | } | |
425 | ||
426 | // | |
427 | // Display the system addresses and the page transfer direction | |
428 | // | |
429 | Status = HttpSendIpAddress ( SocketFD, pPort, &LocalAddress ); | |
430 | if ( EFI_ERROR ( Status )) { | |
431 | break; | |
432 | } | |
433 | Status = HttpSendAnsiString ( SocketFD, pPort, " --> " ); | |
434 | if ( EFI_ERROR ( Status )) { | |
435 | break; | |
436 | } | |
437 | Status = HttpSendIpAddress ( SocketFD, pPort, &RemoteAddress ); | |
438 | if ( EFI_ERROR ( Status )) { | |
439 | break; | |
440 | } | |
441 | Status = HttpSendAnsiString ( SocketFD, pPort, "\r\n" ); | |
442 | if ( EFI_ERROR ( Status )) { | |
443 | break; | |
444 | } | |
445 | } | |
446 | } | |
447 | ||
448 | // | |
449 | // Terminate the page | |
450 | // | |
451 | Status = HttpSendAnsiString ( SocketFD, pPort, " </body>\r\n" ); | |
452 | if ( EFI_ERROR ( Status )) { | |
453 | break; | |
454 | } | |
455 | Status = HttpSendAnsiString ( SocketFD, pPort, " </html>\r\n" ); | |
456 | if ( EFI_ERROR ( Status )) { | |
457 | break; | |
458 | } | |
459 | ||
460 | // | |
461 | // Send the page trailer | |
462 | // | |
463 | Status = HttpFlush ( SocketFD, pPort ); | |
464 | if ( EFI_ERROR ( Status )) { | |
465 | break; | |
466 | } | |
467 | ||
468 | // | |
469 | // Mark the page as complete | |
470 | // | |
471 | *pbDone = TRUE; | |
472 | break; | |
473 | } | |
474 | ||
475 | // | |
476 | // Return the operation status | |
477 | // | |
478 | DBG_EXIT_STATUS ( Status ); | |
479 | return Status; | |
480 | } | |
481 | ||
482 | ||
483 | /** | |
484 | Replace a space with a zero | |
485 | ||
486 | @param [in] pData The request buffer address | |
487 | @param [in] pEnd End of buffer address | |
488 | ||
489 | @returns The next character location | |
490 | ||
491 | **/ | |
492 | UINT8 * | |
493 | HttpReplaceSpace ( | |
494 | IN UINT8 * pData, | |
495 | IN UINT8 * pEnd | |
496 | ) | |
497 | { | |
498 | INTN Character; | |
499 | UINT8 * pSpace; | |
500 | ||
501 | pSpace = pData; | |
502 | while ( pEnd > pData ) { | |
503 | // | |
504 | // Get the character from the request | |
505 | // | |
506 | Character = HttpCharGet ( pData, &pData ); | |
507 | if ( ' ' == Character ) { | |
508 | break; | |
509 | } | |
510 | pSpace = pData; | |
511 | } | |
512 | ||
513 | // | |
514 | // Replace the space character with zero | |
515 | // | |
516 | ZeroMem ( pSpace, pData - pSpace ); | |
517 | ||
518 | // | |
519 | // Return the next character location | |
520 | // | |
521 | return pData; | |
522 | } | |
523 | ||
524 | ||
525 | /** | |
526 | Process an HTTP request | |
527 | ||
528 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
529 | @param [in] pPort The WSDT_PORT structure address | |
530 | @param [out] pbDone Address to receive the request completion status | |
531 | ||
532 | @retval EFI_SUCCESS The request was successfully processed | |
533 | ||
534 | **/ | |
535 | EFI_STATUS | |
536 | HttpRequest ( | |
537 | IN int SocketFD, | |
538 | IN WSDT_PORT * pPort, | |
539 | OUT BOOLEAN * pbDone | |
540 | ) | |
541 | { | |
542 | UINT8 * pData; | |
543 | UINT8 * pEnd; | |
544 | CONST DT_PAGE * pPage; | |
545 | CONST DT_PAGE * pPageEnd; | |
546 | UINT8 * pVerb; | |
547 | UINT8 * pVersion; | |
548 | UINT8 * pWebPage; | |
549 | EFI_STATUS Status; | |
550 | ||
551 | DBG_ENTER ( ); | |
552 | ||
553 | // | |
554 | // Assume the request is not finished | |
555 | // | |
556 | *pbDone = FALSE; | |
557 | Status = EFI_SUCCESS; | |
558 | for ( ; ; ) { | |
559 | ||
560 | // | |
561 | // Attempt to parse the command | |
562 | // | |
563 | pData = &pPort->Request[0]; | |
564 | pEnd = &pData [ pPort->RequestLength ]; | |
565 | pVerb = pData; | |
566 | pWebPage = HttpReplaceSpace ( pVerb, pEnd ); | |
567 | if ( pEnd <= pWebPage ) { | |
568 | break; | |
569 | } | |
570 | pVersion = HttpReplaceSpace ( pWebPage, pEnd ); | |
571 | if ( pEnd <= pVersion ) { | |
572 | break; | |
573 | } | |
574 | ||
575 | // | |
576 | // Validate the request | |
577 | // | |
578 | if ( 0 != HttpMatch ( L"GET", pVerb, TRUE )) { | |
579 | // | |
580 | // Invalid request type | |
581 | // | |
582 | DEBUG (( DEBUG_REQUEST, | |
583 | "HTTP: Invalid verb\r\n" )); | |
584 | Status = EFI_NOT_FOUND; | |
585 | break; | |
586 | } | |
587 | ||
588 | // | |
589 | // Walk the page table | |
590 | // | |
591 | pPage = &mPageList[0]; | |
592 | pPageEnd = &pPage [ mPageCount ]; | |
593 | while ( pPageEnd > pPage ) { | |
594 | // | |
595 | // Determine if the page was located | |
596 | // | |
597 | if ( 0 == HttpMatch ( pPage->pPageName, pWebPage, FALSE )) { | |
598 | break; | |
599 | } | |
600 | ||
601 | // | |
602 | // Set the next page | |
603 | // | |
604 | pPage += 1; | |
605 | } | |
606 | if ( pPageEnd <= pPage ) { | |
607 | // | |
608 | // The page was not found | |
609 | // | |
610 | DEBUG (( DEBUG_REQUEST, | |
611 | "HTTP: Page not found in page table\r\n" )); | |
612 | Status = EFI_NOT_FOUND; | |
613 | break; | |
614 | } | |
615 | ||
616 | // | |
617 | // Respond with the page contents | |
618 | // | |
619 | Status = pPage->pfnResponse ( SocketFD, pPort, pbDone ); | |
620 | break; | |
621 | } | |
622 | ||
623 | // | |
624 | // Return page not found if necessary | |
625 | // | |
626 | if ( EFI_NOT_FOUND == Status ) { | |
627 | Status = HttpPageNotFound ( SocketFD, pPort, pbDone ); | |
628 | } | |
629 | ||
630 | // | |
631 | // Return the operation status | |
632 | // | |
633 | DBG_EXIT_STATUS ( Status ); | |
634 | return Status; | |
635 | } | |
636 | ||
637 | ||
638 | /** | |
639 | Buffer data for sending | |
640 | ||
641 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
642 | @param [in] pPort The WSDT_PORT structure address | |
643 | @param [in] LengthInBytes Length of valid data in the buffer | |
644 | @param [in] pBuffer Buffer of data to send | |
645 | ||
646 | @retval EFI_SUCCESS The request was successfully processed | |
647 | ||
648 | **/ | |
649 | EFI_STATUS | |
650 | HttpSend ( | |
651 | IN int SocketFD, | |
652 | IN WSDT_PORT * pPort, | |
653 | IN size_t LengthInBytes, | |
654 | IN CONST UINT8 * pBuffer | |
655 | ) | |
656 | { | |
657 | size_t DataBytes; | |
658 | size_t MaxBytes; | |
659 | EFI_STATUS Status; | |
660 | ||
661 | // | |
662 | // Assume success | |
663 | // | |
664 | Status = EFI_SUCCESS; | |
665 | do { | |
666 | // | |
667 | // Determine how much data fits into the buffer | |
668 | // | |
669 | MaxBytes = sizeof ( pPort->TxBuffer ); | |
670 | DataBytes = MaxBytes - pPort->TxBytes; | |
671 | if ( DataBytes > LengthInBytes ) | |
672 | { | |
673 | DataBytes = LengthInBytes; | |
674 | } | |
675 | ||
676 | // | |
677 | // Copy the data into the buffer | |
678 | // | |
679 | CopyMem ( &pPort->TxBuffer [ pPort->TxBytes ], | |
680 | pBuffer, | |
681 | DataBytes ); | |
682 | ||
683 | // | |
684 | // Account for the data copied | |
685 | // | |
686 | pPort->TxBytes += DataBytes; | |
687 | LengthInBytes -= DataBytes; | |
688 | ||
689 | // | |
690 | // Transmit the buffer if it is full | |
691 | // | |
692 | if ( MaxBytes <= pPort->TxBytes ) { | |
693 | Status = HttpFlush ( SocketFD, pPort ); | |
694 | } | |
695 | } while (( EFI_SUCCESS == Status ) && ( 0 < LengthInBytes )); | |
696 | ||
697 | // | |
698 | // Return the operation status | |
699 | // | |
700 | return Status; | |
701 | } | |
702 | ||
703 | ||
704 | /** | |
705 | Send an ANSI string | |
706 | ||
707 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
708 | @param [in] pPort The WSDT_PORT structure address | |
709 | @param [in] pString A zero terminated Unicode string | |
710 | ||
711 | @retval EFI_SUCCESS The request was successfully processed | |
712 | ||
713 | **/ | |
714 | EFI_STATUS | |
715 | HttpSendAnsiString ( | |
716 | IN int SocketFD, | |
717 | IN WSDT_PORT * pPort, | |
718 | IN CONST char * pString | |
719 | ) | |
720 | { | |
721 | CONST char * pData; | |
722 | EFI_STATUS Status; | |
723 | ||
724 | // | |
725 | // Assume success | |
726 | // | |
727 | Status = EFI_SUCCESS; | |
728 | ||
729 | // | |
730 | // Walk the characters in he string | |
731 | // | |
732 | pData = pString; | |
733 | while ( 0 != *pData ) { | |
734 | pData += 1; | |
735 | } | |
736 | ||
737 | // | |
738 | // Send the string | |
739 | // | |
740 | Status = HttpSend ( SocketFD, | |
741 | pPort, | |
742 | pData - pString, | |
743 | (CONST UINT8 *)pString ); | |
744 | ||
745 | // | |
746 | // Return the operation status | |
747 | // | |
748 | return Status; | |
749 | } | |
750 | ||
751 | ||
752 | /** | |
753 | Buffer a single byte | |
754 | ||
755 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
756 | @param [in] pPort The WSDT_PORT structure address | |
757 | @param [in] Data The data byte to send | |
758 | ||
759 | @retval EFI_SUCCESS The request was successfully processed | |
760 | ||
761 | **/ | |
762 | EFI_STATUS | |
763 | HttpSendByte ( | |
764 | IN int SocketFD, | |
765 | IN WSDT_PORT * pPort, | |
766 | IN UINT8 Data | |
767 | ) | |
768 | { | |
769 | EFI_STATUS Status; | |
770 | ||
771 | // | |
772 | // Send the data byte | |
773 | // | |
774 | Status = HttpSend ( SocketFD, | |
775 | pPort, | |
776 | 1, | |
777 | &Data ); | |
778 | ||
779 | // | |
780 | // Return the operation status | |
781 | // | |
782 | return Status; | |
783 | } | |
784 | ||
785 | ||
786 | /** | |
787 | Display a character | |
788 | ||
789 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
790 | @param [in] pPort The WSDT_PORT structure address | |
791 | @param [in] Character Character to display | |
792 | @param [in] pReplacement Replacement character string | |
793 | ||
794 | @retval EFI_SUCCESS The request was successfully processed | |
795 | ||
796 | **/ | |
797 | EFI_STATUS | |
798 | HttpSendCharacter ( | |
799 | IN int SocketFD, | |
800 | IN WSDT_PORT * pPort, | |
801 | IN CHAR8 Character, | |
802 | IN CHAR8 * pReplacement | |
803 | ) | |
804 | { | |
805 | EFI_STATUS Status; | |
806 | ||
807 | // | |
808 | // Determine if this is a printable character | |
809 | // | |
810 | if (( 0x20 <= Character ) && ( 0x7f > Character )) { | |
811 | if ( '<' == Character ) { | |
812 | // | |
813 | // Replace with HTML equivalent | |
814 | // | |
815 | Status = HttpSendAnsiString ( SocketFD, | |
816 | pPort, | |
817 | "<" ); | |
818 | } | |
819 | else if ( '>' == Character ) { | |
820 | // | |
821 | // Replace with HTML equivalent | |
822 | // | |
823 | Status = HttpSendAnsiString ( SocketFD, | |
824 | pPort, | |
825 | ">" ); | |
826 | } | |
827 | else if ( '&' == Character ) { | |
828 | // | |
829 | // Replace with HTML equivalent | |
830 | // | |
831 | Status = HttpSendAnsiString ( SocketFD, | |
832 | pPort, | |
833 | "&" ); | |
834 | } | |
835 | else if ( '\"' == Character ) { | |
836 | // | |
837 | // Replace with HTML equivalent | |
838 | // | |
839 | Status = HttpSendAnsiString ( SocketFD, | |
840 | pPort, | |
841 | """ ); | |
842 | } | |
843 | else { | |
844 | // | |
845 | // Display the character | |
846 | // | |
847 | Status = HttpSendByte ( SocketFD, | |
848 | pPort, | |
849 | Character ); | |
850 | } | |
851 | } | |
852 | else { | |
853 | // | |
854 | // Not a displayable character | |
855 | // | |
856 | Status = HttpSendAnsiString ( SocketFD, | |
857 | pPort, | |
858 | pReplacement ); | |
859 | } | |
860 | ||
861 | // | |
862 | // Return the operation status | |
863 | // | |
864 | return Status; | |
865 | } | |
866 | ||
867 | ||
868 | /** | |
869 | Send a buffer dump | |
870 | ||
871 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
872 | @param [in] pPort The WSDT_PORT structure address | |
873 | @param [in] ByteCount The number of bytes to display | |
874 | @param [in] pData Address of the byte array | |
875 | ||
876 | @retval EFI_SUCCESS The request was successfully processed | |
877 | ||
878 | **/ | |
879 | EFI_STATUS | |
880 | HttpSendDump ( | |
881 | IN int SocketFD, | |
882 | IN WSDT_PORT * pPort, | |
883 | IN UINTN ByteCount, | |
884 | IN CONST UINT8 * pData | |
885 | ) | |
886 | { | |
887 | INTN BytesToDisplay; | |
888 | UINT8 Character; | |
889 | INTN Index; | |
890 | INTN InitialSpaces; | |
891 | CONST UINT8 * pDataEnd; | |
892 | CONST UINT8 * pEnd; | |
893 | CONST UINT8 * pTemp; | |
894 | EFI_STATUS Status; | |
895 | ||
896 | // | |
897 | // Use for/break instead of goto | |
898 | // | |
899 | for ( ; ; ) { | |
900 | // | |
901 | // Start the field value | |
902 | // | |
903 | Status = HttpSendAnsiString ( SocketFD, | |
904 | pPort, | |
905 | "<code>" ); | |
906 | if ( EFI_ERROR ( Status )) { | |
907 | break; | |
908 | } | |
909 | ||
910 | // | |
911 | // Walk the bytes to be displayed | |
912 | // | |
913 | pEnd = &pData [ ByteCount ]; | |
914 | while ( pEnd > pData ) { | |
915 | // | |
916 | // Display the address | |
917 | // | |
918 | Status = HttpSendHexBits ( SocketFD, | |
919 | pPort, | |
920 | sizeof ( pData ) * 8, | |
921 | (UINT64)pData ); | |
922 | if ( EFI_ERROR ( Status )) { | |
923 | break; | |
924 | } | |
925 | ||
926 | // | |
927 | // Separate the address and data | |
928 | // | |
929 | Status = HttpSendByte ( SocketFD, pPort, ':' ); | |
930 | if ( EFI_ERROR ( Status )) { | |
931 | break; | |
932 | } | |
933 | ||
934 | // | |
935 | // Position the starting data correctly | |
936 | // | |
937 | InitialSpaces = (UINTN)pData; | |
938 | InitialSpaces &= BYTES_ON_A_LINE - 1; | |
939 | for ( Index = SPACES_ADDRESS_TO_DATA | |
940 | + (( 2 + SPACES_BETWEEN_BYTES ) | |
941 | * InitialSpaces ); | |
942 | 0 < Index; Index-- ) { | |
943 | Status = HttpSendAnsiString ( SocketFD, | |
944 | pPort, | |
945 | " " ); | |
946 | if ( EFI_ERROR ( Status )) { | |
947 | break; | |
948 | } | |
949 | } | |
950 | if ( EFI_ERROR ( Status )) { | |
951 | break; | |
952 | } | |
953 | ||
954 | // | |
955 | // Display the data | |
956 | // | |
957 | BytesToDisplay = pEnd - pData; | |
958 | if (( BYTES_ON_A_LINE - InitialSpaces ) < BytesToDisplay ) { | |
959 | BytesToDisplay = BYTES_ON_A_LINE - InitialSpaces; | |
960 | } | |
961 | pDataEnd = &pData [ BytesToDisplay ]; | |
962 | pTemp = pData; | |
963 | while ( pDataEnd > pTemp ) { | |
964 | Status = HttpSendHexBits ( SocketFD, | |
965 | pPort, | |
966 | 8, | |
967 | *pTemp++ ); | |
968 | if ( EFI_ERROR ( Status )) { | |
969 | break; | |
970 | } | |
971 | ||
972 | // | |
973 | // Separate the data bytes | |
974 | // | |
975 | for ( Index = SPACES_BETWEEN_BYTES; 0 < Index; Index-- ) { | |
976 | Status = HttpSendAnsiString ( SocketFD, | |
977 | pPort, | |
978 | " " ); | |
979 | if ( EFI_ERROR ( Status )) { | |
980 | break; | |
981 | } | |
982 | } | |
983 | if ( EFI_ERROR ( Status )) { | |
984 | break; | |
985 | } | |
986 | } | |
987 | if ( EFI_ERROR ( Status )) { | |
988 | break; | |
989 | } | |
990 | ||
991 | // | |
992 | // Separate the data from the ASCII display | |
993 | // | |
994 | for ( Index = (( 2 + SPACES_BETWEEN_BYTES ) | |
995 | * ( BYTES_ON_A_LINE - BytesToDisplay - InitialSpaces )) | |
996 | - SPACES_BETWEEN_BYTES | |
997 | + SPACES_DATA_TO_ASCII | |
998 | + InitialSpaces; | |
999 | 0 < Index; Index-- ) { | |
1000 | Status = HttpSendAnsiString ( SocketFD, | |
1001 | pPort, | |
1002 | " " ); | |
1003 | if ( EFI_ERROR ( Status )) { | |
1004 | break; | |
1005 | } | |
1006 | } | |
1007 | if ( EFI_ERROR ( Status )) { | |
1008 | break; | |
1009 | } | |
1010 | ||
1011 | // | |
1012 | // Display the ASCII data | |
1013 | // | |
1014 | while ( pDataEnd > pData ) { | |
1015 | Character = *pData++; | |
1016 | Status = HttpSendCharacter ( SocketFD, | |
1017 | pPort, | |
1018 | Character, | |
1019 | "." ); | |
1020 | if ( EFI_ERROR ( Status )) { | |
1021 | break; | |
1022 | } | |
1023 | } | |
1024 | if ( EFI_ERROR ( Status )) { | |
1025 | break; | |
1026 | } | |
1027 | ||
1028 | // | |
1029 | // Terminate the line | |
1030 | // | |
1031 | Status = HttpSendAnsiString ( SocketFD, | |
1032 | pPort, | |
1033 | "<br/>\r\n" ); | |
1034 | if ( EFI_ERROR ( Status )) { | |
1035 | break; | |
1036 | } | |
1037 | } | |
1038 | ||
1039 | // | |
1040 | // Terminate the field value and row | |
1041 | // | |
1042 | Status = HttpSendAnsiString ( SocketFD, | |
1043 | pPort, | |
1044 | "</code>\r\n" ); | |
1045 | break; | |
1046 | } | |
1047 | ||
1048 | // | |
1049 | // Return the operation status | |
1050 | // | |
1051 | return Status; | |
1052 | } | |
1053 | ||
1054 | ||
1055 | /** | |
1056 | Display a row containing a GUID value | |
1057 | ||
1058 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
1059 | @param [in] pPort The WSDT_PORT structure address | |
1060 | @param [in] pGuid Address of the GUID to display | |
1061 | ||
1062 | @retval EFI_SUCCESS The request was successfully processed | |
1063 | ||
1064 | **/ | |
1065 | EFI_STATUS | |
1066 | HttpSendGuid ( | |
1067 | IN int SocketFD, | |
1068 | IN WSDT_PORT * pPort, | |
1069 | IN CONST EFI_GUID * pGuid | |
1070 | ) | |
1071 | { | |
1072 | UINT32 Index; | |
1073 | EFI_STATUS Status; | |
1074 | ||
1075 | DBG_ENTER ( ); | |
1076 | ||
1077 | // | |
1078 | // Use for/break instead of goto | |
1079 | // | |
1080 | for ( ; ; ) { | |
1081 | // | |
1082 | // Display the GUID in a form found in the code | |
1083 | // | |
1084 | // E.g. 0xca16005f, 0x11ec, 0x4bdc, { 0x99, 0x97, 0x27, 0x2c, 0xa9, 0xba, 0x15, 0xe5 } | |
1085 | // | |
1086 | ||
1087 | // | |
1088 | // Display the first 32 bits | |
1089 | // | |
1090 | Status = HttpSendAnsiString ( SocketFD, | |
1091 | pPort, | |
1092 | "0x" ); | |
1093 | if ( EFI_ERROR ( Status )) { | |
1094 | break; | |
1095 | } | |
1096 | Status = HttpSendHexBits ( SocketFD, | |
1097 | pPort, | |
1098 | 32, | |
1099 | pGuid->Data1 ); | |
1100 | if ( EFI_ERROR ( Status )) { | |
1101 | break; | |
1102 | } | |
1103 | ||
1104 | // | |
1105 | // Display the second 16 bits | |
1106 | // | |
1107 | Status = HttpSendAnsiString ( SocketFD, | |
1108 | pPort, | |
1109 | ", 0x" ); | |
1110 | if ( EFI_ERROR ( Status )) { | |
1111 | break; | |
1112 | } | |
1113 | Status = HttpSendHexBits ( SocketFD, | |
1114 | pPort, | |
1115 | 16, | |
1116 | pGuid->Data2 ); | |
1117 | if ( EFI_ERROR ( Status )) { | |
1118 | break; | |
1119 | } | |
1120 | ||
1121 | // | |
1122 | // Display the thrid 16 bits | |
1123 | // | |
1124 | Status = HttpSendAnsiString ( SocketFD, | |
1125 | pPort, | |
1126 | ", 0x" ); | |
1127 | if ( EFI_ERROR ( Status )) { | |
1128 | break; | |
1129 | } | |
1130 | Status = HttpSendHexBits ( SocketFD, | |
1131 | pPort, | |
1132 | 16, | |
1133 | pGuid->Data3 ); | |
1134 | if ( EFI_ERROR ( Status )) { | |
1135 | break; | |
1136 | } | |
1137 | ||
1138 | // | |
1139 | // Place the last 64 bits in braces | |
1140 | // | |
1141 | Status = HttpSendAnsiString ( SocketFD, | |
1142 | pPort, | |
1143 | ", { 0x" ); | |
1144 | if ( EFI_ERROR ( Status )) { | |
1145 | break; | |
1146 | } | |
1147 | for ( Index = 0; 7 >= Index; Index++ ) { | |
1148 | // | |
1149 | // Display the next 8 bits | |
1150 | // | |
1151 | Status = HttpSendHexBits ( SocketFD, | |
1152 | pPort, | |
1153 | 8, | |
1154 | pGuid->Data4 [ Index ]); | |
1155 | if ( EFI_ERROR ( Status )) { | |
1156 | break; | |
1157 | } | |
1158 | ||
1159 | // | |
1160 | // Separate the bytes | |
1161 | // | |
1162 | Status = HttpSendAnsiString ( SocketFD, | |
1163 | pPort, | |
1164 | ( 7 != Index ) ? ", 0x" : " }" ); | |
1165 | if ( EFI_ERROR ( Status )) { | |
1166 | break; | |
1167 | } | |
1168 | } | |
1169 | break; | |
1170 | } | |
1171 | ||
1172 | // | |
1173 | // Return the operation status | |
1174 | // | |
1175 | DBG_EXIT_STATUS ( Status ); | |
1176 | return Status; | |
1177 | } | |
1178 | ||
1179 | ||
1180 | /** | |
1181 | Output a hex value to the HTML page | |
1182 | ||
1183 | @param [in] SocketFD Socket file descriptor | |
1184 | @param [in] pPort The WSDT_PORT structure address | |
1185 | @param [in] Bits Number of bits to display | |
1186 | @param [in] Value Value to display | |
1187 | ||
1188 | @retval EFI_SUCCESS Successfully displayed the address | |
1189 | **/ | |
1190 | EFI_STATUS | |
1191 | HttpSendHexBits ( | |
1192 | IN int SocketFD, | |
1193 | IN WSDT_PORT * pPort, | |
1194 | IN INT32 Bits, | |
1195 | IN UINT64 Value | |
1196 | ) | |
1197 | { | |
1198 | UINT32 Digit; | |
1199 | INT32 Shift; | |
1200 | EFI_STATUS Status; | |
1201 | ||
1202 | // | |
1203 | // Assume success | |
1204 | // | |
1205 | Status = EFI_SUCCESS; | |
1206 | ||
1207 | // | |
1208 | // Walk the list of divisors | |
1209 | // | |
1210 | Shift = (( Bits + 3 ) & ( ~3 )) - 4; | |
1211 | while ( 0 <= Shift ) { | |
1212 | // | |
1213 | // Determine the next digit | |
1214 | // | |
1215 | Digit = (UINT32)(( Value >> Shift ) & 0xf ); | |
1216 | if ( 10 <= Digit ) { | |
1217 | Digit += 'A' - '0' - 10; | |
1218 | } | |
1219 | ||
1220 | // | |
1221 | // Display the digit | |
1222 | // | |
1223 | Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit )); | |
1224 | if ( EFI_ERROR ( Status )) { | |
1225 | break; | |
1226 | } | |
1227 | ||
1228 | // | |
1229 | // Set the next shift | |
1230 | // | |
1231 | Shift -= 4; | |
1232 | } | |
1233 | ||
1234 | // | |
1235 | // Return the operation status | |
1236 | // | |
1237 | return Status; | |
1238 | } | |
1239 | ||
1240 | ||
1241 | /** | |
1242 | Output a hex value to the HTML page | |
1243 | ||
1244 | @param [in] SocketFD Socket file descriptor | |
1245 | @param [in] pPort The WSDT_PORT structure address | |
1246 | @param [in] Value Value to display | |
1247 | ||
1248 | @retval EFI_SUCCESS Successfully displayed the address | |
1249 | **/ | |
1250 | EFI_STATUS | |
1251 | HttpSendHexValue ( | |
1252 | IN int SocketFD, | |
1253 | IN WSDT_PORT * pPort, | |
1254 | IN UINT64 Value | |
1255 | ) | |
1256 | { | |
1257 | BOOLEAN bDisplayZeros; | |
1258 | UINT32 Digit; | |
1259 | INT32 Shift; | |
1260 | EFI_STATUS Status; | |
1261 | ||
1262 | // | |
1263 | // Assume success | |
1264 | // | |
1265 | Status = EFI_SUCCESS; | |
1266 | ||
1267 | // | |
1268 | // Walk the list of divisors | |
1269 | // | |
1270 | bDisplayZeros = FALSE; | |
1271 | Shift = 60; | |
1272 | do { | |
1273 | // | |
1274 | // Determine the next digit | |
1275 | // | |
1276 | Digit = (UINT32)(( Value >> Shift ) & 0xf ); | |
1277 | if ( 10 <= Digit ) { | |
1278 | Digit += 'A' - '0' - 10; | |
1279 | } | |
1280 | ||
1281 | // | |
1282 | // Suppress leading zeros | |
1283 | // | |
1284 | if (( 0 != Digit ) || bDisplayZeros || ( 0 == Shift )) { | |
1285 | bDisplayZeros = TRUE; | |
1286 | ||
1287 | // | |
1288 | // Display the digit | |
1289 | // | |
1290 | Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit )); | |
1291 | if ( EFI_ERROR ( Status )) { | |
1292 | break; | |
1293 | } | |
1294 | } | |
1295 | ||
1296 | // | |
1297 | // Set the next shift | |
1298 | // | |
1299 | Shift -= 4; | |
1300 | } while ( 0 <= Shift ); | |
1301 | ||
1302 | // | |
1303 | // Return the operation status | |
1304 | // | |
1305 | return Status; | |
1306 | } | |
1307 | ||
1308 | ||
1309 | /** | |
1310 | Output an IP address to the HTML page | |
1311 | ||
1312 | @param [in] SocketFD Socket file descriptor | |
1313 | @param [in] pPort The WSDT_PORT structure address | |
1314 | @param [in] pAddress Address of the socket address | |
1315 | ||
1316 | @retval EFI_SUCCESS Successfully displayed the address | |
1317 | **/ | |
1318 | EFI_STATUS | |
1319 | HttpSendIpAddress ( | |
1320 | IN int SocketFD, | |
1321 | IN WSDT_PORT * pPort, | |
1322 | IN struct sockaddr_in * pAddress | |
1323 | ) | |
1324 | { | |
1325 | EFI_STATUS Status; | |
1326 | ||
1327 | // | |
1328 | // Output the IPv4 address | |
1329 | // | |
1330 | Status = HttpSendValue ( SocketFD, pPort, (UINT8)pAddress->sin_addr.s_addr ); | |
1331 | if ( !EFI_ERROR ( Status )) { | |
1332 | Status = HttpSendByte ( SocketFD, pPort, '.' ); | |
1333 | if ( !EFI_ERROR ( Status )) { | |
1334 | Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 8 )); | |
1335 | if ( !EFI_ERROR ( Status )) { | |
1336 | Status = HttpSendByte ( SocketFD, pPort, '.' ); | |
1337 | if ( !EFI_ERROR ( Status )) { | |
1338 | Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 16 )); | |
1339 | if ( !EFI_ERROR ( Status )) { | |
1340 | Status = HttpSendByte ( SocketFD, pPort, '.' ); | |
1341 | if ( !EFI_ERROR ( Status )) { | |
1342 | Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 24 )); | |
1343 | if ( !EFI_ERROR ( Status )) { | |
1344 | // | |
1345 | // Output the port number | |
1346 | // | |
1347 | Status = HttpSendByte ( SocketFD, pPort, ':' ); | |
1348 | if ( !EFI_ERROR ( Status )) { | |
1349 | Status = HttpSendValue ( SocketFD, pPort, htons ( pAddress->sin_port )); | |
1350 | } | |
1351 | } | |
1352 | } | |
1353 | } | |
1354 | } | |
1355 | } | |
1356 | } | |
1357 | } | |
1358 | ||
1359 | // | |
1360 | // Return the operation status | |
1361 | // | |
1362 | return Status; | |
1363 | } | |
1364 | ||
1365 | ||
1366 | /** | |
1367 | Send a Unicode string | |
1368 | ||
1369 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
1370 | @param [in] pPort The WSDT_PORT structure address | |
1371 | @param [in] pString A zero terminated Unicode string | |
1372 | ||
1373 | @retval EFI_SUCCESS The request was successfully processed | |
1374 | ||
1375 | **/ | |
1376 | EFI_STATUS | |
1377 | HttpSendUnicodeString ( | |
1378 | IN int SocketFD, | |
1379 | IN WSDT_PORT * pPort, | |
1380 | IN CONST UINT16 * pString | |
1381 | ) | |
1382 | { | |
1383 | UINT8 Data; | |
1384 | UINT16 Character; | |
1385 | EFI_STATUS Status; | |
1386 | ||
1387 | // | |
1388 | // Assume success | |
1389 | // | |
1390 | Status = EFI_SUCCESS; | |
1391 | ||
1392 | // | |
1393 | // Walk the characters in he string | |
1394 | // | |
1395 | while ( 0 != ( Character = *pString++ )) { | |
1396 | // | |
1397 | // Convert the character to UTF-8 | |
1398 | // | |
1399 | if ( 0 != ( Character & 0xf800 )) { | |
1400 | // | |
1401 | // Send the upper 4 bits | |
1402 | // | |
1403 | Data = (UINT8)(( Character >> 12 ) & 0xf ); | |
1404 | Data |= 0xe0; | |
1405 | Status = HttpSendByte ( SocketFD, | |
1406 | pPort, | |
1407 | Data ); | |
1408 | if ( EFI_ERROR ( Status )) { | |
1409 | break; | |
1410 | } | |
1411 | ||
1412 | // | |
1413 | // Send the next 6 bits | |
1414 | // | |
1415 | Data = (UINT8)(( Character >> 6 ) & 0x3f ); | |
1416 | Data |= 0x80; | |
1417 | Status = HttpSendByte ( SocketFD, | |
1418 | pPort, | |
1419 | Data ); | |
1420 | if ( EFI_ERROR ( Status )) { | |
1421 | break; | |
1422 | } | |
1423 | ||
1424 | // | |
1425 | // Send the last 6 bits | |
1426 | // | |
1427 | Data = (UINT8)( Character & 0x3f ); | |
1428 | Data |= 0x80; | |
1429 | } | |
1430 | else if ( 0 != ( Character & 0x0780 )) { | |
1431 | // | |
1432 | // Send the upper 5 bits | |
1433 | // | |
1434 | Data = (UINT8)(( Character >> 6 ) & 0x1f ); | |
1435 | Data |= 0xc0; | |
1436 | Status = HttpSendByte ( SocketFD, | |
1437 | pPort, | |
1438 | Data ); | |
1439 | if ( EFI_ERROR ( Status )) { | |
1440 | break; | |
1441 | } | |
1442 | ||
1443 | // | |
1444 | // Send the last 6 bits | |
1445 | // | |
1446 | Data = (UINT8)( Character & 0x3f ); | |
1447 | Data |= 0x80; | |
1448 | } | |
1449 | else { | |
1450 | Data = (UINT8)( Character & 0x7f ); | |
1451 | } | |
1452 | ||
1453 | // | |
1454 | // Send the last data byte | |
1455 | // | |
1456 | Status = HttpSendByte ( SocketFD, | |
1457 | pPort, | |
1458 | Data ); | |
1459 | if ( EFI_ERROR ( Status )) { | |
1460 | break; | |
1461 | } | |
1462 | } | |
1463 | ||
1464 | // | |
1465 | // Return the operation status | |
1466 | // | |
1467 | return Status; | |
1468 | } | |
1469 | ||
1470 | ||
1471 | /** | |
1472 | Output a value to the HTML page | |
1473 | ||
1474 | @param [in] SocketFD Socket file descriptor | |
1475 | @param [in] pPort The WSDT_PORT structure address | |
1476 | @param [in] Value Value to display | |
1477 | ||
1478 | @retval EFI_SUCCESS Successfully displayed the address | |
1479 | **/ | |
1480 | EFI_STATUS | |
1481 | HttpSendValue ( | |
1482 | IN int SocketFD, | |
1483 | IN WSDT_PORT * pPort, | |
1484 | IN UINT64 Value | |
1485 | ) | |
1486 | { | |
1487 | BOOLEAN bDisplayZeros; | |
1488 | UINT64 Digit; | |
1489 | CONST UINT64 * pEnd; | |
1490 | CONST UINT64 * pDivisor; | |
1491 | CONST UINT64 pDivisors [ ] = { | |
1492 | 10000000000000000000L, | |
1493 | 1000000000000000000L, | |
1494 | 100000000000000000L, | |
1495 | 10000000000000000L, | |
1496 | 1000000000000000L, | |
1497 | 100000000000000L, | |
1498 | 10000000000000L, | |
1499 | 1000000000000L, | |
1500 | 100000000000L, | |
1501 | 10000000000L, | |
1502 | 1000000000L, | |
1503 | 100000000L, | |
1504 | 10000000L, | |
1505 | 1000000L, | |
1506 | 100000L, | |
1507 | 10000L, | |
1508 | 1000L, | |
1509 | 100L, | |
1510 | 10L | |
1511 | }; | |
1512 | EFI_STATUS Status; | |
1513 | UINT64 Temp; | |
1514 | ||
1515 | // | |
1516 | // Assume success | |
1517 | // | |
1518 | Status = EFI_SUCCESS; | |
1519 | ||
1520 | // | |
1521 | // Walk the list of divisors | |
1522 | // | |
1523 | bDisplayZeros = FALSE; | |
1524 | pDivisor = &pDivisors[0]; | |
1525 | pEnd = &pDivisor [ sizeof ( pDivisors ) / sizeof ( pDivisors [0])]; | |
1526 | while ( pEnd > pDivisor ) { | |
1527 | // | |
1528 | // Determine the next digit | |
1529 | // | |
1530 | Digit = Value / *pDivisor; | |
1531 | ||
1532 | // | |
1533 | // Suppress leading zeros | |
1534 | // | |
1535 | if (( 0 != Digit ) || bDisplayZeros ) { | |
1536 | bDisplayZeros = TRUE; | |
1537 | ||
1538 | // | |
1539 | // Display the digit | |
1540 | // | |
1541 | Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit )); | |
1542 | if ( EFI_ERROR ( Status )) { | |
1543 | break; | |
1544 | } | |
1545 | ||
1546 | // | |
1547 | // Determine the remainder | |
1548 | // | |
1549 | Temp = *pDivisor * Digit; | |
1550 | Value -= Temp; | |
1551 | } | |
1552 | ||
1553 | // | |
1554 | // Set the next divisor | |
1555 | // | |
1556 | pDivisor += 1; | |
1557 | } | |
1558 | ||
1559 | // | |
1560 | // Display the final digit | |
1561 | // | |
1562 | if ( !EFI_ERROR ( Status )) { | |
1563 | Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value )); | |
1564 | } | |
1565 | ||
1566 | // | |
1567 | // Return the operation status | |
1568 | // | |
1569 | return Status; | |
1570 | } |