# HG changeset patch # User Matti Hamalainen # Date 1509289984 -7200 # Node ID 513c467f3a8792c00dcbbd409ef9ddf2b81d3086 # Parent 6539555f00b04ac2ea3633f8d5d05cc7382f31c6 Implement basic search functionality. Has bugs and limitations to be rid of. diff -r 6539555f00b0 -r 513c467f3a87 mapsearch.c --- a/mapsearch.c Sun Oct 29 05:18:21 2017 +0200 +++ b/mapsearch.c Sun Oct 29 17:13:04 2017 +0200 @@ -62,6 +62,15 @@ } MAPInfoCtx; +typedef struct +{ + char *map; + int mx, my, wx, wy; + double accuracy; + BOOL centered; +} MAPMatch; + + /* Options */ MAPInfoCtx optMaps[SET_MAX_MAPS]; @@ -613,6 +622,117 @@ } +void mapPerformSearch(struct lws *wsi, const unsigned char *data, const size_t len, char **verr) +{ + int width, height, centerX, centerY; + MapBlock *pattern = NULL; + MAPMatch matches[SET_MAX_MATCHES]; + int nmatches = 0, maxMatches = SET_MAX_MATCHES; + BOOL centerFound; + + // Parse pattern block dimensions + mapBlockGetDimensions(data, len - 10, &width, &height); + if (width <= 0 || height <= 0) + { + *verr = "Could not parse map block dimensions."; + goto out; + } + + if (width * height < 3) + { + *verr = "Search block pattern too small."; + goto out; + } + + if ((pattern = mapBlockAlloc(width, height)) == NULL) + goto out; + + if (!mapBlockParse(data, len, pattern)) + { + *verr = "Error parsing map block data."; + goto out; + } + + // Entropy check + int entropy = mapBlockGetEntropy(pattern, optCleanChars, strlen(optCleanChars)); + + if ((entropy < 2 && width < 10 && height < 10) || + (entropy < 3 && width * height < 6)) + { + *verr = "Search block entropy insufficient."; + goto out; + } + + // Find pattern center marker, if any + centerFound = mapBlockFindCenter(pattern, "*@", ¢erX, ¢erY, 20); + + // Clean the pattern from characters we do not want to match + mapBlockClean(pattern, optCleanChars); + + // Search maps .. + for (int nmap = 0; nmap < optNMaps; nmap++) + { + MAPInfoCtx *info = &optMaps[nmap]; + + for (int oy = 0; oy < info->map->height - height - 1; oy++) + for (int ox = 0; ox < info->map->width - width - 1; ox++) + { + double accuracy = mapMatchBlock(info->map, pattern, ox, oy, 0, TRUE); + if (accuracy > 99.5f) + { + MAPMatch *match = &matches[nmatches++]; + + match->map = info->locFile.continent; + match->mx = ox + centerX; + match->my = oy + centerY; + match->wx = optWorldXC + info->locFile.x + ox + centerX; + match->wy = optWorldYC + info->locFile.y + oy + centerY; + match->accuracy = accuracy; + match->centered = centerFound; + + if (nmatches >= SET_MAX_MATCHES || nmatches >= maxMatches) + goto out; + } + } + } + +out: + mapBlockFree(pattern); + + if (*verr != NULL) + return; + + if (nmatches > 0) + { + char *buf = NULL; + size_t bufLen = 0, bufSize = 0; + + th_strbuf_puts(&buf, &bufSize, &bufLen, "RESULT:["); + + for (int n = 0; n < nmatches; n++) + { + MAPMatch *match = &matches[n]; + char *vstr = th_strdup_printf( + "[%1.2f,%d,\"%s\",%d,%d,%d,%d]%s", + match->accuracy, + match->centered, + match->map, + match->mx, match->my, + match->wx, match->wy, + (n < nmatches - 1) ? "," : ""); + + th_strbuf_puts(&buf, &bufSize, &bufLen, vstr); + th_free(vstr); + } + + th_strbuf_puts(&buf, &bufSize, &bufLen, "]"); + lws_write(wsi, (unsigned char *) buf, bufLen, LWS_WRITE_TEXT); + } + else + *verr = "No matches found."; +} + + int mapLWSCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) @@ -627,6 +747,32 @@ case LWS_CALLBACK_RECEIVE: { + char *data = (char *) in; + unsigned char *udata = (unsigned char *) in; + char *verr = NULL; + + if (len >= 10 && strncmp(data, "MAPSEARCH\n", 10) == 0) + { + if (len <= 10 + 1) + verr = "Search pattern data too small."; + else + mapPerformSearch(wsi, udata + 10, len - 10, &verr); + } + else + { + verr = "Invalid command/search query, not enough data."; + } + + if (verr != NULL) + { + THERR("%s\n", verr); + char *vstr = th_strdup_printf("ERROR:%s", verr); + lws_write(wsi, (unsigned char *) vstr, strlen(vstr), LWS_WRITE_TEXT); + th_free(vstr); + } + + verr = "END"; + lws_write(wsi, (unsigned char *) verr, strlen(verr), LWS_WRITE_TEXT); lws_close_reason(wsi, LWS_CLOSE_STATUS_NOSTATUS, NULL, 0); } break;