private void doFilterText(String text, Pattern delimitersPattern,
                            @NotNull Map<String, String> additionalProperties,
                            @Nullable Map<String, String> resolvedPropertiesParam,
                            final Appendable out) throws IOException {
    Map<String, String> resolvedProperties = resolvedPropertiesParam;

    final Matcher matcher = delimitersPattern.matcher(text);

    boolean hasEscapeString = !StringUtil.isEmpty(myModuleConfiguration.escapeString);

    final int groupCount = matcher.groupCount();
    int firstPropertyGroupIndex = hasEscapeString ? 3 : 0;

    int last = 0;
    while (matcher.find()) {
      out.append(text, last, matcher.start());
      last = matcher.end();

      if (hasEscapeString) {
        if (matcher.group(1) != null) {
          out.append(myModuleConfiguration.escapeString).append(myModuleConfiguration.escapeString); // double escape string
          continue;
        }
        else if (matcher.group(2) != null) {
          out.append(matcher.group(3)); // escaped value
          continue;
        }
      }

      String propertyName = null;

      for (int i = firstPropertyGroupIndex; i < groupCount; i++) {
        propertyName = matcher.group(i + 1);
        if (propertyName != null) {
          break;
        }
      }

      assert propertyName != null;

      if (resolvedProperties == null) {
        resolvedProperties = new HashMap<>();
      }

      String propertyValue = resolvedProperties.get(propertyName);
      if (propertyValue == null) {
        if (resolvedProperties.containsKey(propertyName)) { // if cyclic property dependencies
          out.append(matcher.group());
          continue;
        }

        String resolved = myProjectConfig.resolveProperty(propertyName, myModuleConfiguration, additionalProperties);
        if (resolved == null) {
          out.append(matcher.group());
          continue;
        }

        resolvedProperties.put(propertyName, null);

        StringBuilder sb = new StringBuilder();
        doFilterText(resolved, delimitersPattern, additionalProperties, resolvedProperties, sb);
        propertyValue = sb.toString();

        resolvedProperties.put(propertyName, propertyValue);
      }

      if (myModuleConfiguration.escapeWindowsPaths) {
        MavenEscapeWindowsCharacterUtils.escapeWindowsPath(out, propertyValue);
      }
      else {
        out.append(propertyValue);
      }
    }

    out.append(text, last, text.length());
  }
private void doFilterText(String text, Pattern delimitersPattern,
                            @NotNull Map<String, String> additionalProperties,
                            @Nullable Map<String, String> resolvedPropertiesParam,
                            final Appendable out)