int CMenus::DemolistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser) { CMenus *pSelf = (CMenus *)pUser; if(str_comp(pName, ".") == 0 || (str_comp(pName, "..") == 0 && str_comp(pSelf->m_aCurrentDemoFolder, "demos") == 0) || (!IsDir && !str_endswith(pName, ".demo"))) { return 0; } CDemoItem Item; str_copy(Item.m_aFilename, pName, sizeof(Item.m_aFilename)); if(IsDir) { str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pName); Item.m_Valid = false; } else { str_truncate(Item.m_aName, sizeof(Item.m_aName), pName, str_length(pName) - 5); Item.m_InfosLoaded = false; } Item.m_IsDir = IsDir != 0; Item.m_StorageType = StorageType; pSelf->m_lDemos.add_unsorted(Item); return 0; }
static int glob_for_cachedir(char *path) { int ret = 1; if (!str_endswith(path, "XXXXXX")) return ret; wordexp_t word_vector; char *p = solv_strdup(path); const int len = strlen(p); struct stat s; ret = 2; p[len-6] = '*'; p[len-5] = '\0'; if (wordexp(p, &word_vector, 0)) { solv_free(p); return ret; } for (int i = 0; i < word_vector.we_wordc; ++i) { char *entry = word_vector.we_wordv[i]; if (stat(entry, &s)) continue; if (S_ISDIR(s.st_mode) && s.st_uid == getuid()) { assert(strlen(path) == strlen(entry)); strcpy(path, entry); ret = 0; break; } } wordfree(&word_vector); solv_free(p); return ret; }
/** * Recursively create directory. * * If it is in the format accepted by mkdtemp() the function globs for a * matching name and if not found it uses mkdtemp() to create the path. 'path' * is modified in those two cases. */ int mkcachedir(char *path) { int ret = 1; if (!glob_for_cachedir(path)) return 0; const int len = strlen(path); if (len < 1 || path[0] != '/') return 1; // only absolute pathnames are accepted char *p = solv_strdup(path); if (p[len-1] == '/') p[len-1] = '\0'; if (access(p, X_OK)) { *(strrchr(p, '/')) = '\0'; ret = mkcachedir(p); if (str_endswith(path, "XXXXXX")) { char *retptr = mkdtemp(path); if (retptr == NULL) ret |= 1; } else ret |= mkdir(path, CACHEDIR_PERMISSIONS); } else { ret = 0; } solv_free(p); return ret; }
END_TEST START_TEST (test_encode_zeros) { struct latlon_double lls[4] = {{0, 0}, { 40.700, -120.950}, { 40.700, -120.950}, { 40.700, -120.950}}; encode (lls, 4); ck_assert (str_endswith(polyline_result(), "????")); ck_assert (str_startswith(polyline_result(), "??")); }
static size_t write_fru(char *eeprom) { gint result; const char *serial, *file; char *ser_num, *filename; time_t frutime; FILE *fp = NULL; size_t i; time_t tmp; struct tm *tmp2; char buf[256]; int j, n; struct dirent **namelist; GtkListStore *store; n = scandir(FRU_FILES, &namelist, 0, alphasort); /* No fru files, don't bother */ if (n < 0) { printf("didn't find FRU_Files in %s at %s(%s)\n", FRU_FILES, __FILE__, __func__); return 0; } g_object_set(dialogs.serial_num, "secondary_text", eeprom, NULL); filename = g_malloc(PATH_MAX); ser_num = malloc(128); memset(ser_num, 0, 128); fp = fopen(".serialnum", "r"); if (fp) { i = fread(ser_num, 1, 128, fp); if (!ferror(fp) && (i == 128 || feof(fp))) gtk_entry_set_text(GTK_ENTRY(serial_num), (const gchar*)&ser_num[1]); fclose(fp); } store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(fru_file_list))); gtk_list_store_clear(store); for (j = 0; j < n; j++) { if (namelist[j]->d_type == DT_REG && str_endswith(namelist[j]->d_name, ".bin")) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fru_file_list), namelist[j]->d_name); free(namelist[j]); } free(namelist); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fru_file_list), "Other..."); gtk_combo_box_set_active(GTK_COMBO_BOX(fru_file_list), ser_num[0]); free(ser_num); frutime = mins_since_jan_1_1996(); tmp = min2date(frutime); tmp2 = gmtime(&tmp); strftime(buf, sizeof(buf), "%a %b %d %H:%M %Y", tmp2); gtk_entry_set_text(GTK_ENTRY(fru_date), buf); get_serial_and_file: result = gtk_dialog_run(GTK_DIALOG(dialogs.serial_num)); i = 0; switch (result) { case GTK_RESPONSE_OK: serial = gtk_entry_get_text(GTK_ENTRY(serial_num)); if (strlen(serial) == 0) { create_blocking_popup(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "", "Serial number required"); goto get_serial_and_file; } file = gtk_combo_box_get_active_text(GTK_COMBO_BOX(fru_file_list)); if (strncmp(file, "Other...", 8) != 0) { snprintf(filename, PATH_MAX, FRU_FILES "%s", file); } else { /* manually choose fru file */ GtkWidget *dialog; dialog = gtk_file_chooser_dialog_new("Select FRU file", GTK_WINDOW(dialogs.serial_num), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); } gtk_widget_destroy(dialog); } if (filename) { fflush(NULL); sprintf(buf, "fru-dump -i %s -o %s -s %s -d %d 2>&1", filename, eeprom, serial, (unsigned int)frutime); #if DEBUG printf("%s\n", buf); #else fp = popen(buf, "r"); #endif if (!fp) { printf("can't execute \"%s\"\n", buf); } else { i = 0; while(fgets(buf, sizeof(buf), fp) != NULL) { /* fru-dump not installed */ if (strstr(buf, "not found")) printf("no fru-tools installed\n"); if (strstr(buf, "wrote") && strstr(buf, "bytes to") && strstr(buf, eeprom)) i = 1; } pclose(fp); } fp = fopen(".serialnum", "w"); if (fp) { fprintf(fp, "%c%s", gtk_combo_box_get_active(GTK_COMBO_BOX(fru_file_list)), serial); fclose(fp); } } break; case GTK_RESPONSE_DELETE_EVENT: break; default: printf("unknown response %d in %s\n", result, __func__); break; } gtk_widget_hide(GTK_WIDGET(dialogs.serial_num)); g_free(filename); return i; }
int main() { printf("=============================================\n"); /* * * * * * * * * str.h tests */ char* s = "test string"; // str_new() char* str_new_ = str_new(s); ass(str_new_ != s, "defferent ptr"); ass_eq(str_new_, s); // str_auto() char* str_auto_ = str_auto(str_new_); ass(str_auto_ != str_new_, "different ptr"); ass_eq(str_auto_, str_new_); // str_cat_new() char* str_cat_new_ = str_cat_new(s, " gnirts tset"); ass(str_cat_new_ != s, "different ptr"); ass_eq(str_cat_new_, "test string gnirts tset"); // str_cat_auto() char* str_cat_auto_ = str_cat_auto(str_cat_new_, "!!"); ass(str_cat_auto_ != str_cat_new_, "dif ptr"); ass_eq(str_cat_auto_, "test string gnirts tset!!"); // str_sub_new() char* str_sub_new_ = str_sub_new(s, 0, 4); ass_eq(str_sub_new_, "test"); // str_sub_auto() char* str_sub_auto_ = str_sub_auto(s, 5, 200); // overalocated? ass_eq(str_sub_auto_, "string"); ass_eq(str_sub_auto(s, 5, 5), ""); ass_eq(str_sub_auto(s, 9, 1), ""); // str_slice_new() char* str_slice_new_ = str_slice_new(s, 0, 4); ass_eq(str_slice_new_, "test"); ass_eq(str_slice_new(s, 0, 0), "test string"); ass_eq(str_slice_new(s, 5, 0), "string"); ass_eq(str_slice_new(s,-6, 0), "string"); // str_slice_auto() ass_eq(str_slice_auto(s,-6,-3), "str"); ass_eq(str_slice_auto(s,-1,-2), ""); ass_eq(str_slice_auto(s, 2, 1), ""); ass_eq(str_slice_auto(s, 5, 200), "string"); // overallocated? // str_input_dest() // str_input_new() // str_input_auto() // str_format_dest() // sprintf // str_format_new() // asprintf // str_format_auto() // str_len() // strlen // str_is_alnum() ass(str_is_alnum("abc123")); ass(! str_is_alnum("(@^*^&")); // str_is_alpha() ass(str_is_alpha("abcdEFG")); ass(! str_is_alpha("!@#$@#$")); // str_from_file_new() char* str_from_file_new_ = str_from_file_new("file.test"); ass_eq(str_from_file_new_, "file.test:test\n"); // str_eq() ass(str_eq("abc", "abc")); ass(str_eq("", "")); // str_endswith() ass(str_endswith(s, "string")); ass(str_endswith(s, "ing")); ass(str_endswith(s, "test string")); //ass(str_endswith(s, "")); //hm... //logs(str_slice_auto(s, -1 * strlen(""), 0)); ass(!str_endswith(s, "swing")); ass(!str_endswith(s, " test string")); // str_startswith() ass(str_startswith(s, "test")); ass(str_startswith(s, "test string")); ass(str_startswith(s, "")); }
/** * Parse arguments, extract ones we care about, and also work out * whether it will be possible to distribute this invocation remotely. * * This is a little hard because the cc argument rules are pretty complex, but * the function still ought to be simpler than it already is. * * This code is called on both the client and the server, though they use the * results differently. * * This function makes a copy of the arguments, modified to ensure that * the arguments include '-o <filename>'. This is returned in *ret_newargv. * The copy is dynamically allocated and the caller is responsible for * deallocating it. * * If @p forced_cpp_ext is non NULL, it is filled it with the extension that * is forced by a -x language directive. The caller should not free this * value. * * @returns 0 if it's ok to distribute this compilation, or an error code. **/ int dcc_scan_args(char *argv[], char **input_file, char **output_file, char ***ret_newargv, const char **forced_cpp_ext) { int seen_opt_c = 0, seen_opt_s = 0; int i; char *a, *optx_lang; const char *optx_ext = NULL; int ret; /* allow for -o foo.o */ if ((ret = dcc_copy_argv(argv, ret_newargv, 2)) != 0) return ret; argv = *ret_newargv; /* FIXME: new copy of argv is leaked */ dcc_trace_argv("scanning arguments", argv); #ifdef XCODE_INTEGRATION /* Xcode invokes the distcc client as "distcc --host-info HOST" to gather * info about HOST. When the request is transmitted to the distccd server, * it will see only "--host-info" and no other arguments in argv. */ if (argv[0] && !strcmp(argv[0], "--host-info")) { return 0; } #endif /* XCODE_INTEGRATION */ /* Things like "distcc -c hello.c" with an implied compiler are * handled earlier on by inserting a compiler name. At this * point, argv[0] should always be a compiler name. */ if (argv[0] && argv[0][0] == '-') { rs_log_error("unrecognized distcc option: %s", argv[0]); exit(EXIT_BAD_ARGUMENTS); } *input_file = *output_file = NULL; for (i = 0; (a = argv[i]); i++) { if (a[0] == '-') { if (!strcmp(a, "-E")) { rs_trace("-E call for cpp must be local"); return EXIT_DISTCC_FAILED; } else if (!strcmp(a, "-MD") || !strcmp(a, "-MMD")) { /* These two generate dependencies as a side effect. They * should work with the way we call cpp. */ } else if (!strcmp(a, "-MG") || !strcmp(a, "-MP")) { /* These just modify the behaviour of other -M* options and do * nothing by themselves. */ } else if (!strcmp(a, "-MF") || !strcmp(a, "-MT") || !strcmp(a, "-MQ")) { /* As above but with extra argument. */ i++; } else if (!strncmp(a, "-MF", 3) || !strncmp(a, "-MT", 3) || !strncmp(a, "-MQ", 3)) { /* As above, without extra argument. */ } else if (a[1] == 'M') { /* -M(anything else) causes the preprocessor to produce a list of make-style dependencies on header files, either to stdout or to a local file. It implies -E, so only the preprocessor is run, not the compiler. There would be no point trying to distribute it even if we could. */ rs_trace("%s implies -E (maybe) and must be local", a); return EXIT_DISTCC_FAILED; } else if (!strcmp(a, "-march=native")) { rs_trace("-march=native generates code for local machine; " "must be local"); return EXIT_DISTCC_FAILED; } else if (!strcmp(a, "-mtune=native")) { rs_trace("-mtune=native optimizes for local machine; " "must be local"); return EXIT_DISTCC_FAILED; } else if (str_startswith("-Wa,", a)) { /* Look for assembler options that would produce output * files and must be local. * * Writing listings to stdout could be supported but it might * be hard to parse reliably. */ if (strstr(a, ",-a") || strstr(a, "--MD")) { rs_trace("%s must be local", a); return EXIT_DISTCC_FAILED; } } else if (str_startswith("-specs=", a)) { rs_trace("%s must be local", a); return EXIT_DISTCC_FAILED; } else if (!strcmp(a, "-S")) { seen_opt_s = 1; } else if (!strcmp(a, "-fprofile-arcs") || !strcmp(a, "-ftest-coverage")) { rs_log_info("compiler will emit profile info; must be local"); return EXIT_DISTCC_FAILED; } else if (!strcmp(a, "-frepo")) { rs_log_info("compiler will emit .rpo files; must be local"); return EXIT_DISTCC_FAILED; } else if (!strcmp("-x", a)) { optx_lang = argv[++i]; if (!optx_lang || !strlen(optx_lang)) { rs_log_info("-x requires an argument; running locally"); return EXIT_DISTCC_FAILED; } if (*input_file) { rs_log_info("-x must precede source file; running locally"); return EXIT_DISTCC_FAILED; } if (optx_ext) { rs_log_info("at most one -x supported; running locally"); return EXIT_DISTCC_FAILED; } optx_ext = dcc_optx_ext_lookup(optx_lang); if (!optx_ext) { rs_log_info("unsupported -x language; running locally"); return EXIT_DISTCC_FAILED; } } else if (str_startswith("-x", a)) { /* Handling -xlanguage is possible, but it makes some of the * command rewriting (over in remote.c) much harder, so it * isn't supported at this time. */ rs_log_info("-xlanguage unsupported, use -x language instead; " "running locally"); return EXIT_DISTCC_FAILED; } else if (str_startswith("-dr", a)) { rs_log_info("gcc's debug option %s may write extra files; " "running locally", a); return EXIT_DISTCC_FAILED; } else if (!strcmp(a, "-c")) { seen_opt_c = 1; } else if (!strcmp(a, "-o")) { /* Whatever follows must be the output */ a = argv[++i]; goto GOT_OUTPUT; } else if (str_startswith("-o", a)) { a += 2; /* skip "-o" */ goto GOT_OUTPUT; } } else { if (dcc_is_source(a)) { rs_trace("found input file \"%s\"", a); if (*input_file) { rs_log_info("do we have two inputs? i give up"); return EXIT_DISTCC_FAILED; } *input_file = a; } else if (str_endswith(".o", a)) { GOT_OUTPUT: rs_trace("found object/output file \"%s\"", a); if (*output_file) { rs_log_info("called for link? i give up"); return EXIT_DISTCC_FAILED; } *output_file = a; } } } /* TODO: ccache has the heuristic of ignoring arguments that are not * extant files when looking for the input file; that's possibly * worthwile. Of course we can't do that on the server. */ if (!seen_opt_c && !seen_opt_s) { rs_log_info("compiler apparently called not for compile"); return EXIT_DISTCC_FAILED; } if (!*input_file) { rs_log_info("no visible input file"); return EXIT_DISTCC_FAILED; } if (dcc_source_needs_local(*input_file)) return EXIT_DISTCC_FAILED; if (!*output_file) { /* This is a commandline like "gcc -c hello.c". They want * hello.o, but they don't say so. For example, the Ethereal * makefile does this. * * Note: this doesn't handle a.out, the other implied * filename, but that doesn't matter because it would already * be excluded by not having -c or -S. */ char *ofile; /* -S takes precedence over -c, because it means "stop after * preprocessing" rather than "stop after compilation." */ if (seen_opt_s) { if (dcc_output_from_source(*input_file, ".s", &ofile)) return EXIT_DISTCC_FAILED; } else if (seen_opt_c) { if (dcc_output_from_source(*input_file, ".o", &ofile)) return EXIT_DISTCC_FAILED; } else { rs_log_crit("this can't be happening(%d)!", __LINE__); return EXIT_DISTCC_FAILED; } rs_log_info("no visible output file, going to add \"-o %s\" at end", ofile); dcc_argv_append(argv, strdup("-o")); dcc_argv_append(argv, ofile); *output_file = ofile; } dcc_note_compiled(*input_file, *output_file); if (strcmp(*output_file, "-") == 0) { /* Different compilers may treat "-o -" as either "write to * stdout", or "write to a file called '-'". We can't know, * so we just always run it locally. Hopefully this is a * pretty rare case. */ rs_log_info("output to stdout? running locally"); return EXIT_DISTCC_FAILED; } if (forced_cpp_ext) *forced_cpp_ext = optx_ext; return 0; }
static size_t write_fru(char *eeprom) { gint result; const char *serial, *file; char *ser_num; time_t frutime; FILE *fp = NULL; size_t i; time_t tmp; struct tm *tmp2; char buf[256]; struct dirent *ent; DIR *d; GtkListStore *store; d = opendir(FRU_FILES); /* No fru files, don't bother */ if (!d) { printf("didn't find FRU_Files in %s at %s(%s)\n", FRU_FILES, __FILE__, __func__); return 0; } g_object_set(dialogs.serial_num, "secondary_text", eeprom, NULL); ser_num = malloc (128); memset(ser_num, 0, 128); fp = fopen(".serialnum", "r"); if (fp) { i = fread(ser_num, 1, 128, fp); if (i >= 0) gtk_entry_set_text(GTK_ENTRY(serial_num), (const gchar*)&ser_num[1]); fclose(fp); } store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(fru_file_list))); gtk_list_store_clear (store); while ((ent = readdir(d))) { if (ent->d_type != DT_REG) continue; if (!str_endswith(ent->d_name, ".bin")) continue; gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fru_file_list), ent->d_name); } gtk_combo_box_set_active(GTK_COMBO_BOX(fru_file_list), ser_num[0]); free(ser_num); frutime = mins_since_jan_1_1996(); tmp = min2date(frutime); tmp2 = gmtime(&tmp); strftime(buf, sizeof(buf), "%a %b %d %H:%M %Y", tmp2); gtk_entry_set_text(GTK_ENTRY(fru_date), buf); result = gtk_dialog_run(GTK_DIALOG(dialogs.serial_num)); i = 0; switch (result) { case GTK_RESPONSE_OK: file = gtk_combo_box_get_active_text(GTK_COMBO_BOX(fru_file_list)); serial = gtk_entry_get_text(GTK_ENTRY(serial_num)); fflush(NULL); sprintf(buf, "fru-dump -i " FRU_FILES "%s -o %s -s %s -d %d 2>&1", file, eeprom, serial, (unsigned int)frutime); #if DEBUG printf("%s\n", buf); #else fp = popen(buf, "r"); #endif if (!fp) { printf("can't execute \"%s\"\n", buf); } else { i = 0; while(fgets(buf, sizeof(buf), fp) != NULL){ /* fru-dump not installed */ if (strstr(buf, "not found")) printf("no fru-tools installed\n"); if (strstr(buf, "wrote") && strstr(buf, "bytes to") && strstr(buf, eeprom)) i = 1; } pclose(fp); } fp = fopen(".serialnum", "w"); if (fp) { fprintf(fp, "%c%s", gtk_combo_box_get_active(GTK_COMBO_BOX(fru_file_list)), serial); fclose(fp); } break; case GTK_RESPONSE_DELETE_EVENT: break; default: printf("unknown response %d in %s\n", result, __func__); break; } gtk_widget_hide(GTK_WIDGET(dialogs.serial_num)); return i; }
static size_t dump_rr(enum DNS_RR rr, const parse_frame *f, const char *buf, size_t len, FILE *out) { char namebuf[256], targetbuf[256]; const char *name = buf; size_t namelen = dns_calc_len_name(name, len); const dns_answer *a = (dns_answer *)(buf + namelen); int bytes; (void)dump_chars_buf(namebuf, sizeof namebuf, name, namelen-1); bytes = fprintf(out, " %s name=%s type=%hu(%s) class=%hu(%s) ttl=%ld target=%s\n", RR[rr].name, namebuf, ntohs(a->type), type2str(ntohs(a->type)), a->class_, class2str(a->class_), (long)ntohl(a->ttl), addrformat(ntohs(a->type), targetbuf, sizeof targetbuf, (char *)a + sizeof *a, ntohs(a->rrlen))); #ifndef TEST /* TODO: split this block off to another function */ if (DNS_RR_AN == rr && DNS_Type_TXT == ntohs(a->type)) { /* is a TXT record answer; usually supplemental information that can * contain some interesting stuff */ const char *addrtype = NULL; char ipbuf[64]; const parse_frame *fi = f-2; if (PROT_IPv4 == fi->id) { const ipv4 *i = fi->off; addrtype = "4"; ipv4_addr_format(ipbuf, sizeof ipbuf, i->src); } else if (PROT_IPv6 == fi->id) { const ipv6 *i = fi->off; addrtype = "6"; ipv6_addr_format(ipbuf, sizeof ipbuf, i->src); } if (addrtype) { (void)dump_chars_buf(namebuf, sizeof namebuf, name, strip_c0(namebuf, namelen)); (void)dump_chars_buf(targetbuf, sizeof targetbuf, (char *)a + sizeof *a, strip_c0((char *)a + sizeof *a, ntohs(a->rrlen))); if ('\0' != namebuf[0]) rep_hint(addrtype, ipbuf, "DNS.TXT", namebuf, -1); if ('\0' != targetbuf[0]) rep_hint(addrtype, ipbuf, "DNS.TXT", targetbuf, -1); } } else if (DNS_RR_AN == rr && (DNS_Type_A == ntohs(a->type) || DNS_Type_AAAA == ntohs(a->type)) && str_endswith(namebuf, "\\x05local")) { /* we're looking for ".local" addresses; which may identify the machine */ char ipbuf[64]; const parse_frame *fi = f-2; const char *addrtype = NULL; if (PROT_IPv4 == fi->id) { const ipv4 *i = fi->off; addrtype = "4"; ipv4_addr_format(ipbuf, sizeof ipbuf, i->src); } else if (PROT_IPv6 == fi->id) { const ipv6 *i = fi->off; addrtype = "6"; ipv6_addr_format(ipbuf, sizeof ipbuf, i->src); } (void)dump_chars_buf(namebuf, sizeof namebuf, name, namelen-1); if ('\0' != namebuf[0]) { rep_hint(addrtype, ipbuf, "DNS.LOCAL", namebuf, -1); } { char localname[64]; /* first char is length of actual name */ if (name[0] > 0 && (unsigned)name[0] < sizeof localname) { strlcpy(localname, name+1, (size_t)name[0]+1); localname[(unsigned)name[0]] = '\0'; } else { strlcpy(localname, name+1, sizeof localname); } rep_addr(addrtype, ipbuf, "D", localname, "DNS.LOCAL", 1); } } #endif return (size_t)bytes; }
int CSkins::SkinScan(const char *pName, int IsDir, int DirType, void *pUser) { CSkins *pSelf = (CSkins *)pUser; if(IsDir || !str_endswith(pName, ".png")) return 0; char aNameWithoutPng[128]; str_copy(aNameWithoutPng, pName, sizeof(aNameWithoutPng)); aNameWithoutPng[str_length(aNameWithoutPng) - 4] = 0; // Don't add duplicate skins (one from user's config directory, other from // client itself) for(int i = 0; i < pSelf->Num(); i++) { const char *pExName = pSelf->Get(i)->m_aName; if(str_comp(pExName, aNameWithoutPng) == 0) return 0; } char aBuf[512]; str_format(aBuf, sizeof(aBuf), "skins/%s", pName); CImageInfo Info; if(!pSelf->Graphics()->LoadPNG(&Info, aBuf, DirType)) { str_format(aBuf, sizeof(aBuf), "failed to load skin from %s", pName); pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf); return 0; } CSkin Skin; Skin.m_IsVanilla = IsVanillaSkin(aNameWithoutPng); Skin.m_OrgTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0); int BodySize = 96; // body size if (BodySize > Info.m_Height) return 0; unsigned char *d = (unsigned char *)Info.m_pData; int Pitch = Info.m_Width*4; // dig out blood color { int aColors[3] = {0}; for(int y = 0; y < BodySize; y++) for(int x = 0; x < BodySize; x++) { if(d[y*Pitch+x*4+3] > 128) { aColors[0] += d[y*Pitch+x*4+0]; aColors[1] += d[y*Pitch+x*4+1]; aColors[2] += d[y*Pitch+x*4+2]; } } Skin.m_BloodColor = ColorRGBA(normalize(vec3(aColors[0], aColors[1], aColors[2]))); } // create colorless version int Step = Info.m_Format == CImageInfo::FORMAT_RGBA ? 4 : 3; // make the texture gray scale for(int i = 0; i < Info.m_Width*Info.m_Height; i++) { int v = (d[i*Step]+d[i*Step+1]+d[i*Step+2])/3; d[i*Step] = v; d[i*Step+1] = v; d[i*Step+2] = v; } int Freq[256] = {0}; int OrgWeight = 0; int NewWeight = 192; // find most common frequence for(int y = 0; y < BodySize; y++) for(int x = 0; x < BodySize; x++) { if(d[y*Pitch+x*4+3] > 128) Freq[d[y*Pitch+x*4]]++; } for(int i = 1; i < 256; i++) { if(Freq[OrgWeight] < Freq[i]) OrgWeight = i; } // reorder int InvOrgWeight = 255-OrgWeight; int InvNewWeight = 255-NewWeight; for(int y = 0; y < BodySize; y++) for(int x = 0; x < BodySize; x++) { int v = d[y*Pitch+x*4]; if(v <= OrgWeight) v = (int)(((v/(float)OrgWeight) * NewWeight)); else v = (int)(((v-OrgWeight)/(float)InvOrgWeight)*InvNewWeight + NewWeight); d[y*Pitch+x*4] = v; d[y*Pitch+x*4+1] = v; d[y*Pitch+x*4+2] = v; } Skin.m_ColorTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0); free(Info.m_pData); // set skin data str_copy(Skin.m_aName, aNameWithoutPng, sizeof(Skin.m_aName)); if(g_Config.m_Debug) { str_format(aBuf, sizeof(aBuf), "load skin %s", Skin.m_aName); pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf); } pSelf->m_aSkins.add(Skin); return 0; }