blob: 91268e59b3f84b6b81a307e7c1ade2d8da1acced [file] [log] [blame]
/* MediaTek Inc. (C) 2016. All rights reserved.
*
* Copyright Statement:
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*/
/*
* Description:
* Implement ParamTreeView related APIs
*/
#include "AudioParamParserPriv.h"
EXPORT ParamTreeView *paramTreeViewCreate(AudioType *audioType, int verMaj, int verMin) {
ParamTreeView *paramTreeView = malloc(sizeof(ParamTreeView));
paramTreeView->audioType = audioType;
paramTreeView->verMaj = verMaj;
paramTreeView->verMin = verMin;
paramTreeView->treeRootHash = NULL;
return paramTreeView;
}
EXPORT void paramTreeViewRelease(ParamTreeView *paramTreeView) {
if (paramTreeView) {
if (paramTreeView->treeRootHash) {
TreeRoot *tmp, *item;
HASH_ITER(hh, paramTreeView->treeRootHash, item, tmp) {
HASH_DEL(paramTreeView->treeRootHash, item);
treeRootRelease(item);
}
}
free(paramTreeView);
}
}
EXPORT TreeRoot *treeRootCreate(const char *name, xmlNode *treeRootNode, ParamTreeView *paramTreeView) {
TreeRoot *treeRoot = malloc(sizeof(TreeRoot));
treeRoot->name = strdup(name);
treeRoot->treeRootNode = treeRootNode;
treeRoot->paramTreeView = paramTreeView;
treeRoot->featureHash = NULL;
treeRoot->switchFieldInfo = NULL;
return treeRoot;
}
EXPORT void treeRootRelease(TreeRoot *treeRoot) {
if (treeRoot) {
if (treeRoot->featureHash) {
Feature *tmp, *item;
HASH_ITER(hh, treeRoot->featureHash, item, tmp) {
HASH_DEL(treeRoot->featureHash, item);
featureRelease(item);
}
}
free(treeRoot->name);
free(treeRoot);
}
}
EXPORT Feature *featureCreate(const char *name, AudioType *audioType, FieldInfo *switchFieldInfo, const char *featureOption) {
Feature *feature = malloc(sizeof(Feature));
feature->name = strdup(name);
feature->audioType = audioType;
if (featureOption) {
feature->featureOption = strdup(featureOption);
} else {
feature->featureOption = NULL;
}
feature->categoryPathHash = NULL;
feature->featureFieldHash = NULL;
feature->switchFieldInfo = switchFieldInfo;
return feature;
}
EXPORT void featureRelease(Feature *feature) {
if (feature) {
if (feature->categoryPathHash) {
CategoryPath *tmp, *item;
HASH_ITER(hh, feature->categoryPathHash, item, tmp) {
HASH_DEL(feature->categoryPathHash, item);
categoryPathRelease(item);
}
}
if (feature->featureFieldHash) {
FeatureField *tmp, *item;
HASH_ITER(hh, feature->featureFieldHash, item, tmp) {
HASH_DEL(feature->featureFieldHash, item);
featureFieldRelease(item);
}
}
if (feature->name) {
free(feature->name);
}
if (feature->featureOption) {
free(feature->featureOption);
}
free(feature);
}
}
EXPORT APP_STATUS categoryPathValidation(CategoryPath *categoryPath) {
char *path;
char *categoryGroup;
char *restOfStr = NULL;
if (!strncmp(categoryPath->path, "", strlen("") + 1)) {
return APP_NO_ERROR;
}
path = strdup(categoryPath->path);
categoryGroup = utilStrtok(path, ARRAY_SEPERATOR, &restOfStr);
if (categoryGroup == NULL || audioTypeValidCategoryGroupName(categoryPath->feature->audioType, categoryGroup) == APP_ERROR) {
free(path);
return APP_ERROR;
}
while ((categoryGroup = utilStrtok(NULL, ARRAY_SEPERATOR, &restOfStr)) != NULL) {
if (audioTypeValidCategoryGroupName(categoryPath->feature->audioType, categoryGroup) == APP_ERROR) {
free(path);
return APP_ERROR;
}
}
free(path);
return APP_NO_ERROR;
}
EXPORT CategoryPath *categoryPathCreate(Feature *feature, const char *path) {
CategoryPath *categoryPath = malloc(sizeof(CategoryPath));
categoryPath->path = strdup(path);
categoryPath->feature = feature;
#ifdef WIN32
/* The category path validation only run on win32 */
if (categoryPathValidation(categoryPath) == APP_ERROR) {
ERR_LOG("The %s feature's category path is not belong to categoryGroup! (%s)\n", feature->name, categoryPath->path);
categoryPathRelease(categoryPath);
return NULL;
}
#endif
return categoryPath;
}
EXPORT void categoryPathRelease(CategoryPath *categoryPath) {
if (categoryPath) {
free(categoryPath->path);
free(categoryPath);
}
}
EXPORT FeatureField *featureFieldCreate(FieldInfo *fieldInfo) {
FeatureField *featureField = malloc(sizeof(FeatureField));
featureField->fieldInfo = fieldInfo;
return featureField;
}
EXPORT void featureFieldRelease(FeatureField *featureField) {
if (featureField) {
free(featureField);
}
}
EXPORT Feature *treeRootGetFeatureByName(TreeRoot *treeRoot, const char *featureName) {
Feature *feature;
HASH_FIND_STR(treeRoot->featureHash, featureName, feature);
return feature;
}
CategoryPath *findFeatureCategoryPath(char **arr, int *Switch, int n, Feature *feature) {
CategoryPath *categoryPath = NULL;
UT_string *path = NULL;
int i;
/* Generate the search string */
utstring_new(path);
for (i = 0; i < n; ++i) {
if (i == n - 1) {
utstring_printf(path, "%s", arr[Switch[i]]);
} else {
utstring_printf(path, "%s,", arr[Switch[i]]);
}
}
/* Find the categoryPath */
HASH_FIND_STR(feature->categoryPathHash, utstring_body(path), categoryPath);
DEBUG_LOG("Search path = %s, paramTree = 0x%p\n", utstring_body(path), categoryPath);
utstring_free(path);
return categoryPath;
}
CategoryPath *fuzzySearchFeatureCategoryPath(char **arr, int totalSize, int pickSize, Feature *feature) {
CategoryPath *categoryPath = NULL;
int i, j, pos = pickSize - 1;
int *swpArray;
if (pickSize > totalSize) {
return categoryPath;
}
swpArray = (int *)malloc(sizeof(int) * totalSize);
for (i = 0; i < totalSize; ++i) {
swpArray[i] = i;
}
categoryPath = findFeatureCategoryPath(arr, swpArray, pickSize, feature);
if (categoryPath) {
free(swpArray);
return categoryPath;
}
do {
if (swpArray[pickSize - 1] == totalSize - 1) {
--pos;
} else {
pos = pickSize - 1;
}
++swpArray[pos];
for (j = pos + 1; j < pickSize; ++j) {
swpArray[j] = swpArray[j - 1] + 1;
}
categoryPath = findFeatureCategoryPath(arr, swpArray, pickSize, feature);
if (categoryPath) {
free(swpArray);
return categoryPath;
}
} while (swpArray[0] < totalSize - pickSize);
free(swpArray);
return categoryPath;
}
CategoryPath *searchFeatureCategoryPath(Feature *feature, const char *categoryPath) {
CategoryPath *featureCategoryPath;
char **categoryArray;
char *category;
char *tmpStr;
char *restOfStr = NULL;
size_t numOfCategoryType;
size_t numOfCategory;
size_t i = 0;
DEBUG_LOG("+Feature = %s, categoryPath = %s\n", feature->name, categoryPath);
/* Full path search first */
HASH_FIND_STR(feature->categoryPathHash, categoryPath, featureCategoryPath);
if (featureCategoryPath) {
DEBUG_LOG("fuzzySearch paramTree found. (path = %s)\n", featureCategoryPath->path);
return featureCategoryPath;
} else if (!strncmp(categoryPath, "", strlen("") + 1)) {
return NULL;
}
/* Setup array for fuzzy search path enum */
numOfCategoryType = audioTypeGetNumOfCategoryType(feature->audioType);
if (numOfCategoryType > 0) {
categoryArray = malloc(sizeof(char *) * numOfCategoryType);
if (NULL == categoryArray) {
ERR_LOG("allocate working buf fail");
return NULL;
}
}
tmpStr = strdup(categoryPath ? categoryPath : "");
category = utilStrtok(tmpStr, ARRAY_SEPERATOR, &restOfStr);
if (!category) {
ERR_LOG("Cannot parse category\n");
free(categoryArray);
free(tmpStr);
return NULL;
}
categoryArray[i++] = category;
while ((category = utilStrtok(NULL, ARRAY_SEPERATOR, &restOfStr)) != NULL) {
categoryArray[i++] = category;
}
numOfCategory = i;
/* Fuzzy search */
for (i = 1; i < numOfCategory; i++) {
featureCategoryPath = fuzzySearchFeatureCategoryPath(categoryArray, numOfCategory, numOfCategory - i, feature);
if (featureCategoryPath) {
break;
}
}
if (!featureCategoryPath) {
/* If no paramTree found, try to get the root paramTree */
UT_string *path = NULL;
utstring_new(path);
utstring_printf(path, "%s", "");
HASH_FIND_STR(feature->categoryPathHash, utstring_body(path), featureCategoryPath);
utstring_free(path);
}
free(categoryArray);
free(tmpStr);
DEBUG_LOG("-fuzzySearch featureCategoryPath %s found. \n", featureCategoryPath ? "" : "not ");
return featureCategoryPath;
}
EXPORT int featureIsCategoryPathSupport(Feature *feature, const char *categoryPath) {
/* Get the category path */
CategoryPath *featureCategoryPath = NULL;
UT_string *searchPath;
if (!feature) {
ERR_LOG("feature is NULL\n");
return 0;
}
if (!categoryPath) {
ERR_LOG("categoryPath is NULL\n");
return 0;
}
/* Check if feature support all categoryPath first */
featureCategoryPath = searchFeatureCategoryPath(feature, "");
if (featureCategoryPath) {
return 1;
}
searchPath = utilNormalizeCategoryGroupPathForAudioType(categoryPath, feature->audioType);
if (!searchPath) {
ERR_LOG("Cannot normalize categoryPath for %s AudioType. (path = %s)\n", feature->audioType->name, categoryPath);
return 0;
}
/* Search the feature's category path */
featureCategoryPath = searchFeatureCategoryPath(feature, utstring_body(searchPath));
utstring_free(searchPath);
if (featureCategoryPath) {
return 1;
} else {
return 0;
}
}