?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

Line No. Rev Author Line
1 32 kaklik /*********************************************************************
2 *
3 * Helper Functions for Microchip TCP/IP Stack
4 *
5 *********************************************************************
6 * FileName: Helpers.C
7 * Dependencies: None
8 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
9 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
10 * Compiler: Microchip C32 v1.05 or higher
11 * Microchip C30 v3.12 or higher
12 * Microchip C18 v3.30 or higher
13 * HI-TECH PICC-18 PRO 9.63PL2 or higher
14 * Company: Microchip Technology, Inc.
15 *
16 * Software License Agreement
17 *
18 * Copyright (C) 2002-2009 Microchip Technology Inc. All rights
19 * reserved.
20 *
21 * Microchip licenses to you the right to use, modify, copy, and
22 * distribute:
23 * (i) the Software when embedded on a Microchip microcontroller or
24 * digital signal controller product ("Device") which is
25 * integrated into Licensee's product; or
26 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
27 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
28 * used in conjunction with a Microchip ethernet controller for
29 * the sole purpose of interfacing with the ethernet controller.
30 *
31 * You should refer to the license agreement accompanying this
32 * Software for additional information regarding your rights and
33 * obligations.
34 *
35 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
36 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
37 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
38 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
39 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
40 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
41 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
42 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
43 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
44 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
45 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
46 *
47 *
48 * Author Date Comment
49 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50 * Nilesh Rajbharti 5/17/01 Original (Rev 1.0)
51 * Nilesh Rajbharti 2/9/02 Cleanup
52 * Nilesh Rajbharti 6/25/02 Rewritten CalcIPChecksum() to avoid
53 * multi-byte shift operation.
54 * Howard Schlunder 2/9/05 Added hexatob(), btohexa_high(), and
55 * btohexa_low()
56 * Howard Schlunder 10/10/06 Optimized swapl()
57 * Elliott Wood 11/20/07 Added leftRotateDWORD()
58 ********************************************************************/
59 #define __HELPERS_C
60  
61 #include "TCPIP Stack/TCPIP.h"
62  
63  
64 /*****************************************************************************
65 Function:
66 DWORD GenerateRandomDWORD(void)
67  
68 Summary:
69 Generates a random DWORD.
70  
71 Description:
72 This function generates a random 32-bit integer. It collects
73 randomness by comparing the A/D converter's internal R/C oscillator
74 clock with our main system clock. By passing collected entropy to the
75 C rand()/srand() functions, the output is normalized to meet statistical
76 randomness tests.
77  
78 Precondition:
79 None
80  
81 Parameters:
82 None
83  
84 Returns:
85 Random 32-bit number.
86  
87 Side Effects:
88 This function uses the A/D converter (and so you must disable
89 interrupts if you use the A/D converted in your ISR). The C rand()
90 function will be reseeded, and Timer0 (PIC18) and Timer1 (PIC24,
91 dsPIC, and PIC32) will be used. TMR#H:TMR#L will have a new value.
92 Note that this is the same timer used by the Tick module.
93  
94 Remarks:
95 This function times out after 1 second of attempting to generate the
96 random DWORD. In such a case, the output may not be truly random.
97 Typically, this function executes in around 500,000 instruction cycles.
98  
99 The intent of this function is to produce statistically random and
100 cryptographically secure random number. Whether or not this is true on
101 all (or any) devices/voltages/temperatures is not tested.
102 ***************************************************************************/
103 DWORD GenerateRandomDWORD(void)
104 {
105 BYTE vBitCount;
106 WORD w, wTime, wLastValue;
107 DWORD dwTotalTime;
108 DWORD dwRandomResult;
109  
110 #if defined __18CXX
111 {
112 BYTE ADCON0Save, ADCON2Save;
113 BYTE T0CONSave, TMR0HSave, TMR0LSave;
114  
115 // Save hardware SFRs
116 ADCON0Save = ADCON0;
117 ADCON2Save = ADCON2;
118 T0CONSave = T0CON;
119 TMR0LSave = TMR0L;
120 TMR0HSave = TMR0H;
121  
122 // Set up Timer and A/D converter module
123 ADCON0 = 0x01; // Turn on the A/D module
124 ADCON2 = 0x3F; // 20 Tad acquisition, Frc A/D clock used for conversion
125 T0CON = 0x88; // TMR0ON = 1, no prescalar
126 vBitCount = 0;
127 dwTotalTime = 0;
128 wLastValue = 0;
129 dwRandomResult = rand();
130 while(1)
131 {
132 // Time the duration of an A/D acquisition and conversion
133 TMR0H = 0x00;
134 TMR0L = 0x00;
135 ADCON0bits.GO = 1;
136 ClrWdt();
137 while(ADCON0bits.GO);
138 ((BYTE*)&wTime)[0] = TMR0L;
139 ((BYTE*)&wTime)[1] = TMR0H;
140 w = rand();
141  
142 // Wait no longer than 1 second obtaining entropy
143 dwTotalTime += wTime;
144 if(dwTotalTime >= GetInstructionClock())
145 {
146 dwRandomResult ^= rand() | (((DWORD)rand())<<15ul) | (((DWORD)rand())<<30ul);
147 break;
148 }
149  
150 // Keep sampling if minimal entropy was likely obtained this round
151 if(wLastValue == wTime)
152 continue;
153  
154 // Add this entropy into the pseudo random number generator by reseeding
155 srand(w + (wLastValue - wTime));
156 wLastValue = wTime;
157  
158 // Accumulate at least 32 bits of randomness over time
159 dwRandomResult <<= 1;
160 if(rand() >= 16384)
161 dwRandomResult |= 0x1;
162  
163 // See if we've collected a fair amount of entropy and can quit early
164 if(++vBitCount == 0u)
165 break;
166 }
167  
168 // Restore hardware SFRs
169 ADCON0 = ADCON0Save;
170 ADCON2 = ADCON2Save;
171 TMR0H = TMR0HSave;
172 TMR0L = TMR0LSave;
173 T0CON = T0CONSave;
174 }
175 #else
176 {
177 WORD AD1CON1Save, AD1CON2Save, AD1CON3Save;
178 WORD T1CONSave, PR1Save;
179  
180 // Save hardware SFRs
181 AD1CON1Save = AD1CON1;
182 AD1CON2Save = AD1CON2;
183 AD1CON3Save = AD1CON3;
184 T1CONSave = T1CON;
185 PR1Save = PR1;
186  
187 // Set up Timer and A/D converter module
188 AD1CON1 = 0x80E4; // Turn on the A/D module, auto-convert
189 AD1CON2 = 0x003F; // Interrupt after every 16th sample/convert
190 AD1CON3 = 0x9F00; // Frc A/D clock, 31 Tad acquisition
191 T1CON = 0x8000; // TON = 1, no prescalar
192 PR1 = 0xFFFF; // Don't clear timer early
193 vBitCount = 0;
194 dwTotalTime = 0;
195 wLastValue = 0;
196 dwRandomResult = rand();
197 while(1)
198 {
199 ClrWdt();
200 #if defined(__C30__)
201 while(!IFS0bits.AD1IF);
202 #else
203 while(!IFS1bits.AD1IF);
204 #endif
205 wTime = TMR1;
206 TMR1 = 0x0000;
207  
208 #if defined(__C30__)
209 IFS0bits.AD1IF = 0;
210 #else
211 IFS1bits.AD1IF = 0;
212 #endif
213 w = rand();
214  
215 // Wait no longer than 1 second obtaining entropy
216 dwTotalTime += wTime;
217 if(dwTotalTime >= GetInstructionClock())
218 {
219 dwRandomResult ^= rand() | (((DWORD)rand())<<15) | (((DWORD)rand())<<30);
220 break;
221 }
222  
223 // Keep sampling if minimal entropy was likely obtained this round
224 if(wLastValue == wTime)
225 continue;
226  
227 // Add this entropy into the pseudo random number generator by reseeding
228 srand(w + (wLastValue - wTime));
229 wLastValue = wTime;
230  
231 // Accumulate at least 32 bits of randomness over time
232 dwRandomResult <<= 1;
233 if(rand() >= 16384)
234 dwRandomResult |= 0x1;
235  
236 // See if we've collected a fair amount of entropy and can quit early
237 if(++vBitCount == 0u)
238 break;
239 }
240  
241  
242 // Restore hardware SFRs
243 AD1CON1 = AD1CON1Save;
244 AD1CON2 = AD1CON2Save;
245 AD1CON3 = AD1CON3Save;
246 T1CON = T1CONSave;
247 PR1 = PR1Save;
248 }
249 #endif
250  
251 return dwRandomResult;
252 }
253  
254  
255 #if defined(STACK_USE_HTTP_SERVER)
256 /*****************************************************************************
257 Function:
258 void UnencodeURL(BYTE* URL)
259  
260 Summary:
261 Decodes a URL-encoded string.
262  
263 Description:
264 This function is deprecated except for use with HTTP Classic. It
265 attempts to decode a URL encoded string, converting all hex escape
266 sequences into a literal byte. However, it is inefficient over long
267 strings and does not handle URL-encoded data strings ('&' and '=').
268  
269 Precondition:
270 None
271  
272 Parameters:
273 URL - the null-terminated string to decode
274  
275 Returns:
276 None
277 ***************************************************************************/
278 void UnencodeURL(BYTE* URL)
279 {
280 BYTE *Right, *Copy;
281 WORD_VAL Number;
282  
283 while((Right = (BYTE*)strchr((char*)URL, '%')))
284 {
285 // Make sure the string is long enough
286 if(Right[1] == '\0')
287 break;
288 if(Right[2] == '\0')
289 break;
290  
291 // Update the string in place
292 Number.v[0] = Right[2];
293 Number.v[1] = Right[1];
294 *Right++ = hexatob(Number);
295 URL = Right;
296  
297 // Remove two blank spots by shifting all remaining characters right two
298 Copy = Right + 2;
299 while((*Right++ = *Copy++));
300 }
301 }
302 #endif
303  
304  
305 /*****************************************************************************
306 Function:
307 BOOL StringToIPAddress(BYTE* str, IP_ADDR* IPAddress)
308  
309 Summary:
310 Converts a string to an IP address
311  
312 Description:
313 This function parses a dotted-quad decimal IP address string into an
314 IP_ADDR struct. The output result is big-endian.
315  
316 Precondition:
317 None
318  
319 Parameters:
320 str - Pointer to a dotted-quad IP address string
321 IPAddress - Pointer to IP_ADDR in which to store the result
322  
323 Return Values:
324 TRUE - an IP address was successfully decoded
325 FALSE - no IP address could be found, or the format was incorrect
326 ***************************************************************************/
327 BOOL StringToIPAddress(BYTE* str, IP_ADDR* IPAddress)
328 {
329 DWORD_VAL dwVal;
330 BYTE i, charLen, currentOctet;
331  
332 charLen = 0;
333 currentOctet = 0;
334 dwVal.Val = 0;
335 while((i = *str++))
336 {
337 if(currentOctet > 3u)
338 break;
339  
340 i -= '0';
341  
342  
343 // Validate the character is a numerical digit or dot, depending on location
344 if(charLen == 0u)
345 {
346 if(i > 9u)
347 return FALSE;
348 }
349 else if(charLen == 3u)
350 {
351 if(i != (BYTE)('.' - '0'))
352 return FALSE;
353  
354 if(dwVal.Val > 0x00020505ul)
355 return FALSE;
356  
357 IPAddress->v[currentOctet++] = dwVal.v[2]*((BYTE)100) + dwVal.v[1]*((BYTE)10) + dwVal.v[0];
358 charLen = 0;
359 dwVal.Val = 0;
360 continue;
361 }
362 else
363 {
364 if(i == (BYTE)('.' - '0'))
365 {
366 if(dwVal.Val > 0x00020505ul)
367 return FALSE;
368  
369 IPAddress->v[currentOctet++] = dwVal.v[2]*((BYTE)100) + dwVal.v[1]*((BYTE)10) + dwVal.v[0];
370 charLen = 0;
371 dwVal.Val = 0;
372 continue;
373 }
374 if(i > 9u)
375 return FALSE;
376 }
377  
378 charLen++;
379 dwVal.Val <<= 8;
380 dwVal.v[0] = i;
381 }
382  
383 // Make sure the very last character is a valid termination character
384 // (i.e., not more hostname, which could be legal and not an IP
385 // address as in "10.5.13.233.picsaregood.com"
386 if(i != 0u && i != '/' && i != '\r' && i != '\n' && i != ' ' && i != '\t')
387 return FALSE;
388  
389 // Verify and convert the last octet and return the result
390 if(dwVal.Val > 0x00020505ul)
391 return FALSE;
392  
393 IPAddress->v[3] = dwVal.v[2]*((BYTE)100) + dwVal.v[1]*((BYTE)10) + dwVal.v[0];
394  
395 return TRUE;
396 }
397  
398 /*****************************************************************************
399 Function:
400 BOOL ROMStringToIPAddress(ROM BYTE* str, IP_ADDR* IPAddress)
401  
402 Summary:
403 Converts a string to an IP address
404  
405 Description:
406 This function parses a dotted-quad decimal IP address string into an
407 IP_ADDR struct. The output result is big-endian.
408  
409 Precondition:
410 None
411  
412 Parameters:
413 str - Pointer to a dotted-quad IP address string
414 IPAddress - Pointer to IP_ADDR in which to store the result
415  
416 Return Values:
417 TRUE - an IP address was successfully decoded
418 FALSE - no IP address could be found, or the format was incorrect
419  
420 Remarks:
421 This function is aliased to StringToIPAddress on non-PIC18 platforms.
422 ***************************************************************************/
423 #if defined(__18CXX)
424 BOOL ROMStringToIPAddress(ROM BYTE* str, IP_ADDR* IPAddress)
425 {
426 DWORD_VAL dwVal;
427 BYTE i, charLen, currentOctet;
428  
429 charLen = 0;
430 currentOctet = 0;
431 dwVal.Val = 0;
432 while(i = *str++)
433 {
434 if(currentOctet > 3u)
435 break;
436  
437 i -= '0';
438  
439  
440 // Validate the character is a numerical digit or dot, depending on location
441 if(charLen == 0u)
442 {
443 if(i > 9u)
444 return FALSE;
445 }
446 else if(charLen == 3u)
447 {
448 if(i != (BYTE)('.' - '0'))
449 return FALSE;
450  
451 if(dwVal.Val > 0x00020505ul)
452 return FALSE;
453  
454 IPAddress->v[currentOctet++] = dwVal.v[2]*((BYTE)100) + dwVal.v[1]*((BYTE)10) + dwVal.v[0];
455 charLen = 0;
456 dwVal.Val = 0;
457 continue;
458 }
459 else
460 {
461 if(i == (BYTE)('.' - '0'))
462 {
463 if(dwVal.Val > 0x00020505ul)
464 return FALSE;
465  
466 IPAddress->v[currentOctet++] = dwVal.v[2]*((BYTE)100) + dwVal.v[1]*((BYTE)10) + dwVal.v[0];
467 charLen = 0;
468 dwVal.Val = 0;
469 continue;
470 }
471 if(i > 9u)
472 return FALSE;
473 }
474  
475 charLen++;
476 dwVal.Val <<= 8;
477 dwVal.v[0] = i;
478 }
479  
480 // Make sure the very last character is a valid termination character
481 // (i.e., not more hostname, which could be legal and not an IP
482 // address as in "10.5.13.233.picsaregood.com"
483 if(i != 0u && i != '/' && i != '\r' && i != '\n' && i != ' ' && i != '\t')
484 return FALSE;
485  
486 // Verify and convert the last octet and return the result
487 if(dwVal.Val > 0x00020505ul)
488 return FALSE;
489  
490 IPAddress->v[3] = dwVal.v[2]*((BYTE)100) + dwVal.v[1]*((BYTE)10) + dwVal.v[0];
491  
492 return TRUE;
493 }
494 #endif
495  
496  
497  
498 /*****************************************************************************
499 Function:
500 WORD Base64Decode(BYTE* cSourceData, WORD wSourceLen,
501 BYTE* cDestData, WORD wDestLen)
502  
503 Description:
504 Decodes a Base-64 array to its literal representation.
505  
506 Precondition:
507 None
508  
509 Parameters:
510 cSourceData - Pointer to a string of Base-64 encoded data
511 wSourceLen - Length of the Base-64 source data
512 cDestData - Pointer to write the decoded data
513 wSourceLen - Maximum length that can be written to cDestData
514  
515 Returns:
516 Number of decoded bytes written to cDestData.
517  
518 Remarks:
519 This function is binary safe and will ignore invalid characters (CR, LF,
520 etc). If cSourceData is equal to cDestData, the data will be converted
521 in-place. If cSourceData is not equal to cDestData, but the regions
522 overlap, the behavior is undefined.
523  
524 Decoded data is always at least 1/4 smaller than the source data.
525 ***************************************************************************/
526 #if defined(STACK_USE_BASE64_DECODE)
527 WORD Base64Decode(BYTE* cSourceData, WORD wSourceLen, BYTE* cDestData, WORD wDestLen)
528 {
529 BYTE i;
530 BYTE vByteNumber;
531 BOOL bPad;
532 WORD wBytesOutput;
533  
534 vByteNumber = 0;
535 wBytesOutput = 0;
536  
537 // Loop over all provided bytes
538 while(wSourceLen--)
539 {
540 // Fetch a Base64 byte and decode it to the original 6 bits
541 i = *cSourceData++;
542 bPad = (i == '=');
543 if(i >= 'A' && i <= 'Z') // Regular data
544 i -= 'A' - 0;
545 else if(i >= 'a' && i <= 'z')
546 i -= 'a' - 26;
547 else if(i >= '0' && i <= '9')
548 i -= '0' - 52;
549 else if(i == '+' || i == '-')
550 i = 62;
551 else if(i == '/' || i == '_')
552 i = 63;
553 else // Skip all padding (=) and non-Base64 characters
554 continue;
555  
556  
557 // Write the 6 bits to the correct destination location(s)
558 if(vByteNumber == 0u)
559 {
560 if(bPad) // Padding here would be illegal, treat it as a non-Base64 chacter and just skip over it
561 continue;
562 vByteNumber++;
563 if(wBytesOutput >= wDestLen)
564 break;
565 wBytesOutput++;
566 *cDestData = i << 2;
567 }
568 else if(vByteNumber == 1u)
569 {
570 vByteNumber++;
571 *cDestData++ |= i >> 4;
572 if(wBytesOutput >= wDestLen)
573 break;
574 if(bPad)
575 continue;
576 wBytesOutput++;
577 *cDestData = i << 4;
578 }
579 else if(vByteNumber == 2u)
580 {
581 vByteNumber++;
582 *cDestData++ |= i >> 2;
583 if(wBytesOutput >= wDestLen)
584 break;
585 if(bPad)
586 continue;
587 wBytesOutput++;
588 *cDestData = i << 6;
589 }
590 else if(vByteNumber == 3u)
591 {
592 vByteNumber = 0;
593 *cDestData++ |= i;
594 }
595 }
596  
597 return wBytesOutput;
598 }
599 #endif // #if defined(STACK_USE_BASE64_DECODE)
600  
601  
602 /*****************************************************************************
603 Function:
604 WORD Base64Encode(BYTE* cSourceData, WORD wSourceLen,
605 BYTE* cDestData, WORD wDestLen)
606  
607 Description:
608 Encodes a binary array to Base-64.
609  
610 Precondition:
611 None
612  
613 Parameters:
614 cSourceData - Pointer to a string of binary data
615 wSourceLen - Length of the binary source data
616 cDestData - Pointer to write the Base-64 encoded data
617 wSourceLen - Maximum length that can be written to cDestData
618  
619 Returns:
620 Number of encoded bytes written to cDestData. This will always be
621 a multiple of 4.
622  
623 Remarks:
624 Encoding cannot be performed in-place. If cSourceData overlaps with
625 cDestData, the behavior is undefined.
626  
627 Encoded data is always at least 1/3 larger than the source data. It may
628 be 1 or 2 bytes larger than that.
629 ***************************************************************************/
630 #if defined(STACK_USE_BASE64_ENCODE) || defined(STACK_USE_SMTP_CLIENT) || defined(STACK_USE_DYNAMICDNS_CLIENT)
631 WORD Base64Encode(BYTE* cSourceData, WORD wSourceLen, BYTE* cDestData, WORD wDestLen)
632 {
633 BYTE i, j;
634 BYTE vOutput[4];
635 WORD wOutputLen;
636  
637 wOutputLen = 0;
638 while(wDestLen >= 4u)
639 {
640 // Start out treating the output as all padding
641 vOutput[0] = 0xFF;
642 vOutput[1] = 0xFF;
643 vOutput[2] = 0xFF;
644 vOutput[3] = 0xFF;
645  
646 // Get 3 input octets and split them into 4 output hextets (6-bits each)
647 if(wSourceLen == 0u)
648 break;
649 i = *cSourceData++;
650 wSourceLen--;
651 vOutput[0] = (i & 0xFC)>>2;
652 vOutput[1] = (i & 0x03)<<4;
653 if(wSourceLen)
654 {
655 i = *cSourceData++;
656 wSourceLen--;
657 vOutput[1] |= (i & 0xF0)>>4;
658 vOutput[2] = (i & 0x0F)<<2;
659 if(wSourceLen)
660 {
661 i = *cSourceData++;
662 wSourceLen--;
663 vOutput[2] |= (i & 0xC0)>>6;
664 vOutput[3] = i & 0x3F;
665 }
666 }
667  
668 // Convert hextets into Base 64 alphabet and store result
669 for(i = 0; i < 4u; i++)
670 {
671 j = vOutput[i];
672  
673 if(j <= 25u)
674 j += 'A' - 0;
675 else if(j <= 51u)
676 j += 'a' - 26;
677 else if(j <= 61u)
678 j += '0' - 52;
679 else if(j == 62u)
680 j = '+';
681 else if(j == 63u)
682 j = '/';
683 else // Padding
684 j = '=';
685  
686 *cDestData++ = j;
687 }
688  
689 // Update counters
690 wDestLen -= 4;
691 wOutputLen += 4;
692 }
693  
694 return wOutputLen;
695 }
696 #endif // #if defined(STACK_USE_BASE64_ENCODE) || defined(STACK_USE_SMTP) || defined(STACK_USE_DYNAMICDNS_CLIENT)
697  
698  
699 /*****************************************************************************
700 Function:
701 void uitoa(WORD Value, BYTE* Buffer)
702  
703 Summary:
704 Converts an unsigned integer to a decimal string.
705  
706 Description:
707 Converts a 16-bit unsigned integer to a null-terminated decimal string.
708  
709 Precondition:
710 None
711  
712 Parameters:
713 Value - The number to be converted
714 Buffer - Pointer in which to store the converted string
715  
716 Returns:
717 None
718 ***************************************************************************/
719 void uitoa(WORD Value, BYTE* Buffer)
720 {
721 BYTE i;
722 WORD Digit;
723 WORD Divisor;
724 BOOL Printed = FALSE;
725  
726 if(Value)
727 {
728 for(i = 0, Divisor = 10000; i < 5u; i++)
729 {
730 Digit = Value/Divisor;
731 if(Digit || Printed)
732 {
733 *Buffer++ = '0' + Digit;
734 Value -= Digit*Divisor;
735 Printed = TRUE;
736 }
737 Divisor /= 10;
738 }
739 }
740 else
741 {
742 *Buffer++ = '0';
743 }
744  
745 *Buffer = '\0';
746 }
747  
748 /*****************************************************************************
749 Function:
750 void ultoa(DWORD Value, BYTE* Buffer)
751  
752 Summary:
753 Converts an unsigned integer to a decimal string.
754  
755 Description:
756 Converts a 32-bit unsigned integer to a null-terminated decimal string.
757  
758 Precondition:
759 None
760  
761 Parameters:
762 Value - The number to be converted
763 Buffer - Pointer in which to store the converted string
764  
765 Returns:
766 None
767 ***************************************************************************/
768 // HI-TECH PICC-18 PRO 9.63 already has a ultoa() library function
769 #if !defined(__18CXX) && !defined(HI_TECH_C)
770 void ultoa(DWORD Value, BYTE* Buffer)
771 {
772 BYTE i;
773 DWORD Digit;
774 DWORD Divisor;
775 BOOL Printed = FALSE;
776  
777 if(Value)
778 {
779 for(i = 0, Divisor = 1000000000; i < 10; i++)
780 {
781 Digit = Value/Divisor;
782 if(Digit || Printed)
783 {
784 *Buffer++ = '0' + Digit;
785 Value -= Digit*Divisor;
786 Printed = TRUE;
787 }
788 Divisor /= 10;
789 }
790 }
791 else
792 {
793 *Buffer++ = '0';
794 }
795  
796 *Buffer = '\0';
797 }
798 #endif
799  
800 /*****************************************************************************
801 Function:
802 BYTE hexatob(WORD_VAL AsciiChars)
803  
804 Summary:
805 Converts a hex string to a single byte.
806  
807 Description:
808 Converts a two-character ASCII hex string to a single packed byte.
809  
810 Precondition:
811 None
812  
813 Parameters:
814 AsciiChars - WORD_VAL where .v[0] is the ASCII value for the lower nibble
815 and .v[1] is the ASCII value for the upper nibble. Each
816 must range from '0'-'9', 'A'-'F', or 'a'-'f'.
817  
818 Returns:
819 Resulting packed byte 0x00 - 0xFF.
820 ***************************************************************************/
821 BYTE hexatob(WORD_VAL AsciiChars)
822 {
823 // Convert lowercase to uppercase
824 if(AsciiChars.v[1] > 'F')
825 AsciiChars.v[1] -= 'a'-'A';
826 if(AsciiChars.v[0] > 'F')
827 AsciiChars.v[0] -= 'a'-'A';
828  
829 // Convert 0-9, A-F to 0x0-0xF
830 if(AsciiChars.v[1] > '9')
831 AsciiChars.v[1] -= 'A' - 10;
832 else
833 AsciiChars.v[1] -= '0';
834  
835 if(AsciiChars.v[0] > '9')
836 AsciiChars.v[0] -= 'A' - 10;
837 else
838 AsciiChars.v[0] -= '0';
839  
840 // Concatenate
841 return (AsciiChars.v[1]<<4) | AsciiChars.v[0];
842 }
843  
844 /*****************************************************************************
845 Function:
846 BYTE btohexa_high(BYTE b)
847  
848 Summary:
849 Converts the upper nibble of a binary value to a hexadecimal ASCII byte.
850  
851 Description:
852 Converts the upper nibble of a binary value to a hexadecimal ASCII byte.
853 For example, btohexa_high(0xAE) will return 'A'.
854  
855 Precondition:
856 None
857  
858 Parameters:
859 b - the byte to convert
860  
861 Returns:
862 The upper hexadecimal ASCII byte '0'-'9' or 'A'-'F'.
863 ***************************************************************************/
864 BYTE btohexa_high(BYTE b)
865 {
866 b >>= 4;
867 return (b>0x9u) ? b+'A'-10:b+'0';
868 }
869  
870 /*****************************************************************************
871 Function:
872 BYTE btohexa_high(BYTE b)
873  
874 Summary:
875 Converts the lower nibble of a binary value to a hexadecimal ASCII byte.
876  
877 Description:
878 Converts the lower nibble of a binary value to a hexadecimal ASCII byte.
879 For example, btohexa_high(0xAE) will return 'E'.
880  
881 Precondition:
882 None
883  
884 Parameters:
885 b - the byte to convert
886  
887 Returns:
888 The lower hexadecimal ASCII byte '0'-'9' or 'A'-'F'.
889 ***************************************************************************/
890 BYTE btohexa_low(BYTE b)
891 {
892 b &= 0x0F;
893 return (b>9u) ? b+'A'-10:b+'0';
894 }
895  
896 /*****************************************************************************
897 Function:
898 signed char stricmppgm2ram(BYTE* a, ROM BYTE* b)
899  
900 Summary:
901 Case-insensitive comparison of a string in RAM to a string in ROM.
902  
903 Description:
904 Performs a case-insensitive comparison of a string in RAM to a string
905 in ROM. This function performs identically to strcmppgm2ram, except that
906 the comparison is not case-sensitive.
907  
908 Precondition:
909 None
910  
911 Parameters:
912 a - Pinter to tring in RAM
913 b - Pointer to string in ROM
914  
915 Return Values:
916 \-1 - a < b
917  
918 1 - a > b
919 ***************************************************************************/
920 signed char stricmppgm2ram(BYTE* a, ROM BYTE* b)
921 {
922 BYTE cA, cB;
923  
924 // Load first two characters
925 cA = *a;
926 cB = *b;
927  
928 // Loop until one string terminates
929 while(cA != '\0' && cB != '\0')
930 {
931 // Shift case if necessary
932 if(cA >= 'a' && cA <= 'z')
933 cA -= 'a' - 'A';
934 if(cB >= 'a' && cB <= 'z')
935 cB -= 'a' - 'A';
936  
937 // Compare
938 if(cA > cB)
939 return 1;
940 if(cA < cB)
941 return -1;
942  
943 // Characters matched, so continue
944 a++;
945 b++;
946 cA = *a;
947 cB = *b;
948 }
949  
950 // See if one string terminated first
951 if(cA > cB)
952 return 1;
953 if(cA < cB)
954 return -1;
955  
956 // Strings match
957 return 0;
958 }
959  
960 /*****************************************************************************
961 Function:
962 WORD swaps(WORD v)
963  
964 Description:
965 Swaps the endian-ness of a WORD.
966  
967 Precondition:
968 None
969  
970 Parameters:
971 v - the WORD to swap
972  
973 Returns:
974 The swapped version of v.
975 ***************************************************************************/
976 WORD swaps(WORD v)
977 {
978 WORD_VAL t;
979 BYTE b;
980  
981 t.Val = v;
982 b = t.v[1];
983 t.v[1] = t.v[0];
984 t.v[0] = b;
985  
986 return t.Val;
987 }
988  
989 /*****************************************************************************
990 Function:
991 DWORD swapl(DWORD v)
992  
993 Description:
994 Swaps the endian-ness of a DWORD.
995  
996 Precondition:
997 None
998  
999 Parameters:
1000 v - the DWORD to swap
1001  
1002 Returns:
1003 The swapped version of v.
1004 ***************************************************************************/
1005 DWORD swapl(DWORD v)
1006 {
1007 // Swap bytes 0 and 3
1008 ((DWORD_VAL*)&v)->v[0] ^= ((DWORD_VAL*)&v)->v[3];
1009 ((DWORD_VAL*)&v)->v[3] ^= ((DWORD_VAL*)&v)->v[0];
1010 ((DWORD_VAL*)&v)->v[0] ^= ((DWORD_VAL*)&v)->v[3];
1011  
1012 // Swap bytes 1 and 2
1013 ((DWORD_VAL*)&v)->v[1] ^= ((DWORD_VAL*)&v)->v[2];
1014 ((DWORD_VAL*)&v)->v[2] ^= ((DWORD_VAL*)&v)->v[1];
1015 ((DWORD_VAL*)&v)->v[1] ^= ((DWORD_VAL*)&v)->v[2];
1016  
1017 return v;
1018 }
1019  
1020  
1021 /*****************************************************************************
1022 Function:
1023 WORD CalcIPChecksum(BYTE* buffer, WORD count)
1024  
1025 Summary:
1026 Calculates an IP checksum value.
1027  
1028 Description:
1029 This function calculates an IP checksum over an array of input data. The
1030 checksum is the 16-bit one's complement of one's complement sum of all
1031 words in the data (with zero-padding if an odd number of bytes are
1032 summed). This checksum is defined in RFC 793.
1033  
1034 Precondition:
1035 buffer is WORD aligned (even memory address) on 16- and 32-bit PICs.
1036  
1037 Parameters:
1038 buffer - pointer to the data to be checksummed
1039 count - number of bytes to be checksummed
1040  
1041 Returns:
1042 The calculated checksum.
1043  
1044 Internal:
1045 This function could be improved to do 32-bit sums on PIC32 platforms.
1046 ***************************************************************************/
1047 WORD CalcIPChecksum(BYTE* buffer, WORD count)
1048 {
1049 WORD i;
1050 WORD *val;
1051 union
1052 {
1053 WORD w[2];
1054 DWORD dw;
1055 } sum;
1056  
1057 i = count >> 1;
1058 val = (WORD*)buffer;
1059  
1060 // Calculate the sum of all words
1061 sum.dw = 0x00000000ul;
1062 while(i--)
1063 sum.dw += (DWORD)*val++;
1064  
1065 // Add in the sum of the remaining byte, if present
1066 if(count & 0x1)
1067 sum.dw += (DWORD)*(BYTE*)val;
1068  
1069 // Do an end-around carry (one's complement arrithmatic)
1070 sum.dw = sum.w[0] + sum.w[1];
1071  
1072 // Do another end-around carry in case if the prior add
1073 // caused a carry out
1074 sum.w[0] += sum.w[1];
1075  
1076 // Return the resulting checksum
1077 return ~sum.w[0];
1078 }
1079  
1080  
1081 /*****************************************************************************
1082 Function:
1083 WORD CalcIPBufferChecksum(WORD len)
1084  
1085 Summary:
1086 Calculates an IP checksum in the MAC buffer itself.
1087  
1088 Description:
1089 This function calculates an IP checksum over an array of input data
1090 existing in the MAC buffer. The checksum is the 16-bit one's complement
1091 of one's complement sum of all words in the data (with zero-padding if
1092 an odd number of bytes are summed). This checksum is defined in RFC 793.
1093  
1094 Precondition:
1095 TCP is initialized and the MAC buffer pointer is set to the start of
1096 the buffer.
1097  
1098 Parameters:
1099 len - number of bytes to be checksummed
1100  
1101 Returns:
1102 The calculated checksum.
1103  
1104 Remarks:
1105 All Microchip MACs should perform this function in hardware.
1106 ***************************************************************************/
1107 #if defined(NON_MCHP_MAC)
1108 WORD CalcIPBufferChecksum(WORD len)
1109 {
1110 DWORD_VAL Checksum = {0x00000000ul};
1111 WORD ChunkLen;
1112 BYTE DataBuffer[20]; // Must be an even size
1113 WORD *DataPtr;
1114  
1115 while(len)
1116 {
1117 // Obtain a chunk of data (less SPI overhead compared
1118 // to requesting one byte at a time)
1119 ChunkLen = len > sizeof(DataBuffer) ? sizeof(DataBuffer) : len;
1120 MACGetArray(DataBuffer, ChunkLen);
1121 len -= ChunkLen;
1122  
1123 // Take care of a last odd numbered data byte
1124 if(((WORD_VAL*)&ChunkLen)->bits.b0)
1125 {
1126 DataBuffer[ChunkLen] = 0x00;
1127 ChunkLen++;
1128 }
1129  
1130 // Calculate the checksum over this chunk
1131 DataPtr = (WORD*)&DataBuffer[0];
1132 while(ChunkLen)
1133 {
1134 Checksum.Val += *DataPtr++;
1135 ChunkLen -= 2;
1136 }
1137 }
1138  
1139 // Do an end-around carry (one's complement arrithmatic)
1140 Checksum.Val = (DWORD)Checksum.w[0] + (DWORD)Checksum.w[1];
1141  
1142 // Do another end-around carry in case if the prior add
1143 // caused a carry out
1144 Checksum.w[0] += Checksum.w[1];
1145  
1146 // Return the resulting checksum
1147 return ~Checksum.w[0];
1148 }
1149 #endif
1150  
1151 /*****************************************************************************
1152 Function:
1153 char* strupr(char* s)
1154  
1155 Summary:
1156 Converts a string to uppercase.
1157  
1158 Description:
1159 This function converts strings to uppercase on platforms that do not
1160 already have this function defined. All lower-case characters are
1161 converted, an characters not included in 'a'-'z' are left as-is.
1162  
1163 Precondition:
1164 None
1165  
1166 Parameters:
1167 s - the null-terminated string to be converted.
1168  
1169 Returns:
1170 Pointer to the initial string.
1171 ***************************************************************************/
1172 #if !defined(__18CXX) || defined(HI_TECH_C)
1173 char* strupr(char* s)
1174 {
1175 char c;
1176 char *t;
1177  
1178 t = s;
1179 while( (c = *t) )
1180 {
1181 if(c >= 'a' && c <= 'z')
1182 {
1183 *t -= ('a' - 'A');
1184 }
1185 t++;
1186 }
1187 return s;
1188 }
1189 #endif
1190  
1191 #if defined(__18CXX)
1192 // Make this variable global for the following function.
1193 // Hi-Tech PICC18 cannot access local function variables from inline asm.
1194 DWORD_VAL toRotate;
1195 #endif
1196  
1197 /*****************************************************************************
1198 Function:
1199 DWORD leftRotateDWORD(DWORD val, BYTE bits)
1200  
1201 Summary:
1202 Left-rotates a DWORD.
1203  
1204 Description:
1205 This function rotates the bits in a 32-bit DWORD left by a specific
1206 number of bits.
1207  
1208 Precondition:
1209 None
1210  
1211 Parameters:
1212 val - the DWORD to be rotated
1213 bits - the number of bits by which to shift
1214  
1215 Returns:
1216 Rotated DWORD value.
1217  
1218 Remarks:
1219 This function is only implemented on 8-bit platforms for now. The
1220 8-bit compilers generate excessive code for this function, while C30
1221 and C32 already generate compact code. Those compilers are served
1222 by a macro defined in Helpers.h.
1223 ***************************************************************************/
1224 #if defined(__18CXX)
1225 DWORD leftRotateDWORD(DWORD val, BYTE bits)
1226 {
1227 BYTE i, t;
1228 //DWORD_VAL toRotate;
1229 toRotate.Val = val;
1230  
1231 for(i = bits; i >= 8u; i -= 8)
1232 {
1233 t = toRotate.v[3];
1234 toRotate.v[3] = toRotate.v[2];
1235 toRotate.v[2] = toRotate.v[1];
1236 toRotate.v[1] = toRotate.v[0];
1237 toRotate.v[0] = t;
1238 }
1239  
1240  
1241 #if defined(HI_TECH_C)
1242 for(; i != 0; i--)
1243 {
1244 asm("movlb (_toRotate)>>8");
1245 //asm("bcf _STATUS,0,C");
1246 asm("bcf 0xFD8,0,C"); // HI-TECH PICC-18 PRO 9.63PL1 doesn't define _STATUS
1247 asm("btfsc (_toRotate)&0ffh+3,7,B");
1248 //asm("bsf _STATUS,0,C");
1249 asm("bsf 0xFD8,0,C"); // HI-TECH PICC-18 PRO 9.63PL1 doesn't define _STATUS
1250 asm("rlcf (_toRotate)&0ffh+0,F,B");
1251 asm("rlcf (_toRotate)&0ffh+1,F,B");
1252 asm("rlcf (_toRotate)&0ffh+2,F,B");
1253 asm("rlcf (_toRotate)&0ffh+3,F,B");
1254 }
1255 #else
1256 for(; i != 0u; i--)
1257 {
1258 _asm
1259 movlb toRotate
1260 bcf STATUS,0,0
1261 btfsc toRotate+3,7,1
1262 bsf STATUS,0,0
1263 rlcf toRotate+0,1,1
1264 rlcf toRotate+1,1,1
1265 rlcf toRotate+2,1,1
1266 rlcf toRotate+3,1,1
1267 _endasm
1268 }
1269 #endif
1270  
1271 return toRotate.Val;
1272 }
1273 #endif
1274  
1275 /*****************************************************************************
1276 Function:
1277 void FormatNetBIOSName(BYTE Name[])
1278  
1279 Summary:
1280 Formats a string to a valid NetBIOS name.
1281  
1282 Description:
1283 This function formats a string to a valid NetBIOS name. Names will be
1284 exactly 16 characters, as defined by the NetBIOS spec. The 16th
1285 character will be a 0x00 byte, while the other 15 will be the
1286 provided string, padded with spaces as necessary.
1287  
1288 Precondition:
1289 None
1290  
1291 Parameters:
1292 Name - the string to format as a NetBIOS name. This parameter must have
1293 at least 16 bytes allocated.
1294  
1295 Returns:
1296 None
1297 ***************************************************************************/
1298 void FormatNetBIOSName(BYTE Name[])
1299 {
1300 BYTE i;
1301  
1302 Name[15] = '\0';
1303 strupr((char*)Name);
1304 i = 0;
1305 while(i < 15u)
1306 {
1307 if(Name[i] == '\0')
1308 {
1309 while(i < 15u)
1310 {
1311 Name[i++] = ' ';
1312 }
1313 break;
1314 }
1315 i++;
1316 }
1317 }
1318  
1319 /*****************************************************************************
1320 Function:
1321 char * strnchr(const char *searchString, size_t count, char c)
1322  
1323 Summary:
1324 Searches a string up to a specified number of characters for a specific
1325 character.
1326  
1327 Description:
1328 Searches a string up to a specified number of characters for a specific
1329 character. The string is searched forward and the first occurance
1330 location is returned. If the search character is not present in the
1331 string, or if the maximum character count is reached first, then a NULL
1332 pointer is returned.
1333  
1334 Precondition:
1335 None
1336  
1337 Parameters:
1338 searchString - Pointer to a null terminated string to search. If count is
1339 less than the string size, then the string need not be null terminated.
1340 count - Maximum number of characters to search before aborting.
1341 c - Character to search for
1342  
1343 Returns:
1344 Pointer to the first occurance of the character c in the string
1345 searchString. If the character is not found or the maximum count is
1346 reached, a NULL pointer is returned.
1347 ***************************************************************************/
1348 char * strnchr(const char *searchString, size_t count, char c)
1349 {
1350 char c2;
1351  
1352 while(count--)
1353 {
1354 c2 = *searchString++;
1355 if(c2 == 0u)
1356 return NULL;
1357 if(c2 == c)
1358 return (char*)--searchString;
1359 }
1360 return NULL;
1361 }
1362  
1363 /*****************************************************************************
1364 Function:
1365 BYTE ExtractURLFields(BYTE *vURL,
1366 PROTOCOLS *protocol,
1367 BYTE *vUsername, WORD *wUsernameLen,
1368 BYTE *vPassword, WORD *wPasswordLen,
1369 BYTE *vHostname, WORD *wHostnameLen,
1370 WORD *wPort,
1371 BYTE *vFilePath, WORD *wFilePathLen)
1372  
1373 Summary:
1374 Extracts all parameters from an URL string (ex:
1375 "http://admin:passwd@www.microchip.com:8080/myfile.gif" is split into
1376 {PROTOCOL_HTTP, "admin", "passwd", "www.microchip.com", 8080, "/myfile.gif"}.
1377  
1378 Description:
1379 Extracts all parameters from an URL string (ex:
1380 "http://admin:passwd@www.microchip.com:8080/myfile.gif" is split into
1381 {PROTOCOL_HTTP, "admin", "passwd", "www.microchip.com", 8080, "/myfile.gif"}.
1382  
1383 The URL string can be null terminated, or alternatively could be terminated
1384 by a carriage return or line feed.
1385  
1386 If the protocol is unrecognized or the protocol is recognized but the URL
1387 is malformed, than an error is safely returned. For more information on
1388 URL/URI interpretation see RFC 2396.
1389  
1390 Precondition:
1391 This function is commented out by default to save code space because
1392 it is not used by any current stack features. However, if you want to use
1393 it, go ahead and uncomment it. It has been tested, so it (should) work
1394 correctly.
1395  
1396 Parameters:
1397 vURL - Pointer to null terminated URL to decode and extract from. This
1398 parameter is required and needs to have the minimum RFC 1738 components
1399 in it (protocol and hostname).
1400  
1401 protocol - Optional pointer to a PROTOCOLS enum to retrieve the decoded
1402 protocol type. If this parameter is unneeded, specify a NULL pointer.
1403 The protocol is a required part of the URL, so it must always be
1404 present. The protocol also determines what scheme all other parameters
1405 are decoded using, so the function will fail if an unrecognized
1406 protocol is provided. The PROTOCOLS enum members show all of the
1407 currently supported protocols for this function.
1408  
1409 <p>For the example URL provided in the function description,
1410 PROTOCOL_HTTP would be returned for this field.
1411  
1412 vUsername - Optional pointer to a buffer to write the decoded username
1413 portion of the URL. If the URL does not contain a username or a NULL
1414 pointer is supplied, then this field is ignored.
1415  
1416 <p>For the example URL provided in the function description, "admin"
1417 would be returned for this field.
1418  
1419 wUsernameLen -
1420 On call\: Optional pointer to a WORD specifying the maximum length of
1421 the vUsername buffer, including the null terminator character.
1422  
1423 <p>Upon return\: If wUsernameLen and vUsername are non-NULL, the
1424 *wUsernameLen WORD is updated with the actual number of characters
1425 written to the vUsername buffer, including the null terminator
1426 character. If vUsername is NULL but wUsernameLen is non-NULL, then no
1427 characters are copied, but *wUsernameLen will return the number of
1428 characters required to fit the full username string. If wUsernameLen
1429 is NULL, then the username field in the URL, if present, is ignored and
1430 the vUsername pointer is not used.
1431  
1432 <p>If zero characters were written, this indicates that the URL did not
1433 contain a username field. If one character was written, this indicates
1434 that a username field was present, but was a zero character string
1435 (ex\: "").
1436  
1437 <p>For the example URL provided in the function description, 6 (0x0006)
1438 would be returned for this field.
1439  
1440 vPassword - Optional pointer to a buffer to write the decoded password
1441 portion of the URL. If the URL does not contain a password or a NULL
1442 pointer is supplied, then this field is ignored.
1443  
1444 <p>For the example URL provided in the function description, "passwd"
1445 would be returned for this field.
1446  
1447 wPasswordLen -
1448 On call\: Optional pointer to a WORD specifying the maximum length of
1449 the vPassword buffer, including the null terminator character.
1450  
1451 <p>Upon return\: If wPasswordLen and vPassword are non-NULL, the
1452 *wPasswordLen WORD is updated with the actual number of characters
1453 written to the vPassword buffer, including the null terminator
1454 character. If vPassword is NULL but wPasswordLen is non-NULL, then no
1455 characters are copied, but *wPasswordLen will return the number of
1456 characters required to fit the full password string. If wPasswordLen
1457 is NULL, then the password field in the URL, if present, is ignored and
1458 the vPassword pointer is not used.
1459  
1460 <p>If zero characters were written, this indicates that the URL did not
1461 contain a password field. If one character was written, this indicates
1462 that a password field was present, but was a zero character string
1463 (ex\: "").
1464  
1465 <p>For the example URL provided in the function description, 7 (0x0007)
1466 would be returned for this field.
1467  
1468 vHostname - Optional pointer to a buffer to write the decoded hostname
1469 portion of the URL. All Internet URLs must contain a hostname or IP
1470 address, however, if a NULL pointer is supplied, then this field is
1471 ignored.
1472  
1473 <p>For the example URL provided in the function description,
1474 "www.microchip.com" would be returned for this field. If the URL was
1475 "http://192.168.0.1", then this field would be returned as
1476 "192.168.0.1". The IP address would not be decoded to a DWORD (use the
1477 StringToIPAddress() helper function to do this).
1478  
1479 wHostnameLen -
1480 On call\: Optional pointer to a WORD specifying the maximum length of
1481 the vHostname buffer, including the null terminator character.
1482  
1483 <p>Upon return\: If wHostnameLen and vHostname are non-NULL, the
1484 *wHostnameLen WORD is updated with the actual number of characters
1485 written to the vHostname buffer, including the null terminator
1486 character. If vHostname is NULL but wHostnameLen is non-NULL, then no
1487 characters are copied, but *wHostnameLen will return the number of
1488 characters required to fit the full hostname string. If wHostnameLen
1489 is NULL, then the hostname field in the URL, is ignored and the
1490 vHostname pointer is not used.
1491  
1492 <p>For the example URL provided in the function description,
1493 18 (0x0012) would be returned for this field. If the URL was
1494 "http://192.168.0.1", then this field would be returned as 12 (0x000C).
1495  
1496 wPort - Optional pointer to a WORD specifying the TCP or UDP port that the
1497 server is listening on. If the port field is absent from the URL, then
1498 this parameter will specify the default port for the protocol. For
1499 example, "http://www.microchip.com" would result in 80 being return as
1500 the specified port.
1501  
1502 <p>If the wPort pointer is NULL, then the port field in the URL
1503 is ignored, if present.
1504  
1505 vFilePath - Optional pointer to a buffer to write the decoded file path
1506 portion of the URL. If a NULL pointer is supplied, then this field is
1507 ignored. If a file path is not present in the URL, then "/" will be
1508 returned in this field.
1509  
1510 <p>For the example URL provided in the function description,
1511 "/myfile.gif" would be returned for this field.
1512  
1513 wFilePathLen -
1514 On call\: Optional pointer to a WORD specifying the maximum length of
1515 the vFilePath buffer, including the null terminator character.
1516  
1517 <p>Upon return\: If wFilePathLen and vFilePath are non-NULL, the
1518 *wFilePathLen WORD is updated with the actual number of characters
1519 written to the vFilePath buffer, including the null terminator
1520 character. If vFilePath is NULL but wFilePathLen is non-NULL, then no
1521 characters are copied, but *wFilePathLen will return the number of
1522 characters required to fit the full file path string. If wFilePathLen
1523 is NULL, then the file path field in the URL, if present, is ignored and
1524 the vFilePath pointer is not used.
1525  
1526 <p>This function always returns "/" if no file path is present, so
1527 *wFilePathLen will also be at least 2 characters ('/' and null
1528 terminator) if the pointer is non-NULL.
1529  
1530 <p>For the example URL provided in the function description, 12 (0x000C)
1531 would be returned for this field.
1532  
1533 Returns:
1534 Zero on success. Nonzero indicates an error code. If a nonzero error code
1535 is returned, none of the returned buffers or pointer values should be
1536 treated as valid, but some of them may have been written to. The following
1537 are all possible return values.
1538 <table>
1539  
1540 1 Protocol unknown (additional code needs to be added to
1541 ExtractURLFields() and the PROTOCOLS enum needs to be updated if
1542 you want to decode URLs of this protocol type.
1543 2 URL malformed. Illegal or unknown URL format encountered.
1544 3 Buffer too small. One of the input buffer sizes is too small to
1545 contain the URL parameter.
1546 </table>
1547 ***************************************************************************/
1548 #if 0
1549 BYTE ExtractURLFields(BYTE *vURL, PROTOCOLS *protocol, BYTE *vUsername, WORD *wUsernameLen, BYTE *vPassword, WORD *wPasswordLen, BYTE *vHostname, WORD *wHostnameLen, WORD *wPort, BYTE *vFilePath, WORD *wFilePathLen)
1550 {
1551 // These two arrays must exactly match up each other and the PROTOCOLS enum
1552 // elements. The protocol name strings must also be specified in all
1553 // lowercase.
1554 static ROM char * ROM vProtocolNames[] = {"http", "https", "mms", "rtsp"};
1555 static ROM WORD wProtocolPorts[] = { 80, 443, 1755, 554};
1556 WORD w, w2;
1557 BYTE i, j;
1558 PROTOCOLS prot;
1559 BYTE *temp, *temp2;
1560 WORD wURLLen;
1561 WORD wLocalPort;
1562  
1563  
1564 // Calculate how long this URL is
1565 wURLLen = strlen((char*)vURL);
1566 temp = (BYTE*)strnchr((char*)vURL, wURLLen, '\r');
1567 if(temp)
1568 wURLLen = temp - vURL;
1569 temp = (BYTE*)strnchr((char*)vURL, wURLLen, '\n');
1570 if(temp)
1571 wURLLen = temp - vURL;
1572  
1573  
1574 // Parse starting protocol field
1575 // Find out how long the protocol name field is
1576 temp = (BYTE*)strnchr((char*)vURL, wURLLen, ':');
1577 if(temp == NULL)
1578 return 2;
1579  
1580 // Search protocol list to see if this is a recognized protocol
1581 for(prot = 0; (BYTE)prot < sizeof(wProtocolPorts)/sizeof(wProtocolPorts[0]); prot++)
1582 {
1583 w = strlenpgm(vProtocolNames[prot]);
1584 if((WORD)(temp - vURL) == w)
1585 {
1586 w2 = 0;
1587 temp2 = vURL;
1588 while(w)
1589 {
1590 i = *temp2++;
1591 if((i >= 'A') && (i <= 'Z'))
1592 i += 'a' - 'A';
1593 if(i != (BYTE)vProtocolNames[prot][w2++])
1594 break;
1595 w--;
1596 }
1597 if(w == 0u)
1598 {
1599 if(protocol)
1600 *protocol = prot;
1601 break;
1602 }
1603 }
1604 }
1605  
1606 // If we've search the whole list and didn't find a match, then
1607 // this protocol is unknown and this URL cannot be parsed.
1608 if((BYTE)prot >= sizeof(wProtocolPorts)/sizeof(wProtocolPorts[0]))
1609 return 1;
1610  
1611 w = temp - vURL + 1;
1612 vURL += w;
1613 wURLLen -= w;
1614  
1615 // Protocols using the authority field all must have a double
1616 // slash "//" prefix
1617 if(wURLLen < 2u)
1618 return 2;
1619 for(j = 0; j < 2u; j++)
1620 {
1621 i = *vURL++;
1622 if(i != '/')
1623 return 2;
1624 }
1625 wURLLen -= 2;
1626  
1627  
1628 // Parse username and password fields
1629 // See if there is a @ sign, indicating that there is at
1630 // least a username and possibly a password in this URL
1631 temp = (BYTE*)strnchr((char*)vURL, wURLLen, '@');
1632 if(temp == NULL)
1633 {
1634 if(wUsernameLen)
1635 *wUsernameLen = 0;
1636 if(wPasswordLen)
1637 *wPasswordLen = 0;
1638 }
1639 else
1640 {
1641 // If we get down here, there is a user name present, let's
1642 // see if a password is also present by searching for a
1643 // colon between the current string position and the @
1644 // symbol.
1645 temp2 = (BYTE*)strnchr((char*)vURL, temp - vURL, ':');
1646  
1647 // Calculate username length and password length, including
1648 // null terminator (if the field exists)
1649 if(temp2 == NULL)
1650 {
1651 w = temp - vURL + 1; // Username
1652 w2 = 0; // Password
1653 }
1654 else
1655 {
1656 w = temp2 - vURL + 1; // Username
1657 w2 = temp - temp2; // Password
1658 }
1659  
1660 if(wUsernameLen)
1661 {
1662 if(vUsername)
1663 {
1664 if(*wUsernameLen < w)
1665 return 3;
1666 memcpy((void*)vUsername, (void*)vURL, w - 1);
1667 vUsername[w-1] = 0;
1668 }
1669 *wUsernameLen = w;
1670 }
1671  
1672 if(wPasswordLen)
1673 {
1674 if(vPassword)
1675 {
1676 if(*wPasswordLen < w2)
1677 return 3;
1678 if(w2)
1679 {
1680 memcpy((void*)vPassword, (void*)temp2+1, w2 - 1);
1681 vPassword[w2-1] = 0;
1682 }
1683 }
1684 *wPasswordLen = w2;
1685 }
1686  
1687 vURL += w;
1688 wURLLen -= w;
1689 if(w2)
1690 {
1691 vURL += w2;
1692 wURLLen -= w2;
1693 }
1694 }
1695  
1696  
1697 // Parse hostname field
1698 // Find the length of the hostname, including NULL
1699 // terminator
1700 temp = (BYTE*)strnchr((char*)vURL, wURLLen, ':');
1701 temp2 = (BYTE*)strnchr((char*)vURL, wURLLen, '/');
1702 if(temp && temp2)
1703 {
1704 if(temp > temp2)
1705 temp = NULL;
1706 }
1707 if(temp == NULL)
1708 {
1709 temp = temp2;
1710 if(temp2 == NULL)
1711 temp = vURL + wURLLen;
1712 }
1713 w = temp - vURL + 1;
1714 if(wHostnameLen)
1715 {
1716 if(vHostname)
1717 {
1718 if(*wHostnameLen < w)
1719 return 3;
1720 memcpy((void*)vHostname, (void*)vURL, w - 1);
1721 vHostname[w-1] = 0;
1722 }
1723 *wHostnameLen = w;
1724 }
1725 vURL += w - 1;
1726 wURLLen -= w - 1;
1727  
1728  
1729 // Parse port field
1730 if(*vURL == ':')
1731 {
1732 vURL++;
1733 wURLLen--;
1734 wLocalPort = 0;
1735 w = wURLLen;
1736 temp = (BYTE*)strnchr((char*)vURL, wURLLen, '/');
1737 if(temp != NULL)
1738 w = temp - vURL;
1739 w2 = w;
1740 if(wPort)
1741 {
1742 while(w--)
1743 {
1744 wLocalPort *= 10;
1745 wLocalPort += *vURL++ - '0';
1746 }
1747 *wPort = wLocalPort;
1748 }
1749 else
1750 vURL += w2;
1751 wURLLen -= w2;
1752 }
1753 else if(wPort)
1754 *wPort = wProtocolPorts[prot];
1755  
1756  
1757 // Parse file path field
1758 if(wFilePathLen)
1759 {
1760 w = ++wURLLen;
1761 if(wURLLen == 1u)
1762 w = 2;
1763 if(vFilePath)
1764 {
1765 if(*wFilePathLen < w)
1766 return 3;
1767 if(wURLLen == 1u)
1768 vFilePath[0] = '/';
1769 else
1770 memcpy((void*)vFilePath, (void*)vURL, wURLLen - 1);
1771 vFilePath[w - 1] = 0;
1772 *wFilePathLen = w;
1773 return 0;
1774 }
1775 *wFilePathLen = w;
1776 }
1777 return 0;
1778 }
1779 #endif
1780  
1781  
1782 /*****************************************************************************
1783 Function:
1784 SHORT Replace(BYTE *vExpression, ROM BYTE *vFind, ROM BYTE *vReplacement,
1785 WORD wMaxLen, BOOL bSearchCaseInsensitive)
1786  
1787 Summary:
1788 Replaces all instances of a particular substring with a new string
1789  
1790 Description:
1791 Searches a string (vExpression) and replaces all instances of a particular
1792 substring (vFind) with a new string (vReplacement). The start offset to
1793 being searching and a maximum number of replacements can be specified. The
1794 search can be performed in a case sensitive or case insensitive manner.
1795  
1796 Precondition:
1797 This function is commented out by default to save code space because
1798 it is not used by any current stack features. However, if you want to use
1799 it, go ahead and uncomment it. It has been tested, so it (should) work
1800 correctly.
1801  
1802 Parameters:
1803 vExpression - Null terminated string to search and make replacements within.
1804 vFind - Null terminated string to search for.
1805 vReplacement - Null terminated string to replace all instances of vFind with.
1806 wMaxLen - Maximum length of the output vExpression string if string
1807 expansion is going to occur (replacement length is longer than find
1808 length). If the replacements will cause this maximum string length to
1809 be exceeded, then no replacements will be made and a negative result
1810 will be returned, indicating failure. If the replacement length is
1811 shorter or equal to the search length, then this parameter is ignored.
1812 bSearchCaseInsensitive - Boolean indicating if the search should be
1813 performed in a case insensitive manner. Specify TRUE for case
1814 insensitive searches (slower) or FALSE for case sensitive
1815 searching (faster).
1816  
1817 Remarks:
1818 If the replacement string length is shorter than or equal to the search
1819 string length and the search string occurs in multiple overlapping
1820 locations (ex\: expression is "aaa", find is "aa", and replacement is "bb")
1821 then the first find match occuring when searching from left to right will
1822 be replaced. (ex\: output expression will be "bba").
1823  
1824 However, if the replacement string length is longer than the search string
1825 length, the search will occur starting from the end of the string and
1826 proceed to the beginning (right to left searching). In this case if the
1827 expression was "aaa", find was "aa", and replacement was "bbb", then the
1828 final output expression will be "abbb".
1829  
1830 Returns:
1831 If zero or greater, indicates the count of how many replacements were made.
1832 If less than zero (negative result), indicates that wMaxLen was too small
1833 to make the necessary replacements. In this case, no replacements were
1834 made.
1835 ***************************************************************************/
1836 #if 0
1837 SHORT Replace(BYTE *vExpression, ROM BYTE *vFind, ROM BYTE *vReplacement, WORD wMaxLen, BOOL bSearchCaseInsensitive)
1838 {
1839 WORD wExpressionLen, wFindLen, wFindLenMinusOne, wReplacementLen;
1840 WORD wFindCount, wReplacementsLeft;
1841 BYTE i, j;
1842 BYTE vFirstFindChar;
1843 WORD wBytesLeft;
1844 BYTE *vDest;
1845 BYTE *vExpressionCompare;
1846 ROM BYTE *vFindCompare;
1847 WORD w;
1848  
1849 wFindLen = strlenpgm((ROM char*)vFind);
1850 if(wFindLen == 0u)
1851 return 0;
1852  
1853 wExpressionLen = strlen((char*)vExpression);
1854 wReplacementLen = strlenpgm((ROM char*)vReplacement);
1855  
1856 wFindCount = 0;
1857 wFindLenMinusOne = wFindLen - 1;
1858 vFirstFindChar = *vFind++;
1859 if(bSearchCaseInsensitive) // Convert to all lowercase if needed
1860 if((vFirstFindChar >= (BYTE)'A') && (vFirstFindChar <= (BYTE)'Z'))
1861 vFirstFindChar += 'a' - 'A';
1862  
1863 // If the replacement string is the same length as the search string, then
1864 // we can immediately do the needed replacements inline and return.
1865 if(wFindLen == wReplacementLen)
1866 {
1867 for(wBytesLeft = wExpressionLen; wBytesLeft; wBytesLeft--)
1868 {
1869 i = *vExpression++;
1870 if(bSearchCaseInsensitive)
1871 {
1872 if((i >= (BYTE)'A') && (i <= (BYTE)'Z'))
1873 i += 'a' - 'A';
1874 if(i != vFirstFindChar)
1875 continue;
1876 vExpressionCompare = vExpression;
1877 vFindCompare = vFind;
1878 w = wFindLenMinusOne;
1879 while(w)
1880 {
1881 i = *vExpressionCompare++;
1882 j = *vFindCompare++;
1883 if((i >= (BYTE)'A') && (i <= (BYTE)'Z'))
1884 i += 'a' - 'A';
1885 if((j >= (BYTE)'A') && (j <= (BYTE)'Z'))
1886 j += 'a' - 'A';
1887 if(i != j)
1888 break;
1889 w--;
1890 }
1891 if(w)
1892 continue;
1893 }
1894 else
1895 {
1896 if(i != vFirstFindChar)
1897 continue;
1898 if(memcmppgm2ram((void*)vExpression, (ROM void*)vFind, wFindLenMinusOne))
1899 continue;
1900 }
1901  
1902 memcpypgm2ram((void*)vExpression-1, (ROM void*)vReplacement, wReplacementLen);
1903 wFindCount++;
1904 vExpression += wFindLenMinusOne;
1905 wBytesLeft -= wFindLenMinusOne;
1906 }
1907 return wFindCount;
1908 }
1909  
1910  
1911 // If the replacement string is shorter than the search string, then we can
1912 // search from left to right and move the string over as we find occurrences.
1913 if(wFindLen > wReplacementLen)
1914 {
1915 vDest = vExpression;
1916 for(wBytesLeft = wExpressionLen; wBytesLeft; wBytesLeft--)
1917 {
1918 i = *vExpression++;
1919 *vDest++ = i;
1920 if(bSearchCaseInsensitive)
1921 {
1922 if((i >= (BYTE)'A') && (i <= (BYTE)'Z'))
1923 i += 'a' - 'A';
1924 if(i != vFirstFindChar)
1925 continue;
1926 vExpressionCompare = vExpression;
1927 vFindCompare = vFind;
1928 w = wFindLenMinusOne;
1929 while(w)
1930 {
1931 i = *vExpressionCompare++;
1932 j = *vFindCompare++;
1933 if((i >= (BYTE)'A') && (i <= (BYTE)'Z'))
1934 i += 'a' - 'A';
1935 if((j >= (BYTE)'A') && (j <= (BYTE)'Z'))
1936 j += 'a' - 'A';
1937 if(i != j)
1938 break;
1939 w--;
1940 }
1941 if(w)
1942 continue;
1943 }
1944 else
1945 {
1946 if(i != vFirstFindChar)
1947 continue;
1948 if(memcmppgm2ram((void*)vExpression, (ROM void*)vFind, wFindLenMinusOne))
1949 continue;
1950 }
1951  
1952 memcpypgm2ram((void*)vDest-1, (ROM void*)vReplacement, wReplacementLen);
1953 vDest += wReplacementLen-1;
1954 wFindCount++;
1955 vExpression += wFindLenMinusOne;
1956 wBytesLeft -= wFindLenMinusOne;
1957 }
1958 *vDest = 0x00; // Write new null terminator since the string may have shrunk
1959 return wFindCount;
1960 }
1961  
1962 // If the replacement string is longer than the search string, then we will
1963 // take a two pass approach. On the first pass, we will merely count how
1964 // many replacements to make. With this we can calculate how long the
1965 // final string is going to be. On the second pass, we will search from
1966 // right to left and expand the string as needed.
1967  
1968 // Pass 1: count how many occurrences of vFind are in vExpression
1969 for(wBytesLeft = wExpressionLen; wBytesLeft; wBytesLeft--)
1970 {
1971 i = *vExpression++;
1972 if(bSearchCaseInsensitive)
1973 {
1974 if((i >= (BYTE)'A') && (i <= (BYTE)'Z'))
1975 i += 'a' - 'A';
1976 if(i != vFirstFindChar)
1977 continue;
1978 vExpressionCompare = vExpression;
1979 vFindCompare = vFind;
1980 w = wFindLenMinusOne;
1981 while(w)
1982 {
1983 i = *vExpressionCompare++;
1984 j = *vFindCompare++;
1985 if((i >= (BYTE)'A') && (i <= (BYTE)'Z'))
1986 i += 'a' - 'A';
1987 if((j >= (BYTE)'A') && (j <= (BYTE)'Z'))
1988 j += 'a' - 'A';
1989 if(i != j)
1990 break;
1991 w--;
1992 }
1993 if(w)
1994 continue;
1995 }
1996 else
1997 {
1998 if(i != vFirstFindChar)
1999 continue;
2000 if(memcmppgm2ram((void*)vExpression, (ROM void*)vFind, wFindLenMinusOne))
2001 continue;
2002 }
2003  
2004 wFindCount++;
2005 vExpression += wFindLenMinusOne;
2006 wBytesLeft -= wFindLenMinusOne;
2007 }
2008  
2009 // Return immediately if no replacements are needed
2010 if(wFindCount == 0u)
2011 return 0;
2012  
2013 // Pass 2: make replacements and move string over
2014 vDest = vExpression + wFindCount * (wReplacementLen - wFindLen);
2015 if(vDest > vExpression - wExpressionLen + wMaxLen)
2016 return -1;
2017 *vDest-- = 0x00; // Write new null terminator
2018 vExpression -= 1;
2019 vFind -= 1;
2020 vFirstFindChar = vFind[wFindLenMinusOne];
2021 if(bSearchCaseInsensitive) // Convert to all lowercase if needed
2022 if((vFirstFindChar >= (BYTE)'A') && (vFirstFindChar <= (BYTE)'Z'))
2023 vFirstFindChar += 'a' - 'A';
2024 wReplacementsLeft = wFindCount;
2025 while(wReplacementsLeft)
2026 {
2027 i = *vExpression--;
2028 *vDest-- = i;
2029 if(bSearchCaseInsensitive)
2030 {
2031 if((i >= (BYTE)'A') && (i <= (BYTE)'Z'))
2032 i += 'a' - 'A';
2033 if(i != vFirstFindChar)
2034 continue;
2035 vExpressionCompare = vExpression;
2036 vFindCompare = &vFind[wFindLenMinusOne-1];
2037 w = wFindLenMinusOne;
2038 while(w)
2039 {
2040 i = *vExpressionCompare--;
2041 j = *vFindCompare--;
2042 if((i >= (BYTE)'A') && (i <= (BYTE)'Z'))
2043 i += 'a' - 'A';
2044 if((j >= (BYTE)'A') && (j <= (BYTE)'Z'))
2045 j += 'a' - 'A';
2046 if(i != j)
2047 break;
2048 w--;
2049 }
2050 if(w)
2051 continue;
2052 }
2053 else
2054 {
2055 if(i != vFirstFindChar)
2056 continue;
2057 if(memcmppgm2ram((void*)vExpression-wFindLenMinusOne, (ROM void*)vFind, wFindLenMinusOne))
2058 continue;
2059 }
2060 memcpypgm2ram((void*)vDest-wReplacementLen+2, (ROM void*)vReplacement, wReplacementLen);
2061 vDest -= wReplacementLen-1;
2062  
2063 vExpression -= wFindLenMinusOne;
2064 wBytesLeft -= wFindLenMinusOne;
2065 wReplacementsLeft--;
2066 }
2067 return wFindCount;
2068 }
2069 #endif
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3