/** * Copyright (c) 2021 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "../../utils/common.hpp" #include "../../utils/file.hpp" #include "../../utils/csv.hpp" #include "../../utils/xml.hpp" #include #include #include #include #include struct LanguageString { std::string key; std::string value; }; int32_t parseString( xml_t *stringNode, std::string key, std::map> *strings ) { auto attrLang = xmlGetAttributeByName(stringNode, "lang"); if(attrLang == -1) { std::cout << "String is missing lang parameter." << std::endl; return -1; } std::string lang(stringNode->attributeDatas[attrLang]); struct LanguageString str; str.key = key; str.value = std::string(stringNode->value); auto existing = (*strings).find(lang); if(existing == (*strings).end()) { (*strings).insert(std::make_pair(lang, std::vector())); } (*strings)[lang].push_back(str); return 0; } int32_t parseGroup( xml_t *groupNode, std::string key, std::map> *strings ) { int32_t ret; auto attrKey = xmlGetAttributeByName(groupNode, "key"); if(attrKey == -1) { std::cout << "Group node is missing key" << std::endl; return 1; } if(key.size() > 0) key += "."; key += std::string(groupNode->attributeDatas[attrKey]); for(int32_t i = 0; i < groupNode->childrenCount; i++) { auto c = groupNode->children + i; if(std::string(c->node) == "string") { ret = parseString(c, key, strings); if(ret != 0) return ret; } else if(std::string(c->node) == "group") { ret = parseGroup(c, key, strings); if(ret != 0) return ret; } } return 0; } int main(int argc, char *argv[]) { if(argc != 3) { std::cout << "Invalid number of arguments provided to language gen!" << std::endl; return 1; } char *fileInName = argv[1]; fileNormalizeSlashes(fileInName); FILE *fileIn = fopen(fileInName, "rb"); if(fileIn == NULL) { std::cout << "Failed to open input file " << fileInName << std::endl; return 1; } auto size = assetReadString(fileIn, NULL); char *buffer = (char *)malloc(sizeof(char) * size); if(buffer == NULL) { std::cout << "Failed to allocate memory for locale string XML" << std::endl; fclose(fileIn); return 1; } assetReadString(fileIn, buffer); fclose(fileIn); xml_t xml; xmlLoad(&xml, buffer); free(buffer); // Begin parsing. Start by looking for the tags std::vector languages; for(int32_t i = 0; i < xml.childrenCount; i++) { auto c = xml.children + i; if(std::string(c->node) != "language") continue; auto attrName = xmlGetAttributeByName(c, "name"); if(attrName == -1) { std::cout << "Missing name param on language node" << std::endl; xmlDispose(&xml); return 1; } languages.push_back(std::string(c->attributeDatas[attrName])); } // Now begin actually parsing std::map> strings; for(int32_t i = 0; i < xml.childrenCount; i++) { auto c = xml.children + i; if(std::string(c->node) == "group") { auto ret = parseGroup(c, "", &strings); if(ret != 0) { xmlDispose(&xml); return ret; } } else if(std::string(c->node) == "string") { std::cout << "String cannot be a root node" << std::endl; xmlDispose(&xml); return 1; } } xmlDispose(&xml); // Now we validate each lang has each key. std::vector keys; auto it = strings.begin(); while(it != strings.end()) { auto it2 = it->second.begin(); while(it2 != it->second.end()) { auto key = it2->key; auto exist = std::find(keys.begin(), keys.end(), key); if(exist == keys.end()) { keys.push_back(key); } it2++; } ++it; } // Now we actually parse each string, validating as we go. it = strings.begin(); while(it != strings.end()) { std::vector itKeys; std::string bufferOut = ""; auto it2 = it->second.begin(); while(it2 != it->second.end()) { auto l = *it2; itKeys.push_back(l.key); bufferOut += l.key + "|" + l.value + "|"; it2++; } std::string filenameOut(argv[2]); filenameOut += "/language_" + it->first + ".language"; char *filenameOutC = (char *)malloc(sizeof(char) * (filenameOut.size() + 1)); if(filenameOutC == NULL) { std::cout << "Failed to allocate filename memory" << std::endl; return 1; } strcpy(filenameOutC, filenameOut.c_str()); fileNormalizeSlashes(filenameOutC); fileMkdirp(filenameOutC); FILE *fileOut = fopen(filenameOutC, "wb"); free(filenameOutC); if(fileOut == NULL) { std::cout << "Failed to create output file " << filenameOut << std::endl; return 1; } const char *strOut = bufferOut.c_str(); fwrite(strOut, sizeof(char), strlen(strOut), fileOut); fclose(fileOut); auto it3 = keys.begin(); while(it3 != keys.end()) { auto key = *it3; auto inIt = std::find(itKeys.begin(), itKeys.end(), key); if(inIt == itKeys.end()) { std::cout << "Locale " << it->first << " missing key " << key << std::endl; } it3++; } if(itKeys.size() != keys.size()) { std::cout << "Locale is missing some keys, see above" << std::endl; return 1; } ++it; } return 0; }