1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6 
7 #include <s_record.h>
8 
9 static int hex1_bin (char  c);
10 static int hex2_bin (char *s);
11 
srec_decode(char * input,int * count,ulong * addr,char * data)12 int srec_decode (char *input, int *count, ulong *addr, char *data)
13 {
14 	int	i;
15 	int	v;				/* conversion buffer	*/
16 	int	srec_type;			/* S-Record type	*/
17 	unsigned char chksum;			/* buffer for checksum	*/
18 
19 	chksum = 0;
20 
21 	/* skip anything before 'S', and the 'S' itself.
22 	 * Return error if not found
23 	 */
24 
25 	for (; *input; ++input) {
26 		if (*input == 'S') {		/* skip 'S' */
27 			++input;
28 			break;
29 		}
30 	}
31 	if (*input == '\0') {			/* no more data?	*/
32 		return (SREC_EMPTY);
33 	}
34 
35 	v = *input++;				/* record type		*/
36 
37 	if ((*count = hex2_bin(input)) < 0) {
38 		return (SREC_E_NOSREC);
39 	}
40 
41 	chksum += *count;
42 	input  += 2;
43 
44 	switch (v) {				/* record type		*/
45 
46 	case '0':				/* start record		*/
47 		srec_type = SREC_START;		/* 2 byte addr field	*/
48 		*count   -= 3;			/* - checksum and addr	*/
49 		break;
50 	case '1':
51 		srec_type = SREC_DATA2;		/* 2 byte addr field	*/
52 		*count   -= 3;			/* - checksum and addr	*/
53 		break;
54 	case '2':
55 		srec_type = SREC_DATA3;		/* 3 byte addr field	*/
56 		*count   -= 4;			/* - checksum and addr	*/
57 		break;
58 	case '3':				/* data record with a	*/
59 		srec_type = SREC_DATA4;		/* 4 byte addr field	*/
60 		*count   -= 5;			/* - checksum and addr	*/
61 		break;
62 /***	case '4'  ***/
63 	case '5':			/* count record, addr field contains */
64 		srec_type = SREC_COUNT;	/* a 2 byte record counter	*/
65 		*count    = 0;			/* no data		*/
66 		break;
67 /***	case '6' -- not used  ***/
68 	case '7':				/* end record with a	*/
69 		srec_type = SREC_END4;		/* 4 byte addr field	*/
70 		*count   -= 5;			/* - checksum and addr	*/
71 		break;
72 	case '8':				/* end record with a	*/
73 		srec_type = SREC_END3;		/* 3 byte addr field	*/
74 		*count   -= 4;			/* - checksum and addr	*/
75 		break;
76 	case '9':				/* end record with a	*/
77 		srec_type = SREC_END2;		/* 2 byte addr field	*/
78 		*count   -= 3;			/* - checksum and addr	*/
79 		break;
80 	default:
81 		return (SREC_E_BADTYPE);
82 	}
83 
84 	/* read address field */
85 	*addr = 0;
86 
87 	switch (v) {
88 	case '3':				/* 4 byte addr field	*/
89 	case '7':
90 		if ((v = hex2_bin(input)) < 0) {
91 			return (SREC_E_NOSREC);
92 		}
93 		*addr  += v;
94 		chksum += v;
95 		input  += 2;
96 		/* FALL THRU */
97 	case '2':				/* 3 byte addr field	*/
98 	case '8':
99 		if ((v = hex2_bin(input)) < 0) {
100 			return (SREC_E_NOSREC);
101 		}
102 		*addr <<= 8;
103 		*addr  += v;
104 		chksum += v;
105 		input  += 2;
106 		/* FALL THRU */
107 	case '0':				/* 2 byte addr field	*/
108 	case '1':
109 	case '5':
110 	case '9':
111 		if ((v = hex2_bin(input)) < 0) {
112 			return (SREC_E_NOSREC);
113 		}
114 		*addr <<= 8;
115 		*addr  += v;
116 		chksum += v;
117 		input  += 2;
118 
119 		if ((v = hex2_bin(input)) < 0) {
120 			return (SREC_E_NOSREC);
121 		}
122 		*addr <<= 8;
123 		*addr  += v;
124 		chksum += v;
125 		input  += 2;
126 
127 		break;
128 	default:
129 		return (SREC_E_BADTYPE);
130 	}
131 
132 	/* convert data and calculate checksum */
133 	for (i=0; i < *count; ++i) {
134 		if ((v = hex2_bin(input)) < 0) {
135 			return (SREC_E_NOSREC);
136 		}
137 		data[i] = v;
138 		chksum += v;
139 		input  += 2;
140 	}
141 
142 	/* read anc check checksum */
143 	if ((v = hex2_bin(input)) < 0) {
144 		return (SREC_E_NOSREC);
145 	}
146 
147 	if ((unsigned char)v != (unsigned char)~chksum) {
148 		return (SREC_E_BADCHKS);
149 	}
150 
151 	return (srec_type);
152 }
153 
hex1_bin(char c)154 static int hex1_bin (char c)
155 {
156 	if (c >= '0' && c <= '9')
157 		return (c - '0');
158 	if (c >= 'a' && c <= 'f')
159 		return (c + 10 - 'a');
160 	if (c >= 'A' && c <= 'F')
161 		return (c + 10 - 'A');
162 	return (-1);
163 }
164 
hex2_bin(char * s)165 static int hex2_bin (char *s)
166 {
167 	int i, j;
168 
169 	if ((i = hex1_bin(*s++)) < 0) {
170 		return (-1);
171 	}
172 	if ((j = hex1_bin(*s)) < 0) {
173 		return (-1);
174 	}
175 
176 	return ((i<<4) + j);
177 }
178