• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <stdio.h>
17 #include <stdint.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <limits.h>
22 #include <sys/stat.h>
23 #include "securec.h"
24 #include "cJSON.h"
25 #include "endian_internal.h"
26 #include "create_pcid.h"
27 
28 #ifdef SYSCAP_DEFINE_EXTERN_ENABLE
29 #include "syscap_define_custom.h"
30 #else
31 #include "syscap_define.h"
32 #endif
33 
34 #define SYSCAP_PREFIX_LEN 17
35 #define SINGLE_FEAT_LEN (SINGLE_SYSCAP_LEN - SYSCAP_PREFIX_LEN)
36 #define PCID_OUT_BUFFER 32
37 #define PRIVATE_SYSCAP_SIZE 1000
38 #define UINT8_BIT 8
39 
40 #define U32_TO_STR_MAX_LEN 11
41 
42 #define PRINT_ERR(...) \
43     do { \
44         printf("ERROR: [%s: %d] -> ", __FILE__, __LINE__); \
45         printf(__VA_ARGS__); \
46     } while (0)
47 
FreeContextBuffer(char * contextBuffer)48 static void FreeContextBuffer(char *contextBuffer)
49 {
50     (void)free(contextBuffer);
51 }
52 
GetFileContext(char * inputFile,char ** contextBufPtr,size_t * contextBufLen)53 static int32_t GetFileContext(char *inputFile, char **contextBufPtr, size_t *contextBufLen)
54 {
55     int32_t ret;
56     FILE *fp = NULL;
57     struct stat statBuf;
58     char *contextBuffer = NULL;
59     char path[PATH_MAX + 1] = {0x00};
60 
61 #ifdef _POSIX_
62     if (strlen(inputFile) > PATH_MAX || strncpy_s(path, PATH_MAX, inputFile, strlen(inputFile)) != EOK) {
63         PRINT_ERR("get path(%s) failed\n", inputFile);
64         return -1;
65     }
66 #else
67     if (strlen(inputFile) > PATH_MAX || realpath(inputFile, path) == NULL) {
68         PRINT_ERR("get file(%s) real path failed\n", inputFile);
69         return -1;
70     }
71 #endif
72 
73     ret = stat(path, &statBuf);
74     if (ret != 0) {
75         PRINT_ERR("get file(%s) st_mode failed, errno = %d\n", path, errno);
76         return -1;
77     }
78     if (!(statBuf.st_mode & S_IRUSR)) {
79         PRINT_ERR("don't have permission to read the file(%s)\n", path);
80         return -1;
81     }
82     contextBuffer = (char *)malloc(statBuf.st_size + 1);
83     if (contextBuffer == NULL) {
84         PRINT_ERR("malloc buffer failed, size = %d, errno = %d\n", (int32_t)statBuf.st_size + 1, errno);
85         return -1;
86     }
87 
88     fp = fopen(path, "rb");
89     if (fp == NULL) {
90         PRINT_ERR("open file(%s) failed, errno = %d\n", path, errno);
91         FreeContextBuffer(contextBuffer);
92         return -1;
93     }
94     size_t retFread = fread(contextBuffer, statBuf.st_size, 1, fp);
95     if (retFread != 1) {
96         PRINT_ERR("read file(%s) failed, errno = %d\n", path, errno);
97         FreeContextBuffer(contextBuffer);
98         (void)fclose(fp);
99         return -1;
100     }
101     contextBuffer[statBuf.st_size] = '\0';
102     (void)fclose(fp);
103 
104     *contextBufPtr = contextBuffer;
105     *contextBufLen = statBuf.st_size + 1;
106     return 0;
107 }
108 
ConvertedContextSaveAsFile(char * outDirPath,const char * filename,char * convertedBuffer,size_t contextBufLen)109 static int32_t ConvertedContextSaveAsFile(char *outDirPath, const char *filename, \
110                                           char *convertedBuffer, size_t contextBufLen)
111 {
112     int32_t ret;
113     FILE *fp = NULL;
114     char path[PATH_MAX + 1] = {0x00};
115 
116 #ifdef _POSIX_
117     if (strlen(outDirPath) > PATH_MAX || strncpy_s(path, PATH_MAX, outDirPath, strlen(outDirPath)) != EOK) {
118         PRINT_ERR("get path(%s) failed\n", outDirPath);
119         return -1;
120     }
121 #else
122     if (strlen(outDirPath) > PATH_MAX || realpath(outDirPath, path) == NULL) {
123         PRINT_ERR("get file(%s) real path failed\n", outDirPath);
124         return -1;
125     }
126 #endif
127     int32_t pathLen = strlen(path);
128     if (path[pathLen - 1] != '/' && path[pathLen - 1] != '\\') {
129         path[pathLen] = '/';
130     }
131 
132     if (strlen(path) + strlen(filename) + 1 > PATH_MAX) {
133         PRINT_ERR("length of path too long.\n");
134         return -1;
135     }
136     ret = strncat_s(path, PATH_MAX, filename, strlen(filename) + 1);
137     if (ret != 0) {
138         PRINT_ERR("strncat_s failed, (%s, %d, %s, %d), errno = %d\n",
139                   path, PATH_MAX, filename, (int32_t)strlen(filename) + 1, errno);
140         return -1;
141     }
142 
143     fp = fopen(path, "wb");
144     if (fp == NULL) {
145         PRINT_ERR("can't create file(%s), errno = %d\n", path, errno);
146         return -1;
147     }
148 
149     if (fwrite(convertedBuffer, contextBufLen, 1, fp) != 1) {
150         PRINT_ERR("can't write file(%s),errno = %d\n", path, errno);
151         (void)fclose(fp);
152         return -1;
153     }
154 
155     (void)fclose(fp);
156 
157     return 0;
158 }
159 
CreateWholeSyscapJsonObj(void)160 static cJSON *CreateWholeSyscapJsonObj(void)
161 {
162     size_t numOfSyscapAll = sizeof(g_arraySyscap) / sizeof(SyscapWithNum);
163     cJSON *root =  cJSON_CreateObject();
164     for (size_t i = 0; i < numOfSyscapAll; i++) {
165         cJSON_AddItemToObject(root, g_arraySyscap[i].str, cJSON_CreateNumber(g_arraySyscap[i].num));
166     }
167     return root;
168 }
169 
SetOsSyscap(PCIDMain * pcidBuffer,uint32_t osCapSize,const cJSON * jsonOsSyscapObj,const cJSON * allOsSyscapObj)170 int32_t SetOsSyscap(PCIDMain *pcidBuffer, uint32_t osCapSize,
171     const cJSON *jsonOsSyscapObj, const cJSON *allOsSyscapObj)
172 {
173     int32_t sectorOfBits, posOfBits;
174     cJSON *jsonArrayItem = NULL;
175     cJSON *osCapIndex = NULL;
176 
177     for (uint32_t i = 0; i < osCapSize; i++) {
178         jsonArrayItem = cJSON_GetArrayItem(jsonOsSyscapObj, (int)i);
179         if (jsonArrayItem == NULL || !cJSON_IsString(jsonArrayItem)) {
180             PRINT_ERR("Get jsonArrayItem failed.");
181             return -1;
182         }
183         osCapIndex = cJSON_GetObjectItem(allOsSyscapObj, jsonArrayItem->valuestring);
184         if (osCapIndex == NULL || !cJSON_IsNumber(osCapIndex)) {
185             PRINT_ERR("Get osCapIndex failed.");
186             return -1;
187         }
188         sectorOfBits = (osCapIndex->valueint) / UINT8_BIT;
189         posOfBits = (osCapIndex->valueint) % UINT8_BIT;
190         if (sectorOfBits >= OS_SYSCAP_BYTES) {
191             PRINT_ERR("num of \"os syscap\" is out of 960\n");
192             return -1;
193         }
194         pcidBuffer->osSyscap[sectorOfBits] |= 1 << (posOfBits);
195     }
196 
197     return 0;
198 }
199 
SetPriSyscap(PCIDMain * pcidBuffer,cJSON * jsonPriSyscapObj,uint32_t privateCapSize,uint16_t allPriSyscapStrLen)200 int32_t SetPriSyscap(PCIDMain *pcidBuffer, cJSON *jsonPriSyscapObj,
201     uint32_t privateCapSize, uint16_t allPriSyscapStrLen)
202 {
203     char *priSyscapHead = (char *)(pcidBuffer + 1);
204     char *priSyscapStr = NULL;
205     for (uint32_t i = 0; i < privateCapSize; i++) {
206         cJSON *jsonArrayItem = cJSON_GetArrayItem(jsonPriSyscapObj, (int)i);
207         if (jsonArrayItem == NULL || !cJSON_IsString(jsonArrayItem)) {
208             PRINT_ERR("get jsonArrayItem failed!");
209             return -1;
210         }
211         priSyscapStr = strchr(jsonArrayItem->valuestring, '.') + 1;
212         errno_t nRet = strcat_s(priSyscapHead, allPriSyscapStrLen + 1, priSyscapStr);
213         nRet += strcat_s(priSyscapHead, allPriSyscapStrLen + 1, ",");
214         if (nRet != EOK) {
215             PRINT_ERR("strcat_s \"pri\" string is failed\n");
216             return -1;
217         }
218     }
219     return 0;
220 }
221 
SetPCIDHeader(PCIDMain * pcidBuffer,const cJSON * jsonRootObj)222 int32_t SetPCIDHeader(PCIDMain *pcidBuffer, const cJSON *jsonRootObj)
223 {
224     cJSON *jsonSyscapObj = cJSON_GetObjectItem(jsonRootObj, "api_version");
225     if (jsonSyscapObj == NULL || !cJSON_IsNumber(jsonSyscapObj)) {
226         PRINT_ERR("get \"api_version\" failed\n");
227         return -1;
228     }
229     pcidBuffer->apiVersion = HtonsInter((uint16_t)jsonSyscapObj->valueint);
230     pcidBuffer->apiVersionType = 0;
231 
232     jsonSyscapObj = cJSON_GetObjectItem(jsonRootObj, "system_type");
233     if (jsonSyscapObj == NULL || !cJSON_IsString(jsonSyscapObj)) {
234         PRINT_ERR("get \"system_type\" failed\n");
235         return -1;
236     }
237     char *systemType = jsonSyscapObj->valuestring;
238     pcidBuffer->systemType = !strcmp(systemType, "mini") ? 0b001 :
239                             (!strcmp(systemType, "small") ? 0b010 :
240                             (!strcmp(systemType, "standard") ? 0b100 : 0));
241     if (pcidBuffer->systemType == 0) {
242         PRINT_ERR("\"system_type\" is invaild, systemType = \"%s\"\n", systemType);
243         return -1;
244     }
245 
246     jsonSyscapObj = cJSON_GetObjectItem(jsonRootObj, "manufacturer_id");
247     if (jsonSyscapObj == NULL || !cJSON_IsNumber(jsonSyscapObj)) {
248         PRINT_ERR("get \"manufacturer_id\" failed\n");
249         return -1;
250     }
251     pcidBuffer->manufacturerID = HtonlInter((uint32_t)jsonSyscapObj->valueint);
252 
253     return 0;
254 }
255 
GetOsAndPriSyscapSize(const cJSON * osSyscap,const cJSON * priSyscap,uint32_t * osCapSize,uint32_t * privateCapSize)256 int32_t GetOsAndPriSyscapSize(const cJSON *osSyscap, const cJSON *priSyscap,
257     uint32_t *osCapSize, uint32_t *privateCapSize)
258 {
259     *osCapSize = 0;
260     *privateCapSize = 0;
261 
262     // get os syscap size
263     if (osSyscap == NULL || !cJSON_IsArray(osSyscap)) {
264         PRINT_ERR("get \"os\" array failed\n");
265         return -1;
266     }
267     int32_t ret = cJSON_GetArraySize(osSyscap);
268     if (ret < 0) {
269         PRINT_ERR("get \"os\" array size failed\n");
270         return -1;
271     }
272     *osCapSize = (uint32_t)ret;
273 
274     // get private syscap size
275     if (priSyscap != NULL && cJSON_IsArray(priSyscap)) {
276         ret = cJSON_GetArraySize(priSyscap);
277         if (ret < 0) {
278             PRINT_ERR("get \"private syscap\" array size failed\n");
279             return -1;
280         }
281         *privateCapSize = (uint32_t)ret;
282     } else if (priSyscap == NULL) {
283         *privateCapSize = 0;
284     } else {
285         PRINT_ERR("get \"private\" array failed\n");
286         return -1;
287     }
288 
289     return 0;
290 }
291 
GetPriSyscapLen(uint32_t privateCapSize,cJSON * jsonPriSyscapObj,uint16_t * len)292 int32_t GetPriSyscapLen(uint32_t privateCapSize, cJSON *jsonPriSyscapObj, uint16_t *len)
293 {
294     for (uint32_t i = 0; i < privateCapSize; i++) {
295         cJSON *jsonArrayItem = cJSON_GetArrayItem(jsonPriSyscapObj, (int)i);
296         if (jsonArrayItem == NULL || !cJSON_IsString(jsonArrayItem)) {
297             PRINT_ERR("Get jsonArrayItem failed.");
298             return -1;
299         }
300         *len += (uint16_t)strlen(strchr(jsonArrayItem->valuestring, '.') + 1);
301         (*len)++;  // for separator ','
302     }
303     if ((*len + 1) > PRIVATE_SYSCAP_SIZE) {
304         PRINT_ERR("context of \"pri\" array is too many.\n");
305         return -1;
306     }
307     return 0;
308 }
309 
CreatePCID(char * inputFile,char * outDirPath)310 int32_t CreatePCID(char *inputFile, char *outDirPath)
311 {
312     uint32_t privateCapSize, osCapSize;
313     size_t contextBufLen;
314     char *contextBuffer = NULL;
315     cJSON *allOsSyscapObj = CreateWholeSyscapJsonObj();
316 
317     int32_t ret = GetFileContext(inputFile, &contextBuffer, &contextBufLen);
318     if (ret != 0) {
319         PRINT_ERR("GetFileContext failed, input file : %s\n", inputFile);
320         goto FREE_CONVERT_OUT;
321     }
322 
323     cJSON *jsonRootObj = cJSON_ParseWithLength(contextBuffer, contextBufLen);
324     if (jsonRootObj == NULL) {
325         PRINT_ERR("cJSON_Parse failed, context buffer is:\n%s\n", contextBuffer);
326         ret = -1;
327         goto FREE_CONVERT_OUT;
328     }
329 
330     cJSON *jsonSyscapObj = cJSON_GetObjectItem(jsonRootObj, "syscap");
331     if (jsonSyscapObj == NULL || !cJSON_IsObject(jsonSyscapObj)) {
332         PRINT_ERR("get \"syscap\" object failed\n");
333         ret = -1;
334         goto FREE_CONVERT_OUT;
335     }
336 
337     cJSON *jsonOsSyscapObj = cJSON_GetObjectItem(jsonSyscapObj, "os");
338     cJSON *jsonPriSyscapObj = cJSON_GetObjectItem(jsonSyscapObj, "private");
339     ret = GetOsAndPriSyscapSize(jsonOsSyscapObj, jsonPriSyscapObj, &osCapSize, &privateCapSize);
340     if (ret != 0) {
341         goto FREE_CONVERT_OUT;
342     }
343 
344     uint16_t allPriSyscapStrLen = 0;
345     ret = GetPriSyscapLen(privateCapSize, jsonPriSyscapObj, &allPriSyscapStrLen);
346     if (ret != 0) {
347         goto FREE_CONVERT_OUT;
348     }
349 
350     uint16_t pcidLength = sizeof(PCIDMain) + allPriSyscapStrLen + 1;
351     PCIDMain *pcidBuffer = (PCIDMain *)malloc(pcidLength);
352     if (pcidBuffer == NULL) {
353         PRINT_ERR("malloc for pcid buffer failed\n");
354         ret = -1;
355         goto FREE_CONVERT_OUT;
356     }
357     (void)memset_s(pcidBuffer, pcidLength, 0, pcidLength);
358 
359     ret = SetOsSyscap(pcidBuffer, osCapSize, jsonOsSyscapObj, allOsSyscapObj);
360     ret += SetPriSyscap(pcidBuffer, jsonPriSyscapObj, privateCapSize, allPriSyscapStrLen);
361     ret += SetPCIDHeader(pcidBuffer, jsonRootObj);
362     if (ret != 0) {
363         goto FREE_PCID_BUFFER_OUT;
364     }
365 
366     const char pcidFileName[] = "PCID.sc";
367     ret = ConvertedContextSaveAsFile(outDirPath, pcidFileName, (char *)pcidBuffer, pcidLength);
368     if (ret != 0) {
369         PRINT_ERR("Save as file failed, outDirPath:%s, filename:%s\n", outDirPath, pcidFileName);
370         goto FREE_PCID_BUFFER_OUT;
371     }
372 
373 FREE_PCID_BUFFER_OUT:
374     free(pcidBuffer);
375 FREE_CONVERT_OUT:
376     cJSON_Delete(allOsSyscapObj);
377     FreeContextBuffer(contextBuffer);
378     return ret;
379 }
380 
GetOsSyscap(PCIDMain * pcidMain,cJSON * sysCapObject)381 int32_t GetOsSyscap(PCIDMain *pcidMain, cJSON *sysCapObject)
382 {
383     uint32_t i, j, countOfSyscap = 0;
384     uint8_t osSyscap[OS_SYSCAP_BYTES] = {0};
385     uint16_t indexOfSyscap[OS_SYSCAP_BYTES * UINT8_BIT] = {0};
386 
387     cJSON *capVectorPtr = cJSON_CreateArray();
388     if (capVectorPtr == NULL) {
389         PRINT_ERR("cJSON_CreateArray failed\n");
390         return -1;
391     }
392 
393     // 8, bytes of pcid header
394     errno_t nRet = memcpy_s(osSyscap, OS_SYSCAP_BYTES, (uint8_t *)pcidMain + 8, OS_SYSCAP_BYTES);
395     if (nRet != EOK) {
396         PRINT_ERR("memcpy_s failed.");
397         return -1;
398     }
399 
400     for (i = 0; i < OS_SYSCAP_BYTES; i++) {
401         for (j = 0; j < UINT8_BIT; j++) {
402             if (osSyscap[i] & (0x01 << j)) {
403                 indexOfSyscap[countOfSyscap++] = i * UINT8_BIT + j;
404             }
405         }
406     }
407     for (i = 0; i < countOfSyscap; i++) {
408         for (j = 0; j < sizeof(g_arraySyscap) / sizeof(SyscapWithNum); j++) {
409             if (g_arraySyscap[j].num == indexOfSyscap[i]) {
410                 if (!cJSON_AddItemToArray(capVectorPtr, cJSON_CreateString(g_arraySyscap[j].str))) {
411                     printf("cJSON_AddItemToArray or cJSON_CreateString failed\n");
412                     return -1;
413                 }
414             }
415         }
416     }
417 
418     if (!cJSON_AddItemToObject(sysCapObject, "os", capVectorPtr)) {
419         PRINT_ERR("cJSON_AddItemToObject failed\n");
420         return -1;
421     }
422 
423     return 0;
424 }
425 
GetPriSyscap(PCIDMain * pcidMain,cJSON * sysCapObject,size_t contextBufLen)426 int32_t GetPriSyscap(PCIDMain *pcidMain, cJSON *sysCapObject, size_t contextBufLen)
427 {
428     cJSON *capVectorPtr = cJSON_CreateArray();
429     if (capVectorPtr == NULL) {
430         PRINT_ERR("cJSON_CreateArray failed\n");
431         return -1;
432     }
433 
434     int32_t privateSyscapLen = (int32_t)(contextBufLen - sizeof(PCIDMain) - 1);
435     if (privateSyscapLen < 0) {
436         PRINT_ERR("parse private syscap failed.");
437         return -1;
438     } else if (privateSyscapLen == 0) {
439         return 0;
440     }
441 
442     char fullCapStr[SINGLE_SYSCAP_LEN] = {0};
443     char priSyscapStr[SINGLE_SYSCAP_LEN] = {0};
444     char *tempPriSyscapStr = priSyscapStr;
445     char *ptrPrivateSyscap = (char *)(pcidMain + 1);
446     while (*ptrPrivateSyscap != '\0') {
447         if (*ptrPrivateSyscap == ',') {
448             *tempPriSyscapStr = '\0';
449             int32_t ret = sprintf_s(fullCapStr, SINGLE_SYSCAP_LEN, "SystemCapability.%s", priSyscapStr);
450             if (ret == -1) {
451                 printf("sprintf_s failed\n");
452                 return -1;
453             }
454             if (!cJSON_AddItemToArray(capVectorPtr, cJSON_CreateString(fullCapStr))) {
455                 printf("cJSON_AddItemToArray or cJSON_CreateString failed\n");
456                 return -1;
457             }
458             tempPriSyscapStr = priSyscapStr;
459             ptrPrivateSyscap++;
460             continue;
461         }
462         *tempPriSyscapStr++ = *ptrPrivateSyscap++;
463     }
464     if (!cJSON_AddItemToObject(sysCapObject, "private", capVectorPtr)) {
465         PRINT_ERR("cJSON_AddItemToObject failed\n");
466         return -1;
467     }
468 
469     return 0;
470 }
471 
DecodePCID(char * inputFile,char * outDirPath)472 int32_t DecodePCID(char *inputFile, char *outDirPath)
473 {
474     int32_t ret = 0;
475     char *contextBuffer = NULL;
476     size_t contextBufLen;
477 
478     ret = GetFileContext(inputFile, &contextBuffer, &contextBufLen);
479     if (ret != 0) {
480         PRINT_ERR("GetFileContext failed, input file : %s\n", inputFile);
481         return -1;
482     }
483 
484     PCIDMain *pcidMain = (PCIDMain *)contextBuffer;
485 
486     /* api version */
487     if (pcidMain->apiVersionType != 0) {
488         PRINT_ERR("Prase file failed, apiVersionType is invaild, input file : %s\n", inputFile);
489         ret = -1;
490         goto FREE_CONTEXT_OUT;
491     }
492 
493     /* system type */
494     char *systemType = pcidMain->systemType == 0b001 ? "mini" :
495                        (pcidMain->systemType == 0b010 ? "small" :
496                        (pcidMain->systemType == 0b100 ? "standard" : NULL));
497     if (systemType == NULL) {
498         PRINT_ERR("prase file failed, systemType is invaild, %u\n", pcidMain->systemType);
499         ret = -1;
500         goto FREE_CONTEXT_OUT;
501     }
502 
503     /* syscap */
504     cJSON *sysCapObj = cJSON_CreateObject();
505     if (sysCapObj == NULL) {
506         PRINT_ERR("cJSON_CreateObject failed\n");
507         ret = -1;
508         goto FREE_CONTEXT_OUT;
509     }
510 
511     if (GetOsSyscap(pcidMain, sysCapObj) != 0) {
512         goto FREE_CONTEXT_OUT;
513     }
514     if (GetPriSyscap(pcidMain, sysCapObj, contextBufLen) != 0) {
515         goto FREE_CONTEXT_OUT;
516     }
517 
518     // create json root
519     cJSON *jsonRootObj = cJSON_CreateObject();
520     if (jsonRootObj == NULL) {
521         PRINT_ERR("cJSON_CreateObject failed\n");
522         ret = -1;
523         goto FREE_SYSCAP_OUT;
524     }
525 
526     if (!cJSON_AddNumberToObject(jsonRootObj, "api_version", NtohsInter(pcidMain->apiVersion))) {
527         PRINT_ERR("cJSON_AddNumberToObject failed\n");
528         ret = -1;
529         goto FREE_ROOT_OUT;
530     }
531     if (!cJSON_AddNumberToObject(jsonRootObj, "manufacturer_id", NtohlInter(pcidMain->manufacturerID))) {
532         PRINT_ERR("cJSON_AddNumberToObject failed\n");
533         ret = -1;
534         goto FREE_ROOT_OUT;
535     }
536     if (!cJSON_AddStringToObject(jsonRootObj, "system_type", systemType)) {
537         PRINT_ERR("cJSON_AddStringToObject failed\n");
538         ret = -1;
539         goto FREE_ROOT_OUT;
540     }
541     if (!cJSON_AddItemToObject(jsonRootObj, "syscap", sysCapObj)) {
542         PRINT_ERR("cJSON_AddItemToObject failed\n");
543         ret = -1;
544         goto FREE_ROOT_OUT;
545     }
546     sysCapObj = NULL; // avoid being released repeatedly.
547 
548     char *strJson = cJSON_Print(jsonRootObj);
549     const char outputFileName[] = "PCID.json";
550     ret = ConvertedContextSaveAsFile(outDirPath, outputFileName, strJson, strlen(strJson));
551     if (ret != 0) {
552         PRINT_ERR("ConvertedContextSaveAsFile failed, outDirPath:%s, filename:%s\n", outDirPath, outputFileName);
553         goto FREE_CONVERT_OUT;
554     }
555 
556 FREE_CONVERT_OUT:
557     free(strJson);
558 FREE_ROOT_OUT:
559     cJSON_Delete(jsonRootObj);
560 FREE_SYSCAP_OUT:
561     cJSON_Delete(sysCapObj);
562 FREE_CONTEXT_OUT:
563     FreeContextBuffer(contextBuffer);
564     return ret;
565 }
566 
567 #define U32_TO_STR_MAX_LEN 11
568 #define OS_SYSCAP_NUM 30
569 #define PCID_HEADER 2
ParseStringSyscap(char * input,uint32_t * osSyscap,uint32_t osSyscapNum,uint32_t * header,uint32_t headerLen)570 static int32_t ParseStringSyscap(char *input, uint32_t *osSyscap, uint32_t osSyscapNum,
571                                  uint32_t *header, uint32_t headerLen)
572 {
573     int32_t ret;
574     uint32_t tempNum;
575     uint32_t i = 0;
576     size_t inputLen = strlen(input);
577 
578     if (osSyscapNum != OS_SYSCAP_NUM || headerLen != PCID_HEADER) {
579         PRINT_ERR("Input osSyscapNum(%u) or headerLen(%u) error.\n", osSyscapNum, headerLen);
580         return -1;
581     }
582 
583     if (sscanf_s(input, "%u,%u,%s", &header[0], &header[1], input, inputLen) != 3) { // 3, return val of "%u,%u,%s"
584         PRINT_ERR("Get pcid header failed.\n");
585         return -1;
586     }
587 
588     while ((ret = sscanf_s(input, "%u,%s", &tempNum, input, inputLen)) > 0) {
589         osSyscap[i++] = tempNum;
590         if (i >= OS_SYSCAP_NUM) {
591             break;
592         }
593     }
594     if (ret == -1) {
595         PRINT_ERR("sscanf_s failed, i = %u.\n", i);
596         return -1;
597     }
598 
599     if (strlen(input) <= 1) {
600         *input = '\0';
601     }
602 
603     return 0;
604 }
605 
AddHeaderToJsonObj(uint32_t * pcidHeader,uint32_t pcidHeaderLen,cJSON * rootObj)606 static int32_t AddHeaderToJsonObj(uint32_t *pcidHeader, uint32_t pcidHeaderLen, cJSON *rootObj)
607 {
608     if (pcidHeaderLen != PCID_HEADER) {
609         PRINT_ERR("input pcidHeader(%u) error.\n", pcidHeaderLen);
610         return -1;
611     }
612 
613     PCIDHeader *header = (PCIDHeader *)pcidHeader;
614     // trans system type to string
615     char *systemType = header->systemType  == 0b001 ? "mini" :
616                        (header->systemType == 0b010 ? "small" :
617                        (header->systemType == 0b100 ? "standard" : NULL));
618     if (systemType == NULL) {
619         PRINT_ERR("prase system type failed.\n");
620         return -1;
621     }
622 
623     // add to json
624     if (!cJSON_AddNumberToObject(rootObj, "api_version", NtohsInter(header->apiVersion))) {
625         PRINT_ERR("add api_version(%u) to json object failed.\n", NtohsInter(header->apiVersion));
626         return -1;
627     }
628     if (!cJSON_AddNumberToObject(rootObj, "manufacturer_id", NtohlInter(header->manufacturerID))) {
629         PRINT_ERR("add manufacturer_id(%u) to json object failed\n", NtohlInter(header->manufacturerID));
630         return -1;
631     }
632     if (!cJSON_AddStringToObject(rootObj, "system_type", systemType)) {
633         PRINT_ERR("add system_type(%s) to json object failed\n", systemType);
634         return -1;
635     }
636     return 0;
637 }
638 
AddOsSyscapToJsonObj(uint32_t * osSyscapArray,uint32_t osSyscapArrayLen,cJSON * sysCapObj)639 static int32_t AddOsSyscapToJsonObj(uint32_t *osSyscapArray, uint32_t osSyscapArrayLen, cJSON *sysCapObj)
640 {
641     cJSON *sysCapArray = cJSON_CreateArray();
642     if (sysCapArray == NULL) {
643         PRINT_ERR("Create cJSON array failed.\n");
644         return -1;
645     }
646 
647     if (osSyscapArrayLen != OS_SYSCAP_NUM) {
648         PRINT_ERR("Input os syscap array len error.\n");
649         free(sysCapArray);
650         return -1;
651     }
652     uint8_t *osSysCapArrayUint8 = (uint8_t *)osSyscapArray;
653 
654     uint32_t i, j;
655     uint32_t osSyscapCount = 0;
656     uint16_t index[OS_SYSCAP_BYTES * UINT8_BIT] = {0};
657     for (i = 0; i < OS_SYSCAP_BYTES; i++) {
658         for (j = 0; j < UINT8_BIT; j++) {
659             if (osSysCapArrayUint8[i] & (0x01 << j)) {
660                 index[osSyscapCount++] = i * UINT8_BIT + j;
661             }
662         }
663     }
664 
665     for (i = 0; i < osSyscapCount; i++) {
666         for (j = 0; j < sizeof(g_arraySyscap) / sizeof(SyscapWithNum); j++) {
667             if (index[i] != g_arraySyscap[j].num) {
668                 continue;
669             }
670             if (!cJSON_AddItemToArray(sysCapArray, cJSON_CreateString(g_arraySyscap[j].str))) {
671                 PRINT_ERR("Add os syscap string to json failed.\n");
672                 free(sysCapArray);
673                 return -1;
674             }
675             break;
676         }
677     }
678 
679     if (!cJSON_AddItemToObject(sysCapObj, "os", sysCapArray)) {
680         PRINT_ERR("Add os syscap item to json object failed.\n");
681         free(sysCapArray);
682         return -1;
683     }
684     return 0;
685 }
686 
AddPriSyscapToJsonObj(char * priSyscapString,uint32_t priSyscapStringLen,cJSON * sysCapObj)687 static int32_t AddPriSyscapToJsonObj(char *priSyscapString, uint32_t priSyscapStringLen, cJSON *sysCapObj)
688 {
689     char *token = NULL;
690 
691     cJSON *sysCapArray = cJSON_CreateArray();
692     if (sysCapArray == NULL) {
693         PRINT_ERR("Create cJSON array failed.\n");
694         free(sysCapArray);
695         return -1;
696     }
697     if (priSyscapStringLen == 0) {
698         if (!cJSON_AddItemToObject(sysCapObj, "private", sysCapArray)) {
699             PRINT_ERR("Add private syscap array to json failed.\n");
700             free(sysCapArray);
701             return -1;
702         }
703         return 0;
704     }
705 
706     token = strtok(priSyscapString, ",");
707     while (token != NULL) {
708         if (!cJSON_AddItemToArray(sysCapArray, cJSON_CreateString(token))) {
709             PRINT_ERR("Add private syscap string to json failed.\n");
710             free(sysCapArray);
711             return -1;
712         }
713         token = strtok(NULL, ",");
714     }
715     if (!cJSON_AddItemToObject(sysCapObj, "private", sysCapArray)) {
716         PRINT_ERR("Add private syscap array to json failed.\n");
717         free(sysCapArray);
718         return -1;
719     }
720     return 0;
721 }
722 
DecodeStringPCIDToJson(char * input,char * outDirPath)723 int32_t DecodeStringPCIDToJson(char *input, char *outDirPath)
724 {
725     int32_t ret = -1;
726     uint32_t osSyscap[OS_SYSCAP_NUM] = {0};
727     uint32_t pcidHeader[PCID_HEADER];
728     size_t fileContextLen;
729     char *ctx = NULL;
730     char *priSyscapStr = NULL;
731 
732     if (GetFileContext(input, &ctx, &fileContextLen) != 0) {
733         PRINT_ERR("GetFileContext failed, input file : %s\n", input);
734         goto PARSE_FAILED;
735     }
736     if (ParseStringSyscap(ctx, osSyscap, OS_SYSCAP_NUM, pcidHeader, PCID_HEADER) != 0) {
737         PRINT_ERR("Parse string syscap failed.\n");
738         goto PARSE_FAILED;
739     }
740     priSyscapStr = ctx;
741 
742     // add to json object
743     cJSON *sysCapObj = cJSON_CreateObject();
744     cJSON *rootObj = cJSON_CreateObject();
745     if (!cJSON_AddItemToObject(rootObj, "syscap", sysCapObj)) {
746         PRINT_ERR("Add syscap to json failed.\n");
747         goto ADD_JSON_FAILED;
748     }
749     if (AddHeaderToJsonObj(pcidHeader, PCID_HEADER, rootObj) != 0) {
750         PRINT_ERR("Add header to json object failed.\n");
751         goto ADD_JSON_FAILED;
752     }
753     if (AddOsSyscapToJsonObj(osSyscap, OS_SYSCAP_NUM, sysCapObj) != 0) {
754         PRINT_ERR("Add os syscap json object failed.\n");
755         goto ADD_JSON_FAILED;
756     }
757     if (AddPriSyscapToJsonObj(priSyscapStr, (uint32_t)strlen(priSyscapStr), sysCapObj) != 0) {
758         PRINT_ERR("Add private syscap json object failed.\n");
759         goto ADD_JSON_FAILED;
760     }
761     // save as json file
762     char *jsonBuffer = cJSON_Print(rootObj);
763     const char outputFileName[] = "PCID.json";
764     if (ConvertedContextSaveAsFile(outDirPath, outputFileName,
765                                    jsonBuffer, strlen(jsonBuffer)) != 0) {
766         PRINT_ERR("Save as json file failed.\n");
767         goto SAVE_FAILED;
768     }
769     ret = 0;
770 
771 SAVE_FAILED:
772     free(jsonBuffer);
773 ADD_JSON_FAILED:
774     cJSON_Delete(rootObj);
775 PARSE_FAILED:
776     free(ctx);
777     return ret;
778 }
779 
EncodePcidscToString(char * inputFile,char * outDirPath)780 int32_t EncodePcidscToString(char *inputFile, char *outDirPath)
781 {
782     int32_t ret = 0;
783     size_t bufferLen, privateSyscapLen, outputLen;
784     uint32_t i, j;
785     uint32_t *mainSyscap = NULL;
786     uint16_t priSyscapCount = 0;
787     char *contextBuffer = NULL;
788     char *privateSyscap = NULL;
789     char *priSyscapFull = NULL;
790     char *output = NULL;
791     PCIDMain *pcidMain = NULL;
792 
793     ret = GetFileContext(inputFile, &contextBuffer, &bufferLen);
794     if (ret != 0) {
795         PRINT_ERR("Get pcid file failed, pcid file path: %s\n", inputFile);
796         return -1;
797     }
798 
799     if (bufferLen > 1128) { // 1128, max size of pcid.sc
800         PRINT_ERR("Input pcid file too large, pcid file size: %zu\n", bufferLen);
801         goto FREE_CONTEXT;
802     }
803 
804     pcidMain = (PCIDMain *)contextBuffer;
805     privateSyscap = (char *)(pcidMain + 1);
806     privateSyscapLen = strlen(privateSyscap);
807 
808     // process os syscap
809     mainSyscap = (uint32_t *)pcidMain;
810 
811     // process private syscap
812     for (i = 0; i < privateSyscapLen; i++) {
813         if (privateSyscap[i] == ',') {
814             priSyscapCount++;
815         }
816     }
817     if (priSyscapCount == 0) {
818         goto OUT_PUT;
819     }
820     priSyscapFull = (char *)malloc(priSyscapCount * SINGLE_SYSCAP_LEN);
821     if (priSyscapFull == NULL) {
822         PRINT_ERR("malloc failed\n");
823         goto FREE_PRISYSCAP_FULL;
824     }
825     (void)memset_s(priSyscapFull, priSyscapCount * SINGLE_SYSCAP_LEN,
826                    0, priSyscapCount * SINGLE_SYSCAP_LEN);
827     char tempSyscap[SINGLE_SYSCAP_LEN] = {0};
828     char *temp = tempSyscap;
829     for (i = 0, j = 0; i < privateSyscapLen; i++) {
830         if (*privateSyscap == ',') {
831             *temp = '\0';
832             ret = sprintf_s(priSyscapFull + j * SINGLE_SYSCAP_LEN, SINGLE_SYSCAP_LEN,
833                             "SystemCapability.%s", tempSyscap);
834             if (ret == -1) {
835                 PRINT_ERR("sprintf_s failed\n");
836                 goto FREE_PRISYSCAP_FULL;
837             }
838             temp = tempSyscap;
839             privateSyscap++;
840             j++;
841             continue;
842         }
843         *temp++ = *privateSyscap++;
844     }
845     // output
846 OUT_PUT:
847     // 17, size of "SystemCapability."
848     outputLen = U32_TO_STR_MAX_LEN * PCID_OUT_BUFFER + 17 * priSyscapCount + privateSyscapLen + 1;
849     output = (char *)malloc(outputLen);
850     if (output == NULL) {
851         PRINT_ERR("malloc failed\n");
852         goto FREE_PRISYSCAP_FULL;
853     }
854     (void)memset_s(output, outputLen, 0, outputLen);
855     ret = sprintf_s(output, outputLen, "%u", mainSyscap[0]);
856     if (ret == -1) {
857         PRINT_ERR("sprintf_s failed\n");
858         goto FREE_OUTPUT;
859     }
860     for (i = 1; i < PCID_OUT_BUFFER; i++) {
861         ret = sprintf_s(output, outputLen, "%s,%u", output, mainSyscap[i]);
862         if (ret == -1) {
863             PRINT_ERR("sprintf_s failed\n");
864             goto FREE_OUTPUT;
865         }
866     }
867     for (i = 0; i < priSyscapCount; i++) {
868         ret = sprintf_s(output, outputLen, "%s,%s", output, priSyscapFull + i * SINGLE_SYSCAP_LEN);
869         if (ret == -1) {
870             PRINT_ERR("sprintf_s failed\n");
871             goto FREE_OUTPUT;
872         }
873     }
874     // save as file
875     const char outputFileName[] = "PCID.txt";
876     ret = ConvertedContextSaveAsFile(outDirPath, outputFileName, output, strlen(output));
877     if (ret != 0) {
878         PRINT_ERR("ConvertedContextSaveAsFile failed, outDirPath:%s, filename:%s\n", outDirPath, outputFileName);
879         goto FREE_OUTPUT;
880     }
881 
882 FREE_OUTPUT:
883     free(output);
884 FREE_PRISYSCAP_FULL:
885     free(priSyscapFull);
886 FREE_CONTEXT:
887     free(contextBuffer);
888     return ret;
889 }