From 5df4e29051a0b27273b413f8357c6aa467858cdf Mon Sep 17 00:00:00 2001
From: Ludovic Poitou <ludovic.poitou@forgerock.com>
Date: Wed, 13 Mar 2013 08:48:57 +0000
Subject: [PATCH] Fix for OPENDJ-800 : Support escaping characters in make-ldif templates. The main set of changes have been provided by Elliot Kandall @ UCSF, but I've done additional cleanup of code and refactoring, added support for multiple constants per lines (this was required by the support for escaping [ and ]. Unit tests are provided and have been extended after the code review and suggestions by reviewers (CR-1401).

---
 opendj-sdk/opends/src/server/org/opends/server/tools/makeldif/TemplateFile.java |  197 +++++++++++++++++++++++-------------------------
 1 files changed, 95 insertions(+), 102 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/makeldif/TemplateFile.java b/opendj-sdk/opends/src/server/org/opends/server/tools/makeldif/TemplateFile.java
index 2de6f2d..5bd5f77 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/makeldif/TemplateFile.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/makeldif/TemplateFile.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2013 ForgeRock AS.
  */
 package org.opends.server.tools.makeldif;
 import org.opends.messages.Message;
@@ -707,33 +708,8 @@
     {
       String line = lines[lineNumber];
 
-      // See if there are any constant definitions in the line that need to be
-      // replaced.  We'll do that first before any further processing.
-      int closePos = line.lastIndexOf(']');
-      if (closePos > 0)
-      {
-        StringBuilder lineBuffer = new StringBuilder(line);
-        int openPos = line.lastIndexOf('[', closePos);
-        if (openPos >= 0)
-        {
-          String constantName =
-               toLowerCase(line.substring(openPos+1, closePos));
-          String constantValue = templateFileConstants.get(constantName);
-          if (constantValue == null)
-          {
-            Message message = WARN_MAKELDIF_WARNING_UNDEFINED_CONSTANT.get(
-                    constantName, lineNumber);
-            warnings.add(message);
-          }
-          else
-          {
-            lineBuffer.replace(openPos, closePos+1, constantValue);
-          }
-        }
-
-        line = lineBuffer.toString();
-      }
-
+      line = replaceConstants(line, lineNumber,
+                              templateFileConstants, warnings);
 
       String lowerLine = toLowerCase(line);
       if ((line.length() == 0) || line.startsWith("#"))
@@ -837,35 +813,8 @@
           }
           else
           {
-            // See if there are any constant definitions in the line that need
-            // to be replaced.  We'll do that first before any further
-            // processing.
-            closePos = line.lastIndexOf(']');
-            if (closePos > 0)
-            {
-              StringBuilder lineBuffer = new StringBuilder(line);
-              int openPos = line.lastIndexOf('[', closePos);
-              if (openPos >= 0)
-              {
-                String constantName =
-                     toLowerCase(line.substring(openPos+1, closePos));
-                String constantValue = templateFileConstants.get(constantName);
-                if (constantValue == null)
-                {
-                  Message message =
-                          WARN_MAKELDIF_WARNING_UNDEFINED_CONSTANT.get(
-                                  constantName, lineNumber);
-                  warnings.add(message);
-                }
-                else
-                {
-                  lineBuffer.replace(openPos, closePos+1, constantValue);
-                }
-              }
-
-              line = lineBuffer.toString();
-            }
-
+            line = replaceConstants(line, lineNumber,
+                                    templateFileConstants, warnings);
             lineList.add(line);
           }
         }
@@ -875,7 +824,7 @@
 
         Branch b = parseBranchDefinition(branchLines, lineNumber,
                                          templateFileIncludeTags,
-                                         templateFileConstants, warnings);
+            warnings);
         DN branchDN = b.getBranchDN();
         if (templateFileBranches.containsKey(branchDN))
         {
@@ -908,35 +857,8 @@
           }
           else
           {
-            // See if there are any constant definitions in the line that need
-            // to be replaced.  We'll do that first before any further
-            // processing.
-            closePos = line.lastIndexOf(']');
-            if (closePos > 0)
-            {
-              StringBuilder lineBuffer = new StringBuilder(line);
-              int openPos = line.lastIndexOf('[', closePos);
-              if (openPos >= 0)
-              {
-                String constantName =
-                     toLowerCase(line.substring(openPos+1, closePos));
-                String constantValue = templateFileConstants.get(constantName);
-                if (constantValue == null)
-                {
-                  Message message =
-                          WARN_MAKELDIF_WARNING_UNDEFINED_CONSTANT.get(
-                                  constantName, lineNumber);
-                  warnings.add(message);
-                }
-                else
-                {
-                  lineBuffer.replace(openPos, closePos+1, constantValue);
-                }
-              }
-
-              line = lineBuffer.toString();
-            }
-
+            line = replaceConstants(line, lineNumber,
+                                    templateFileConstants, warnings);
             lineList.add(line);
           }
         }
@@ -946,8 +868,7 @@
 
         Template t = parseTemplateDefinition(templateLines, startLineNumber,
                                              templateFileIncludeTags,
-                                             templateFileConstants,
-                                             templateFileTemplates, warnings);
+            templateFileTemplates, warnings);
         String lowerName = toLowerCase(t.getName());
         if (templateFileTemplates.containsKey(lowerName))
         {
@@ -989,18 +910,76 @@
   }
 
 
+  /**
+   * Parse a line and replace all constants within [ ] with their
+   * values.
+   *
+   * @param line        The line to parse.
+   * @param lineNumber  The line number in the template file.
+   * @param constants   The set of constants defined in the template file.
+   * @param warnings    A list into which any warnings identified may be
+   *                    placed.
+   * @return The line in which all constant variables have been replaced
+   *         with their value
+   */
+  private String replaceConstants(String line, int lineNumber,
+                                  Map<String,String> constants,
+                                  List<Message> warnings)
+  {
+    int closePos = line.lastIndexOf(']');
+    // Loop until we've scanned all closing brackets
+    do
+    {
+      // Skip escaped closing brackets
+      while (closePos > 0 &&
+          line.charAt(closePos - 1) == '\\')
+      {
+        closePos = line.lastIndexOf(']', closePos - 1);
+      }
+      if (closePos > 0)
+      {
+        StringBuilder lineBuffer = new StringBuilder(line);
+        int openPos = line.lastIndexOf('[', closePos);
+        // Find the opening bracket. If it's escaped, then it's not a constant
+        if ((openPos > 0 && line.charAt(openPos - 1) != '\\') ||
+            (openPos == 0))
+        {
+          String constantName =
+              toLowerCase(line.substring(openPos+1, closePos));
+          String constantValue = constants.get(constantName);
+          if (constantValue == null)
+          {
+            Message message = WARN_MAKELDIF_WARNING_UNDEFINED_CONSTANT.get(
+                constantName, lineNumber);
+            warnings.add(message);
+          }
+          else
+          {
+            lineBuffer.replace(openPos, closePos+1, constantValue);
+          }
+        }
+        if (openPos >= 0)
+        {
+          closePos = openPos;
+        }
+        line = lineBuffer.toString();
+        closePos = line.lastIndexOf(']', closePos);
+      }
+    } while (closePos > 0);
+    return line;
+  }
 
   /**
    * Parses the information contained in the provided set of lines as a MakeLDIF
    * branch definition.
    *
+   *
    * @param  branchLines      The set of lines containing the branch definition.
    * @param  startLineNumber  The line number in the template file on which the
    *                          first of the branch lines appears.
    * @param  tags             The set of defined tags from the template file.
    *                          Note that this does not include the tags that are
    *                          always registered by default.
-   * @param  constants        The set of constants defined in the template file.
    * @param  warnings         A list into which any warnings identified may be
    *                          placed.
    *
@@ -1013,8 +992,7 @@
    */
   private Branch parseBranchDefinition(String[] branchLines,
                                        int startLineNumber,
-                                       LinkedHashMap<String,Tag> tags,
-                                       LinkedHashMap<String,String> constants,
+                                       Map<String, Tag> tags,
                                        List<Message> warnings)
           throws InitializationException, MakeLDIFException
   {
@@ -1108,6 +1086,7 @@
    * Parses the information contained in the provided set of lines as a MakeLDIF
    * template definition.
    *
+   *
    * @param  templateLines     The set of lines containing the template
    *                           definition.
    * @param  startLineNumber   The line number in the template file on which the
@@ -1115,8 +1094,6 @@
    * @param  tags              The set of defined tags from the template file.
    *                           Note that this does not include the tags that are
    *                           always registered by default.
-   * @param  constants         The set of constants defined in the template
-   *                           file.
    * @param  definedTemplates  The set of templates already defined in the
    *                           template file.
    * @param  warnings          A list into which any warnings identified may be
@@ -1131,11 +1108,9 @@
    */
   private Template parseTemplateDefinition(String[] templateLines,
                                            int startLineNumber,
-                                           LinkedHashMap<String,Tag> tags,
-                                           LinkedHashMap<String,String>
-                                                constants,
-                                           LinkedHashMap<String,Template>
-                                                definedTemplates,
+                                           Map<String, Tag> tags,
+                                           Map<String, Template>
+                                               definedTemplates,
                                            List<Message> warnings)
           throws InitializationException, MakeLDIFException
   {
@@ -1316,7 +1291,7 @@
   private TemplateLine parseTemplateLine(String line, String lowerLine,
                                          int lineNumber, Branch branch,
                                          Template template,
-                                         LinkedHashMap<String,Tag> tags,
+                                         Map<String,Tag> tags,
                                          List<Message> warnings)
           throws InitializationException, MakeLDIFException
   {
@@ -1405,9 +1380,10 @@
     final int PARSING_STATIC_TEXT     = 0;
     final int PARSING_REPLACEMENT_TAG = 1;
     final int PARSING_ATTRIBUTE_TAG   = 2;
+    final int PARSING_ESCAPED_CHAR    = 3;
 
     int phase = PARSING_STATIC_TEXT;
-
+    int previousPhase = PARSING_STATIC_TEXT;
 
     ArrayList<Tag> tagList = new ArrayList<Tag>();
     StringBuilder buffer = new StringBuilder();
@@ -1420,6 +1396,10 @@
         case PARSING_STATIC_TEXT:
           switch (c)
           {
+            case '\\':
+              phase = PARSING_ESCAPED_CHAR;
+              previousPhase = PARSING_STATIC_TEXT;
+              break;
             case '<':
               if (buffer.length() > 0)
               {
@@ -1454,6 +1434,10 @@
         case PARSING_REPLACEMENT_TAG:
           switch (c)
           {
+            case '\\':
+              phase = PARSING_ESCAPED_CHAR;
+              previousPhase = PARSING_REPLACEMENT_TAG;
+              break;
             case '>':
               Tag t = parseReplacementTag(buffer.toString(), branch, template,
                                           lineNumber, tags, warnings);
@@ -1471,7 +1455,11 @@
         case PARSING_ATTRIBUTE_TAG:
           switch (c)
           {
-              case '}':
+            case '\\':
+              phase = PARSING_ESCAPED_CHAR;
+              previousPhase = PARSING_ATTRIBUTE_TAG;
+              break;
+            case '}':
               Tag t = parseAttributeTag(buffer.toString(), branch, template,
                                         lineNumber, warnings);
               tagList.add(t);
@@ -1484,6 +1472,11 @@
               break;
           }
           break;
+
+        case PARSING_ESCAPED_CHAR:
+          buffer.append(c);
+          phase = previousPhase;
+          break;
       }
     }
 
@@ -1535,7 +1528,7 @@
    */
   private Tag parseReplacementTag(String tagString, Branch branch,
                                   Template template, int lineNumber,
-                                  LinkedHashMap<String,Tag> tags,
+                                  Map<String,Tag> tags,
                                   List<Message> warnings)
           throws InitializationException, MakeLDIFException
   {

--
Gitblit v1.10.0