Velocity Userspace
ini.c
Go to the documentation of this file.
1 /*
2  * Microchip Velocity PCIe Management Library
3  * Copyright (c) 2025, Microchip Technology
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  */
24 
39 #ifdef __linux__
40 
41 #include "switchtec/ini.h"
42 
43 void handle_section_state(char current_char, char *current_section, int *position) {
44  current_section[(*position)++] = current_char;
45 }
46 
47 void handle_name_state(char current_char, char *current_name, int *position) {
48  current_name[(*position)++] = current_char;
49 }
50 
51 void handle_value_state(char current_char, char *returned_string, int *position, int *valueStartWithDoubleQuote) {
52  if (*position == 0 && current_char == '"') {
53  *valueStartWithDoubleQuote = 1;
54  }
55  returned_string[(*position)++] = current_char;
56 }
57 
58 void finalize_section_state(char *current_section, int *position) {
59  current_section[(*position)++] = '\0';
60 }
61 
62 void finalize_name_state(char *current_name, int *position) {
63  current_name[(*position)++] = '\0';
64 }
65 
66 void finalize_value_state(char *returned_string, int *position, int *valueStartWithDoubleQuote) {
67  if (*position > 0 && returned_string[*position - 1] == '"') {
68  if (*valueStartWithDoubleQuote != 0) {
69  (*position)--;
70  for (int copy = 0; copy < *position - 1; copy++) {
71  returned_string[copy] = returned_string[copy + 1];
72  }
73  (*position)--;
74  }
75  }
76  returned_string[(*position)++] = '\0';
77 }
78 
79 void handle_state_transition(char current_char, enum INI_STATE *state, enum INI_STATE *new_state, char *current_section, char *current_name, char *returned_string, int *position, int *valueStartWithDoubleQuote, int nSize)
80 {
81  switch (current_char)
82  {
83  case '[':
84  if (*state == NONE)
85  {
86  *new_state = SECTION;
87  }
88  break;
89  case ']':
90  if (*state == SECTION)
91  {
92  *new_state = NONE;
93  }
94  break;
95  case ';':
96  *new_state = COMMENT;
97  break;
98  case '\r':
99  case '\n':
100  *new_state = NONE;
101  break;
102  case '=':
103  if (*state == NAME)
104  {
105  *new_state = VALUE;
106  }
107  break;
108  default:
109  switch (*state)
110  {
111  case SECTION:
112  handle_section_state(current_char, current_section, position);
113  break;
114  case NAME:
115  handle_name_state(current_char, current_name, position);
116  break;
117  case VALUE:
118  handle_value_state(current_char, returned_string, position, valueStartWithDoubleQuote);
119  break;
120  case NONE:
121  *position = 0;
122  *state = NAME;
123  *new_state = NAME;
124  handle_name_state(current_char, current_name, position);
125  break;
126  default:
127  break;
128  }
129  switch (*state)
130  {
131  case VALUE:
132  if (*position > nSize - 2)
133  {
134  *position = nSize - 2;
135  }
136  break;
137  default:
138  if (*position > MAX_LENGTH - 2)
139  {
140  *position = MAX_LENGTH - 2;
141  }
142  break;
143  }
144  break;
145  }
146 }
147 
148 int get_key_list(const char *section, const char *name, const char *defaultValue, char *KeyList, int nSize, FILE *fp) {
149  char current_section[MAX_LENGTH];
150  char current_name[MAX_LENGTH];
151  char returned_string[KEY_BUF_SIZE];
152  if (!fp)
153  {
154  perror("error");
155  strncpy(returned_string, defaultValue, nSize);
156  returned_string[nSize - 1] = '\0';
157  return strnlen(returned_string, nSize - 1);
158  }
159  enum INI_STATE state = NONE;
160  enum INI_STATE new_state = NONE;
161 
162  int valueStartWithDoubleQuote = 0;
163 
164  char current_char;
165  int position = 0;
166  int pos = 0;
167 
168  fseek(fp, 0, SEEK_END); // seek to end of file
169  int size = ftell(fp); // get current file pointer
170  fseek(fp, 0, SEEK_SET);
171  while (size--)
172  {
173  size_t readed = fread(&current_char, 1, 1, fp);
174  if (readed == 1)
175  {
176  handle_state_transition(current_char, &state, &new_state, current_section, current_name, returned_string, &position, &valueStartWithDoubleQuote, nSize);
177  }
178  if (new_state != state)
179  {
180  switch (state)
181  {
182  case SECTION:
183  finalize_section_state(current_section, &position);
184  break;
185  case NAME:
186  finalize_name_state(current_name, &position);
187  break;
188  case VALUE:
189  finalize_value_state(returned_string, &position, &valueStartWithDoubleQuote);
190 
191  if (position > 0 && returned_string[position - 1] == '"') {
192 
193  if (valueStartWithDoubleQuote != 0) {
194  position--;
195  for (int copy = 0; copy < position - 1; copy++)
196  {
197  returned_string[copy] = returned_string[copy + 1];
198  }
199  position--;
200  }
201  }
202  returned_string[position++] = '\0';
203 
204  if(strncmp(current_section, section, MAX_LENGTH) == 0)
205  {
206  if(strncmp(current_name, name, MAX_LENGTH) == 0) {
207  memcpy(&KeyList[0], returned_string, strlen(returned_string));
208  pos = pos + strlen(returned_string);
209  KeyList[pos++] = '\0';
210 
211  return strnlen(returned_string, nSize - 1);
212  }
213  else if (strncmp(name, "NULL", MAX_LENGTH) == 0) {
214  memcpy(&KeyList[pos], current_name, strlen(current_name));
215  pos = pos + strlen(current_name);
216 
217  KeyList[pos++] = '\0';
218  KeyList[pos++] = '=';
219 
220  memcpy(&KeyList[pos++], returned_string, strlen(returned_string));
221  KeyList[pos++] = '\0';
222 
223  state = new_state;
224  continue;
225  }
226  else
227  {
228  memcpy(KeyList, defaultValue, nSize);
229  KeyList[nSize - 1] = '\0';
230 
231  state = new_state;
232  continue;
233  }
234  }
235  break;
236  default:
237  break;
238  }
239  position = 0;
240  valueStartWithDoubleQuote = 0;
241  state = new_state;
242  }
243  }
244 
245  return strnlen(returned_string, nSize - 1);
246 }
247 
248 BOOL check_valid_address(BYTE byCurrXMode, BOOL bIsDwordAddress, DWORD dwCurrAddress)
249 {
250  if ((byCurrXMode == XMODE_CLEAR_BITS) || (byCurrXMode == XMODE_SET_BITS) ||
251  (byCurrXMode == XMODE_WRITE_BYTE))
252  {
253  //Check for valid address
254  if ((TRUE == bIsDwordAddress) && (dwCurrAddress < 0xFFFF))
255  {
256  return FALSE;
257  }
258  else if ((FALSE == bIsDwordAddress) && (dwCurrAddress > 0xFFFF))
259  {
260  return FALSE;
261  }
262  }
263  return TRUE;
264 }
265 
266 void handle_address_change(DWORD dwCurrAddress, DWORD dwPrevAddress, BOOL *bValidDataOffset, BYTE *byDataLength, WORD *wDataLengthOffset, BYTE *m_pBinConfig, WORD *m_wDataOffset, DWORD nTemp)
267 {
268  WORD wTemp = (dwCurrAddress - dwPrevAddress - 1);
269 
270  if (*bValidDataOffset)
271  {
272  // Complete the data record before switching/skipping address
273  m_pBinConfig[*wDataLengthOffset] = *byDataLength;
274  *bValidDataOffset = FALSE;
275  }
276 
277  if ((dwCurrAddress < dwPrevAddress) || (wTemp > 0x7D)) {
278  // Set new xdata address
279  m_pBinConfig[(*m_wDataOffset)++] = SET_XDATA_ADDRESS;
280  if (nTemp < 0xFFFF) {
281  m_pBinConfig[(*m_wDataOffset)++] = HIBYTE(LOWORD(dwCurrAddress));
282  m_pBinConfig[(*m_wDataOffset)++] = LOBYTE(LOWORD(dwCurrAddress));
283  } else {
284  m_pBinConfig[(*m_wDataOffset)++] = HIBYTE(HIWORD(dwCurrAddress));
285  m_pBinConfig[(*m_wDataOffset)++] = LOBYTE(HIWORD(dwCurrAddress));
286  m_pBinConfig[(*m_wDataOffset)++] = HIBYTE(LOWORD(dwCurrAddress));
287  m_pBinConfig[(*m_wDataOffset)++] = LOBYTE(LOWORD(dwCurrAddress));
288  }
289  } else {
290  // Skip xdata write for wTemp length
291  m_pBinConfig[(*m_wDataOffset)++] = (0x80 | LOBYTE(wTemp));
292  }
293 }
294 
295 void handle_xdata_mode_switch(BYTE byCurrXMode, BYTE *byPrevXMode, BOOL *bValidDataOffset, BYTE *byDataLength, WORD *wDataLengthOffset, BYTE *m_pBinConfig, WORD *m_wDataOffset) {
296  if (byCurrXMode == XMODE_WRITE_BYTE)
297  {
298  if (*bValidDataOffset)
299  {
300  // Complete the data record before switching XDATA mode
301  m_pBinConfig[*wDataLengthOffset] = *byDataLength;
302  *bValidDataOffset = FALSE;
303  }
304  // Switch to new xdata write/set/clear mode
305  m_pBinConfig[(*m_wDataOffset)++] = CUSTOM_COMMAND;
306  m_pBinConfig[(*m_wDataOffset)++] = byCurrXMode;
307 
308  *byPrevXMode = byCurrXMode;
309  }
310 
311  // Take care of xdata mode switching
312  if (byCurrXMode != *byPrevXMode)
313  {
314  if (*bValidDataOffset)
315  {
316  // Complete the data record before switching XDATA mode
317  m_pBinConfig[*wDataLengthOffset] = *byDataLength;
318  *bValidDataOffset = FALSE;
319  }
320  // Switch to new xdata write/set/clear mode
321  m_pBinConfig[(*m_wDataOffset)++] = CUSTOM_COMMAND;
322  m_pBinConfig[(*m_wDataOffset)++] = byCurrXMode;
323 
324  *byPrevXMode = byCurrXMode;
325  }
326 }
327 
328 BOOL process_key_entry(char *pszToken, char *szKeyEntry, char *szSeparators, BYTE *m_pBinConfig, WORD *m_wDataOffset, DWORD *dwPrevAddress, BYTE *byDataLength, WORD *wDataLengthOffset, BYTE *abyBinBuffer, BOOL *bValidDataOffset)
329 {
330 
331  unsigned int nTemp;
332  BYTE byData;
333  DWORD dwActualSize;
334  ssize_t rlen;
335 
336  // Initialize data offset if not valid
337  if (!(*bValidDataOffset))
338  {
339  *bValidDataOffset = TRUE;
340  *wDataLengthOffset = (*m_wDataOffset)++;
341  *byDataLength = 0;
342  }
343 
344  // Check if the key entry points to a .bin file
345  if (strstr(szKeyEntry, ".bin"))
346  {
347  FILE *fp = fopen(szKeyEntry, "rb");
348  if (!fp) {
349  return FALSE; // Failed to open file
350  }
351 
352  // Move file pointer to the end to get the file size
353  fseek(fp, 0, SEEK_END);
354  dwActualSize = ftell(fp);
355  fseek(fp, 0, SEEK_SET);
356 
357  // Load data bytes from the binary file
358  rlen = fread(&abyBinBuffer[0], 1, dwActualSize, fp);
359  fclose(fp);
360 
361  if (rlen < dwActualSize)
362  {
363  return FALSE; // Failed to read the entire file
364  }
365 
366  // Process the binary data
367  (*dwPrevAddress)--;
368  for (int k = 0; k < dwActualSize; k++)
369  {
370  (*byDataLength)++;
371  (*dwPrevAddress)++;
372  m_pBinConfig[(*m_wDataOffset)++] = abyBinBuffer[k];
373 
374  // Handle data length exceeding 0x7F bytes
375  if (0x7F == *byDataLength) {
376  m_pBinConfig[*wDataLengthOffset] = *byDataLength;
377  *wDataLengthOffset = (*m_wDataOffset)++;
378  *byDataLength = 0;
379  }
380  }
381  }
382  else
383  {
384  // Process the key entry as a list of data values
385  (*dwPrevAddress)--;
386  pszToken = strtok(szKeyEntry, szSeparators);
387  while (pszToken != NULL) {
388  (*byDataLength)++;
389 
390  sscanf(pszToken, "%x", &nTemp);
391  byData = nTemp;
392 
393  (*dwPrevAddress)++;
394  m_pBinConfig[(*m_wDataOffset)++] = byData;
395 
396  // Handle data length exceeding 0x7F bytes
397  if (0x7F == *byDataLength) {
398  m_pBinConfig[*wDataLengthOffset] = *byDataLength;
399  *wDataLengthOffset = (*m_wDataOffset)++;
400  *byDataLength = 0;
401  }
402 
403  pszToken = strtok(NULL, szSeparators);
404  }
405  }
406 
407  return TRUE;
408 }
409 
410 void handle_stop_opcode(BOOL bValidDataOffset, BYTE byDataLength, BYTE *m_pBinConfig, WORD wDataLengthOffset, WORD *m_wDataOffset)
411 {
412  if (bValidDataOffset)
413  {
414  if (0 == byDataLength)
415  {
416  m_pBinConfig[wDataLengthOffset] = STOP;
417  }
418  else
419  {
420  m_pBinConfig[wDataLengthOffset] = byDataLength;
421  m_pBinConfig[(*m_wDataOffset)++] = STOP;
422  }
423  }
424  else
425  {
426  m_pBinConfig[(*m_wDataOffset)++] = STOP;
427  }
428 }
429 
444 int switchtec_convert_ini2bin(FILE *szINIFileName, char *pclog ,BYTE *m_pBinConfig, int *binlength)
445 {
446  char *pKeyName;
447  char szKeyList[KEY_BUF_SIZE];
448  WORD m_wDataOffset = 0;
449  char szKeyEntry[KEY_BUF_SIZE];
450  BYTE byPrevXMode = XMODE_WRITE_BYTE; // By default xdata_write mode
451  BYTE byCurrXMode = SET_XMODE_NONE;
452  unsigned int nTemp = 0;
453  DWORD dwCurrAddress = 0, dwPrevAddress = 0;
454  BYTE byPatchCount = 0;
455  BOOL bValidDataOffset = FALSE;
456  WORD wDataLengthOffset = 0;
457  BYTE byDataLength = 0;
458  char *pszToken = NULL;
459  char szSeparators[] = " ,\t";
460  BYTE byData;
461  BYTE abyBinBuffer[10 * 1024];
462  BOOL bIsDwordAddress = TRUE;
463  BOOL ret = 0;
464 
465  get_key_list(CONFIG_SECTION_NAME, "NULL", "EMPTY", szKeyList, KEY_BUF_SIZE, szINIFileName);
466 
467  if (!strcmp(szKeyList, "EMPTY"))
468  {
469  return FALSE;
470  }
471  pKeyName = szKeyList;
472 
473  while (strcmp(pKeyName, ""))
474  {
475  get_key_list(CONFIG_SECTION_NAME, pKeyName, "EMPTY", szKeyEntry, KEY_BUF_SIZE, szINIFileName);
476 
477  if (!strcmp(szKeyEntry, "") || !strcmp(szKeyEntry, "EMPTY"))
478  {
479  // Empty key Move to next Key Entry
480  pKeyName += (strlen(pKeyName) + 1);
481  continue;
482  }
483  // Parse key entry
484  if (!strncmp(pKeyName, KEY_XDATA_WRITE, KEY_ID_SIZE))
485  {
486  byCurrXMode = XMODE_WRITE_BYTE;
487  sscanf(pKeyName, KEY_XDATA_WRITE"%x", &nTemp);
488  dwCurrAddress = nTemp;
489  }
490  else if (!strncmp(pKeyName, KEY_XDATA_SET, KEY_ID_SIZE))
491  {
492  byCurrXMode = XMODE_SET_BITS;
493  sscanf(pKeyName, KEY_XDATA_SET"%x", &nTemp);
494  dwCurrAddress = nTemp;
495  }
496  else if (!strncmp(pKeyName, KEY_XDATA_CLEAR, KEY_ID_SIZE))
497  {
498  byCurrXMode = XMODE_CLEAR_BITS;
499  sscanf(pKeyName, KEY_XDATA_CLEAR"%x", &nTemp);
500  dwCurrAddress = nTemp;
501  }
502  else if (!strncmp(pKeyName, KEY_PATCH_CODE, KEY_ID_SIZE))
503  {
504  byCurrXMode = XMODE_PATCH_CODE;
505  sscanf(pKeyName, KEY_PATCH_CODE"%x", &nTemp);
506 
507  //Check for valid address
508  if ((TRUE == bIsDwordAddress) && (nTemp < 0xFFFF))
509  {
510  return FALSE;
511  }
512  else if ((FALSE == bIsDwordAddress) && (nTemp > 0xFFFF))
513  {
514  return FALSE;
515  }
516  dwCurrAddress = nTemp;
517  byPatchCount++;
518  if (bValidDataOffset)
519  {
520  // Complete the data record before switching/skipping address
521  m_pBinConfig[wDataLengthOffset] = byDataLength;
522  bValidDataOffset = FALSE;
523  }
524  m_pBinConfig[m_wDataOffset++] = CUSTOM_COMMAND;
525  m_pBinConfig[m_wDataOffset++] = byCurrXMode;
526 
527 
528  //32 Bit - 16 Bit Addressing check
529  if (nTemp < 0xFFFF)
530  {
531  m_pBinConfig[m_wDataOffset++] = HIBYTE(LOWORD(dwCurrAddress));
532  m_pBinConfig[m_wDataOffset++] = LOBYTE(LOWORD(dwCurrAddress));
533  }
534  else
535  {
536  m_pBinConfig[m_wDataOffset++] = HIBYTE(HIWORD(dwCurrAddress));
537  m_pBinConfig[m_wDataOffset++] = LOBYTE(HIWORD(dwCurrAddress));
538  m_pBinConfig[m_wDataOffset++] = HIBYTE(LOWORD(dwCurrAddress));
539  m_pBinConfig[m_wDataOffset++] = LOBYTE(LOWORD(dwCurrAddress));
540  }
541  pszToken = strtok(szKeyEntry, szSeparators);
542 
543  sscanf(pszToken, "%x", &nTemp);
544  byData = nTemp;
545 
546  m_pBinConfig[m_wDataOffset++] = byData;
547  pszToken = strtok(NULL, szSeparators);
548 
549  pKeyName += (strlen(pKeyName) + 1);
550  //Fix for JIRA-1644
551  byPrevXMode = byCurrXMode;
552  continue;
553  }
554  else
555  {
556  return FALSE;
557  }
558 
559  ret = check_valid_address(byCurrXMode, bIsDwordAddress, dwCurrAddress);
560  if(!ret)
561  {
562  return ret;
563  }
564 
565  if (dwCurrAddress != (dwPrevAddress + 1))
566  {
567  handle_address_change(dwCurrAddress, dwPrevAddress, &bValidDataOffset, &byDataLength, &wDataLengthOffset, m_pBinConfig, &m_wDataOffset, nTemp);
568  }
569  dwPrevAddress = dwCurrAddress;
570 
571  handle_xdata_mode_switch(byCurrXMode, &byPrevXMode, &bValidDataOffset, &byDataLength, &wDataLengthOffset, m_pBinConfig, &m_wDataOffset);
572 
573  if (!process_key_entry(pszToken, szKeyEntry, szSeparators, m_pBinConfig, &m_wDataOffset, &dwPrevAddress, &byDataLength, &wDataLengthOffset, abyBinBuffer, &bValidDataOffset))
574  {
575  return FALSE;
576  }
577 
578  // Move to next Key Entry
579  pKeyName += (strlen(pKeyName) + 1);
580  }
581  if (m_wDataOffset <= 1)
582  {
583  return FALSE;
584  }
585 
586  handle_stop_opcode(bValidDataOffset, byDataLength, m_pBinConfig, wDataLengthOffset, &m_wDataOffset);
587 
588  // copy length
589  *binlength = m_wDataOffset;
590 
591  return TRUE;
592 }
593 
594 #endif
switchtec_convert_ini2bin
int switchtec_convert_ini2bin(FILE *szINIFileName, char *pclog, BYTE *m_pBinConfig, int *binlength)
Converts an INI configuration file to a binary format.
Definition: ini.c:444