public int parseStartLoop( String content, DirectivesStack directives, int startOfStartListDirectiveIndex )
    {
        // contentWichStartsWithList='[#list developers as d]yyy'
        String contentWhichStartsWithList = content.substring( startOfStartListDirectiveIndex, content.length() );
        int endOfStartListDirectiveIndex = contentWhichStartsWithList.indexOf( ']' );
        if ( endOfStartListDirectiveIndex == -1 )
        {
            // [#list not closed with ']'
            return 0;
        }
        // startLoopDirective='[#list developers as d]'
        String startLoopDirective = contentWhichStartsWithList.substring( 0, endOfStartListDirectiveIndex + 1 );
        // insideLoop='developers as d]'
        String insideLoop = startLoopDirective.substring( START_LIST_DIRECTIVE.length(), startLoopDirective.length() );
        int indexBeforeAs = insideLoop.indexOf( " " );
        if ( indexBeforeAs == -1 )
        {
            return 0;
        }

        // afterSequence=' as d]'
        String afterSequence = insideLoop.substring( indexBeforeAs, insideLoop.length() );
        int indexAfterAs = afterSequence.indexOf( AS_DIRECTIVE );
        if ( indexAfterAs == -1 )
        {
            return 0;
        }

        // sequence='developpers'
        String sequence = insideLoop.substring( 0, indexBeforeAs ).trim();
        if ( StringUtils.isEmpty( sequence ) )
        {
            return 0;
        }
        // afterAs='d]'
        String afterAs = afterSequence.substring( AS_DIRECTIVE.length(), afterSequence.length() );
        int endListIndex = afterAs.indexOf( ']' );
        if ( endListIndex == -1 )
        {
            return 0;
        }
        // item='d'
        String item = afterAs.substring( 0, endListIndex ).trim();
        if ( StringUtils.isEmpty( item ) )
        {
            return 0;
        }

        int nbLoop = 1;
        directives.push( new LoopDirective( directives.peekOrNull(), startLoopDirective, getEndLoopDirective( null ),
                                            sequence, item ) );

        // afterList = 'yyy'
        String afterList =
            content.substring( startOfStartListDirectiveIndex + startLoopDirective.length(), content.length() );
        nbLoop += extractListDirectiveInfo( afterList, directives );
        return nbLoop;
    }
 public boolean containsInterpolation(String content) {
   if (StringUtils.isEmpty(content)) {
     return false;
   }
   int dollarIndex = content.indexOf(DOLLAR_TOTKEN);
   if (dollarIndex == -1) {
     // Not included to FM directive
     return false;
   }
   return true;
 }
  @Override
  public boolean doStartElement(String uri, String localName, String name, Attributes attributes)
      throws SAXException {
    /**
     * <w:abstractNum w:abstractNumId="1"> <w:nsid w:val="68EC0125" /> <w:multiLevelType
     * w:val="hybridMultilevel" /> <w:tmpl w:val="3D16DCB8" /> <w:lvl w:ilvl="0" w:tplc="040C0001">
     * <w:start w:val="1" /> <w:numFmt w:val="bullet" />
     */
    if (DocxUtils.isAbstractNum(uri, localName, name)) {
      // w:abstractNumId
      this.currentAbstractNumId = attributes.getValue(W_ABSTRACT_NUM_ID_ATTR);
    } else if (DocxUtils.isNumFmt(uri, localName, name)) {
      String firstNumFmt = attributes.getValue(W_VAL_ATTR);
      if (StringUtils.isNotEmpty(firstNumFmt)) {
        if (BULLET.equals(firstNumFmt)) {
          DefaultStyle defaultStyle = DocxContextHelper.getDefaultStyle(sharedContext);
          if (defaultStyle.getAbstractNumIdForUnordererList() == null) {
            defaultStyle.setAbstractNumIdForUnordererList(
                StringUtils.asInteger(currentAbstractNumId));
          }
        } else if (DECIMAL.equals(firstNumFmt)) {
          DefaultStyle defaultStyle = DocxContextHelper.getDefaultStyle(sharedContext);
          if (defaultStyle.getAbstractNumIdForOrdererList() == null) {
            defaultStyle.setAbstractNumIdForOrdererList(
                StringUtils.asInteger(currentAbstractNumId));
          }
        }
      }
    } else if (DocxUtils.isNum(uri, localName, name)) {
      Integer numId = StringUtils.asInteger(attributes.getValue(W_NUM_ID_ATTR));
      if (numId != null) {
        DefaultStyle defaultStyle = DocxContextHelper.getDefaultStyle(sharedContext);
        if (defaultStyle.getMaxNumId() == null || numId > defaultStyle.getMaxNumId()) {
          defaultStyle.setMaxNumId(numId);
        }
      }

      generateDynamicAbstractNumIfNeeded();
    }
    return super.doStartElement(uri, localName, name, attributes);
  }
 public PdfOptions toPdfOptions(Options options) {
   if (options == null) {
     return null;
   }
   Object value = options.getSubOptions(PdfOptions.class);
   if (value instanceof PdfOptions) {
     return (PdfOptions) value;
   }
   PdfOptions pdfOptions = PdfOptions.create();
   // Populate font encoding
   String fontEncoding = OptionsHelper.getFontEncoding(options);
   if (StringUtils.isNotEmpty(fontEncoding)) {
     pdfOptions.fontEncoding(fontEncoding);
   }
   return pdfOptions;
 }
 protected boolean isModelField(String content, String fieldName) {
   if (StringUtils.isEmpty(content)) {
     return false;
   }
   int dollarIndex = content.indexOf(DOLLAR_TOTKEN);
   if (dollarIndex == -1) {
     // Not included to FM directive
     return false;
   }
   int fieldNameIndex = content.indexOf(fieldName);
   if (fieldNameIndex < dollarIndex) {
     // Not included to FM directive
     return false;
   }
   return true;
 }
  @Override
  protected void doTransform(String content, IDocumentHandler documentHandler) throws Exception {

    // pre-process content : can be used to integrate a markup based html generator like markdown
    content = generateXhtmlFromContent(content);

    // remove special characters \n, \r
    String xml = StringUtils.replaceEach(content, searchList, replacementList);
    // add root element if xml doesn't contain xml root element.
    xml = new StringBuilder(START_XML).append(xml).append(END_XML).toString();

    if (LOGGER.isLoggable(Level.FINE)) {
      LOGGER.fine(xml);
    }
    XMLReader xmlReader = XMLReaderFactory.createXMLReader();
    xmlReader.setContentHandler(new HTMLTextStylingContentHandler(documentHandler));
    xmlReader.parse(new InputSource(new StringReader(xml)));
  }
 public String formatAsFieldItemList(String content, String fieldName, boolean forceAsField) {
   if (forceAsField) {
     return ITEM_TOKEN + content;
   }
   if (!isModelField(content, fieldName)) {
     return content;
   }
   int startIndex = content.indexOf(DOLLAR_TOTKEN);
   startIndex = startIndex + DOLLAR_TOTKEN.length();
   int endIndex = content.indexOf('}');
   if (endIndex == -1) {
     return null;
   }
   String startContent = content.substring(0, startIndex);
   String endContent = content.substring(endIndex, content.length());
   String contentToFormat = content.substring(startIndex, endIndex);
   String formattedContent =
       StringUtils.replaceAll(contentToFormat, fieldName, getItemToken() + fieldName);
   return startContent + formattedContent + endContent;
 }