XprEntity.java
/*
** Module : XprEntity.java
** Abstract : Class to collect and prcess XPR file structures and data.
**
** Copyright (c) 2018-2019, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------Description----------------------------------
** 001 EVL 20180509 Created initial version.
** 002 EVL 20180522 Adding multiple pages support. Tag checking is now case insensitive.
** 003 EVL 20180527 Code optimization and clean ups. Adding left margin tag support.
** 004 EVL 20180601 Fix for text lines positioning. Complete filled rectangle support.
** 005 EVL 20180622 Fix for number format error with row or column set tags. Adding support for
** lpi save/adjust/restore tags. Adding page orientation tags support.
** 006 EVL 20180703 Adding support for /P stop font size tag. Do nothing except message logging
** for now until we find the real work to be happen with this tag.
** 007 EVL 20180717 Adding valid integer string to font size tag to separate from other taggs with
** same starting substring, like PREVIEW.
** 008 EVL 20180727 Adding abend protection and bookmark handling for column and row setter tags.
** 009 EVL 20181007 Adding ability to get image from application jar file.
** 010 EVL 20190116 Adding simple image resource name validiation check.
** 011 EVL 20190514 Adding interface for all PDF sources to be used in JasperReports.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.reporting;
import com.goldencode.p2j.ui.*;
import com.goldencode.p2j.util.*;
import java.io.*;
import java.util.*;
/**
* The object collecting all initial data for given XPR file. Also it performs tags processing
* and makes abstraction model to be used by Jasperreport library to make proper report object.
*/
public class XprEntity
implements PdfProvider
{
/** Default LPI value for screen report. */
public static final double LPI_DEFAULT = 6.0;
/** Default CPI value for screen report. */
public static final double CPI_DEFAULT = 10.0;
/** Default DPI value for PDF images rendering. */
public static final int DPI_PDF_DEFAULT = 300;
/** Base units is inches constant. */
private static final int UNITS_INCHES = 0;
/** Base units is mm constant. */
private static final int UNITS_MM = 1;
/** Inch to mm transformation. */
public static final double INCH_2_MM = 25.4;
/** Font size default value for XPR. */
private static final int FONT_SIZE_DEFAULT = 12;
/** Font name default value for XPR. */
private static final String FONT_NAME_DEFAULT = "Courier New";
/** Page separator marker. */
private static final String PAGE_SEPARATOR = "\f";
/** Page separator marker. */
private static final String TAG_VALUE_ERROR = "TAG_VALUE_ERROR";
/** This string to be considered as text, not a tag start. */
private static final String LT_IN_TEXT = "\\<";
/** Constant to replace temporary substitution for lt char */
private static final String LT_AS_TEXT = "<";
/** Constant to temporary replace lt char in text for the time of tags processing. */
private static final String LT_IN_TEXT_SUBST = "\\LT";
/** This string to be considered as text, not a tag end. */
private static final String GT_IN_TEXT = "\\>";
/** Constant to replace temporary substitution for gt char. */
private static final String GT_AS_TEXT = ">";
/** Constant to temporary replace gt char in text for the time of tags processing. */
private static final String GT_IN_TEXT_SUBST = "\\GT";
/** Pattern matches string as containing only digits, allowing decimal one. */
private static final String DECIMAL_DIGIT = "\\d*\\.?\\d*";
/** Pattern matches string as containing only integer digits. */
private static final String INTEGER_DIGIT = "\\d+";
/** Pattern matches string as containing any char except digit. */
private static final String ANY_CHAR_BUT_DIGIT = "[^0-9]";
/** LPI identifier as tag value part. */
private static final String LPI_AS_TEXT = "LPI";
/** Original data from source file as array of pages. */
private List<List<String>> origPagesBuffer = new ArrayList<List<String>>();
/** The Z-ordered list of the objects recognized inside current file entity, paginated. */
private List<List<XprObjBase>> pages = new ArrayList<List<XprObjBase>>();
/** New page specific options. */
private List<XprPageOptions> pageOptions = new ArrayList<XprPageOptions>();
/** Separate list of bookmark objects in use. */
private Map<String, XprObjBookmark> bkmks = new HashMap<String, XprObjBookmark>();
/** Enhanced vpxPrint color palette. */
private static Map<String, ColorRgb> xprPalette = new HashMap<String, ColorRgb>();
/** The value of the per document PREVIEW tag. */
private boolean preview = false;
/** The value of the per document MODAL mode tag. */
private boolean noModal = false;
/** The value of the per document PROGRESS line style tag. */
private boolean noProgressStyle = false;
/** Number of copies (single by default). */
private int numCopies = 1;
/** Current column value in new entity. */
private double colCurr = 1.0;
/** Current row value in new entity. */
private double rowCurr = 1.0;
/** Column value for FROM tag. */
private double colFrom = 1.0;
/** Row value for FROM tag. */
private double rowFrom = 1.0;
/** Column value for LEFT tag. */
private double leftMargin = 0.0;
/** Raw value for TOP tag. */
private double topMargin = 0.0;
/** Current line width value. */
private int lineWidth = 1;
/** Current font name (default is 'Courier New'). */
private String currFontName = FONT_NAME_DEFAULT;
/** Current font size (default is 12). */
private int parSize = FONT_SIZE_DEFAULT;
/** Current lines per inch value (default is 6). */
private double linesPerInch = LPI_DEFAULT;
/** Previously saved lines per inch value (default is not saved). */
private double linesPerInchSaved = 0.0;
/** Current characters per inch value (default is 10). */
private double charsPerInch = 10.0;
/** Flag indicating if the font is currently bold or not. */
private boolean isBoldFont = false;
/** Flag indicating if the font is currently italic or not. */
private boolean isItalicFont = false;
/** Background color for filled rectangles.*/
private int bgColor = 0xFFFFFFFF;
/** Foreground color for text.*/
private int fgColor = 0xFF000000;
/** Line color for lines, rectangles and border of the filled rectangles.*/
private int lineColor = 0xFF000000;
/** Base units type, inches or mm. */
private int units = UNITS_INCHES;
/** Device independent DPI scaling factor */
private double dpiScalingFactor = 1.0;
/** Current page orientation. */
private int pageOrientation = XprPageOptions.PORTRAIT;
// one time variables init
static
{
// init predefined color palette
xprPalette.put("BLUE", new ColorRgb(0x00, 0x00, 0xFF));
xprPalette.put("LTBLUE", new ColorRgb(0x4D, 0x4D, 0xFF));
xprPalette.put("DKBLUE", new ColorRgb(0x00, 0x00, 0xB2));
xprPalette.put("WHITE", new ColorRgb(0xFF, 0xFF, 0xFF));
xprPalette.put("LTWHITE", new ColorRgb(0xFF, 0xFF, 0xFF));
xprPalette.put("DKWHITE", new ColorRgb(0xB2, 0xB2, 0xB2));
xprPalette.put("BLACK", new ColorRgb(0x00, 0x00, 0x00));
xprPalette.put("LTBLACK", new ColorRgb(0x4D, 0x4D, 0x4D));
xprPalette.put("DKBLACK", new ColorRgb(0x00, 0x00, 0x00));
xprPalette.put("AQUA", new ColorRgb(0x00, 0xFF, 0xFF));
xprPalette.put("LTAQUA", new ColorRgb(0x4D, 0xFF, 0xFF));
xprPalette.put("DKAQUA", new ColorRgb(0x00, 0xB2, 0xB2));
xprPalette.put("DKGRAY", new ColorRgb(0x80, 0x80, 0x80));
xprPalette.put("LTDKGRAY", new ColorRgb(0xA6, 0xA6, 0xA6));
xprPalette.put("DKDKGRAY", new ColorRgb(0x5A, 0x5A, 0x5A));
xprPalette.put("LTGRAY", new ColorRgb(0xC0, 0xC0, 0xC0));
xprPalette.put("LTLTGRAY", new ColorRgb(0xD3, 0xD3, 0xD3));
xprPalette.put("DKLTGRAY", new ColorRgb(0x86, 0x86, 0x86));
xprPalette.put("GRAY", new ColorRgb(0x80, 0x80, 0x80));
xprPalette.put("LTGRAY", new ColorRgb(0xC0, 0xC0, 0xC0));
xprPalette.put("DKGRAY", new ColorRgb(0x80, 0x80, 0x80));
xprPalette.put("FUCHSIA", new ColorRgb(0xFF, 0x00, 0xFF));
xprPalette.put("LTFUCHSIA", new ColorRgb(0xFF, 0x4D, 0xFF));
xprPalette.put("DKFUCHSIA", new ColorRgb(0xB2, 0x00, 0xB2));
xprPalette.put("GREEN", new ColorRgb(0x00, 0x80, 0x00));
xprPalette.put("LTGREEN", new ColorRgb(0x4D, 0xA6, 0x4D));
xprPalette.put("DKGREEN", new ColorRgb(0x00, 0x5A, 0x00));
xprPalette.put("NAVY", new ColorRgb(0x00, 0x00, 0x80));
xprPalette.put("LTNAVY", new ColorRgb(0x4D, 0x4D, 0xA6));
xprPalette.put("DKNAVY", new ColorRgb(0x00, 0x00, 0x5A));
xprPalette.put("OLIVE", new ColorRgb(0x80, 0x80, 0x00));
xprPalette.put("LTOLIVE", new ColorRgb(0xA6, 0xA6, 0x4D));
xprPalette.put("DKOLIVE", new ColorRgb(0x5A, 0x5A, 0x00));
xprPalette.put("PURPLE", new ColorRgb(0x80, 0x00, 0x80));
xprPalette.put("LTPURPLE", new ColorRgb(0xA6, 0x4D, 0xA6));
xprPalette.put("DKPURPLE", new ColorRgb(0x5A, 0x00, 0x5A));
xprPalette.put("RED", new ColorRgb(0xFF, 0x00, 0x00));
xprPalette.put("LTRED", new ColorRgb(0xFF, 0x4D, 0x4D));
xprPalette.put("DKRED", new ColorRgb(0xB2, 0x00, 0x00));
xprPalette.put("SILVER", new ColorRgb(0xC0, 0xC0, 0xC0));
xprPalette.put("LTSILVER", new ColorRgb(0xD3, 0xD3, 0xD3));
xprPalette.put("DKSILVER", new ColorRgb(0x86, 0x86, 0x86));
xprPalette.put("YELLOW", new ColorRgb(0xFF, 0xFF, 0x00));
xprPalette.put("LTYELLOW", new ColorRgb(0xFF, 0xFF, 0x4D));
xprPalette.put("DKYELLOW", new ColorRgb(0xB2, 0xB2, 0x00));
xprPalette.put("MAROON", new ColorRgb(0x80, 0x00, 0x00));
xprPalette.put("LTMAROON", new ColorRgb(0xA6, 0x4D, 0x4D));
xprPalette.put("DKMAROON", new ColorRgb(0x5A, 0x00, 0x00));
}
/**
* Creates new instance of the object for given file object.
*
* @param xprFileReader
* The XPR file object reader to process.
*/
public XprEntity(Reader xprFileReader)
throws IOException
{
// reading data from source
BufferedReader brInput = new BufferedReader(xprFileReader);
// reading line by line until the end
String nextLine = brInput.readLine();
// at least one page we always have
List<String> origLinesBuffer = new ArrayList<String>();
while (nextLine != null)
{
// next page creation is requied
if (origLinesBuffer == null)
{
origLinesBuffer = new ArrayList<String>();
}
// page separation
int pageSepNdx = nextLine.indexOf(PAGE_SEPARATOR);
// another original line
if (pageSepNdx != -1)
{
String textBeforePageSep = nextLine.substring(0, pageSepNdx);
// adding possible text in line before page separator
if (!textBeforePageSep.isEmpty())
{
origLinesBuffer.add(textBeforePageSep);
}
// now adding lines buffer as new page
origPagesBuffer.add(origLinesBuffer);
// this means we finished current page but not yet started the new one
origLinesBuffer = null;
// check if there is something after page separator
if (pageSepNdx < nextLine.length() - 1)
{
// there is a text after page separator
nextLine = nextLine.substring(pageSepNdx + 1);
// skip next line reading, consider the rest of line as next one
continue;
}
}
else
{
origLinesBuffer.add(nextLine);
}
// read next line
nextLine = brInput.readLine();
}
// close the reader
brInput.close();
// check if there is unhandled page buffer
if (origLinesBuffer != null)
{
origPagesBuffer.add(origLinesBuffer);
origLinesBuffer = null;
}
}
/**
* Setting up internal object of this entity.
*/
public void init()
{
// init global variable for XPR
initGlobals();
// scan for objects inside XPR and initialize them
initObjects();
}
/**
* Initializes internal objets for this XPR entity.
*
* @return <code>TRUE</code> if success, <code>FALSE</code> otherwise.
*/
private boolean initObjects()
{
XprObjText xprText = null;
int totalNumPages = origPagesBuffer.size();
// every page will have separate list
for (int i = 0; i < totalNumPages; i++)
{
// reset internal constants
resetInitials();
// new object list for new page
List<XprObjBase> objects = new ArrayList<XprObjBase>();
// new page options set with current default page size
XprPageOptions pgOpt = new XprPageOptions(XprHelper.getPdfPageWidth(),
XprHelper.getPdfPageHeight(),
pageOrientation);
// go throught all lines from start to end
List<String> origLinesBuffer = origPagesBuffer.get(i);
for (int j = 0; j < origLinesBuffer.size(); j++)
{
// starting to scan next line
String currLine = origLinesBuffer.get(j);
// we need to replace all <> characters to be considered as tags with other
// string for the time of tags scanning and processing
// will return back when constructing text object
currLine = currLine.replace(LT_IN_TEXT, LT_IN_TEXT_SUBST)
.replace(GT_IN_TEXT, GT_IN_TEXT_SUBST);
String nextTag = null;
// main line loop for not empty initial lines
while ((nextTag = getNextTagOrTextInLine(currLine)) != null)
{
// single case tags one per documents nothing to do here
// TODO: looks not very optimal check think more to find a better way
if (!tagMatch(nextTag, XprTag.PREVIEW) && !tagMatch(nextTag, XprTag.MODAL) &&
!tagMatch(nextTag, XprTag.NO_PROGRESS) && !tagMatch(nextTag, XprTag.COPIES))
{
// tags processing
if (tagMatch(nextTag, XprTag.FROM))
{
// remember current coords as primitive starting point
rowFrom = rowCurr;
colFrom = colCurr;
}
else if (tagMatch(nextTag, XprTag.COL_SET))
{
// column value change
char chOperation = nextTag.charAt(2);
// depending on operation type
if (chOperation == XprTag.CHR_PLUS)
{
// getting number from string
String numStr = nextTag.substring(3,nextTag.length() - 1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
colCurr += Double.valueOf(numStr).doubleValue();
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
else if (chOperation == XprTag.CHR_MINUS)
{
// getting number from string
String numStr = nextTag.substring(3,nextTag.length() - 1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
colCurr -= Double.valueOf(numStr).doubleValue();
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
else if (chOperation == XprTag.CHR_SHARP)
{
String bkmkName = nextTag.substring(nextTag.indexOf(XprTag.CHR_SHARP) + 1,
nextTag.indexOf(XprTag.END));
// get column from bookmark provided
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
colCurr = bkmkObj.getColumn();
}
else
{
// invalid bookmark name
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid bookmark name in tag %s.",
nextTag));
}
}
else
{
// getting number from string
String numStr = nextTag.substring(2,nextTag.length() - 1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
colCurr = Double.valueOf(numStr).doubleValue();
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.", nextTag));
}
}
}
else if (tagMatch(nextTag, XprTag.RECT))
{
double rowBk = 0.0;
double colBk = 0.0;
int bkmkNdx = nextTag.indexOf(XprTag.CHR_SHARP);
// if bookmark embedded - use it as from point
if (bkmkNdx != -1)
{
int bkmkEnd = nextTag.indexOf(XprTag.END);
String bkmkName = nextTag.substring(bkmkNdx + 1, bkmkEnd);
// get bookmark coords
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
rowBk = bkmkObj.getRow();
colBk = bkmkObj.getColumn();
}
}
else
{
rowBk = rowFrom;
colBk = colFrom;
}
// check if the rectangle is rounded
boolean isRounded = nextTag.indexOf(")") != -1;
// new rectangle detected
XprObjRectangle xprRect = new XprObjRectangle(lineColor, rowBk, colBk,
rowCurr, colCurr, lineWidth,
isRounded);
xprRect.setMargins(leftMargin, topMargin);
objects.add(xprRect);
}
else if (tagMatch(nextTag, XprTag.FILLRECT))
{
double rowBk = 0.0;
double colBk = 0.0;
int bkmkNdx = nextTag.indexOf(XprTag.CHR_SHARP);
// if bookmark embedded - use it as from point
if (bkmkNdx != -1)
{
int bkmkEnd = nextTag.indexOf(XprTag.END);
String bkmkName = nextTag.substring(bkmkNdx + 1, bkmkEnd);
// get bookmark coords
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
rowBk = bkmkObj.getRow();
colBk = bkmkObj.getColumn();
}
}
else
{
rowBk = rowFrom;
colBk = colFrom;
}
// check if the rectangle is rounded
boolean isRounded = nextTag.indexOf(")") != -1;
int frLineWidth = 0;
if (nextTag.indexOf("+") != -1 || nextTag.indexOf("|") != -1)
{
frLineWidth = lineWidth;
}
// new rectangle detected
XprObjFilledRectangle xprFillRect =
new XprObjFilledRectangle(lineColor, bgColor, rowBk, colBk,
rowCurr, colCurr, frLineWidth, isRounded);
xprFillRect.setMargins(leftMargin, topMargin);
objects.add(xprFillRect);
}
else if (tagMatch(nextTag, XprTag.RESTORE))
{
String tagVal = getTagValue(nextTag, XprTag.RESTORE);
if (tagVal.toUpperCase().indexOf(LPI_AS_TEXT) != -1 &&
linesPerInchSaved != 0.0)
{
linesPerInch = linesPerInchSaved;
}
}
else if (tagMatch(nextTag, XprTag.SAVE))
{
String tagVal = getTagValue(nextTag, XprTag.SAVE);
if (tagVal.toUpperCase().indexOf(LPI_AS_TEXT) != -1)
{
linesPerInchSaved = linesPerInch;
}
}
else if (tagMatch(nextTag, XprTag.ADJUST))
{
String tagVal = getTagValue(nextTag, XprTag.ADJUST);
if (tagVal.toUpperCase().indexOf(LPI_AS_TEXT) != -1)
{
// do LPI to match the current font size
linesPerInch = LPI_DEFAULT * (double)FONT_SIZE_DEFAULT /
((double)parSize + 1.0);
}
}
else if (tagMatch(nextTag, XprTag.ROW_SET))
{
// row value change
char chOperation = nextTag.charAt(2);
if (chOperation == XprTag.CHR_PLUS)
{
// getting number from string
String numStr = nextTag.substring(3,nextTag.length() - 1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
rowCurr += Double.valueOf(numStr).doubleValue() * LPI_DEFAULT /
linesPerInch;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
else if (chOperation == XprTag.CHR_MINUS)
{
// getting number from string
String numStr = nextTag.substring(3,nextTag.length() - 1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
rowCurr -= Double.valueOf(numStr).doubleValue() * LPI_DEFAULT /
linesPerInch;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
else if (chOperation == XprTag.CHR_SHARP)
{
String bkmkName = nextTag.substring(nextTag.indexOf(XprTag.CHR_SHARP) + 1,
nextTag.indexOf(XprTag.END));
// get column from bookmark provided
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
rowCurr = bkmkObj.getRow();
}
else
{
// invalid bookmark name
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid bookmark name in tag %s.",
nextTag));
}
}
else
{
// getting number from string
String numStr = nextTag.substring(2,nextTag.length() - 1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
rowCurr = Double.valueOf(numStr).doubleValue() * LPI_DEFAULT /
linesPerInch;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
}
else if (tagMatch(nextTag, XprTag.FGCOLOR))
{
fgColor = getColorFromTag(getTagValue(nextTag, XprTag.FGCOLOR));
}
else if (tagMatch(nextTag, XprTag.BGCOLOR))
{
bgColor = getColorFromTag(getTagValue(nextTag, XprTag.BGCOLOR));
}
// it is important to have LINECOLOR tag before LINE tag to avoid wrong line
// creation command
else if (tagMatch(nextTag, XprTag.LINECOLOR))
{
lineColor = getColorFromTag(getTagValue(nextTag, XprTag.LINECOLOR));
}
// current page orientations
else if (tagMatch(nextTag, XprTag.LANDSCAPE) ||
tagMatch(nextTag, XprTag.OLANDSCAPE))
{
pageOrientation = XprPageOptions.LANDSCAPE;
// refresh page size
pgOpt.setPageOrientation(pageOrientation);
}
else if (tagMatch(nextTag, XprTag.PORTRAIT) ||
tagMatch(nextTag, XprTag.OPORTRAIT))
{
pageOrientation = XprPageOptions.PORTRAIT;
// refresh page size
pgOpt.setPageOrientation(pageOrientation);
}
else if (tagMatch(nextTag, XprTag.LINE))
{
// new line detected
double rowBk = 0.0;
double colBk = 0.0;
int bkmkNdx = nextTag.indexOf(XprTag.CHR_SHARP);
// if bookmark embedded - use it as from point
if (bkmkNdx != -1)
{
int bkmkEnd = nextTag.indexOf(XprTag.END);
String bkmkName = nextTag.substring(bkmkNdx + 1, bkmkEnd);
// get bookmark coords
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
rowBk = bkmkObj.getRow();
colBk = bkmkObj.getColumn();
}
}
else
{
rowBk = rowFrom;
colBk = colFrom;
}
XprObjLine xprLine = new XprObjLine(lineColor, rowBk, colBk,
rowCurr, colCurr, lineWidth);
xprLine.setMargins(leftMargin, topMargin);
objects.add(xprLine);
}
// it is important to process #PAGES before bookmark tag
// otherwise it will be ignored due to same starting subsequense
else if (tagMatch(nextTag, XprTag.NUM_PAGES))
{
// #PAGES must be substituted by literal with number of pages
// this is a text object
String numPagesTxt = String.valueOf(totalNumPages);
xprText = new XprObjText(currFontName, parSize, isBoldFont, isItalicFont,
fgColor, rowCurr, colCurr, numPagesTxt);
xprText.setMargins(leftMargin, topMargin);
objects.add(xprText);
// current column value shofted to the text length
colCurr += (double)numPagesTxt.length() * (double)parSize /
(double)FONT_SIZE_DEFAULT;
}
else if (tagMatch(nextTag, XprTag.BOOKMARK))
{
// new bookmark with the current coordinates
String bkmkName = nextTag.substring(2,nextTag.length() - 1);
XprObjBookmark bkmkObj = new XprObjBookmark(bkmkName, rowCurr, colCurr);
bkmks.put(bkmkName, bkmkObj);
}
else if (tagMatch(nextTag, XprTag.GOTO_BOOKMARK))
{
String bkmkName = null;
// optional char in GOTO operation
if (nextTag.charAt(2) == XprTag.CHR_SHARP)
{
bkmkName = nextTag.substring(3,nextTag.length() - 1);
}
else
{
bkmkName = nextTag.substring(2,nextTag.length() - 1);
}
// bookmark object must already be handled
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
// change the current coordinates
rowCurr = bkmkObj.getRow();
colCurr = bkmkObj.getColumn();
}
}
else if (tagMatch(nextTag, XprTag.LINE_WIDTH))
{
// device dependent line width
if (nextTag.charAt(2) != '|')
{
if (nextTag.charAt(2) != '>')
{
// getting number from string
String numStr = nextTag.substring(2,nextTag.length() - 1);
if (numStr.matches(INTEGER_DIGIT))
{
lineWidth = Integer.valueOf(numStr).intValue();
}
else
{
// bad digit format
XprHelper.displayOrLogError(
String.format("XPR Entity has found unsupported line width tag %s.",
nextTag));
}
}
else
{
// empty tag, reset line width to default one
lineWidth = 1;
}
}
// device independent case, || tag in use
else
{
if (nextTag.charAt(3) != '>')
{
// getting number from string
String numStr = nextTag.substring(3,nextTag.length() - 1);
if (numStr.matches(DECIMAL_DIGIT))
{
double dblLineWidth =
Double.valueOf(numStr).doubleValue() * dpiScalingFactor;
lineWidth = dblLineWidth < 1.0 ? 1 : (int)Math.round(dblLineWidth);
}
else
{
// bad digit format
XprHelper.displayOrLogError(
String.format("XPR Entity has found unsupported line width tag %s.",
nextTag));
}
}
else
{
// empty tag, reset line width to default one
lineWidth = 1;
}
}
}
else if (tagMatch(nextTag, XprTag.IMAGE))
{
double rowBk = 0.0;
double colBk = 0.0;
int bkmkNdx = nextTag.indexOf(XprTag.CHR_SHARP);
String fullImageTag = new String(XprTag.IMAGE);
if (bkmkNdx != -1)
{
int bkmkEnd = nextTag.indexOf('=');
String bkmkName = nextTag.substring(bkmkNdx + 1, bkmkEnd);
// get bookmark coords
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
rowBk = bkmkObj.getRow();
colBk = bkmkObj.getColumn();
}
// append bookmark name to full tag value
fullImageTag = fullImageTag.concat(nextTag.substring(bkmkNdx,
bkmkEnd + 1));
}
else
{
rowBk = rowFrom;
colBk = colFrom;
}
// sometimes image path is null
String imgPath = getTagValue(nextTag, fullImageTag);
// check if the image is accessible, the server jar will have a preference
if (imgPath == null || imgPath.isEmpty())
{
// the image name is null or empty
XprHelper.displayOrLogError(
"XPR Entity got null or empty image file name, ignore creation.");
}
else if (FwdJasperExtensionRegistry.getRepositoryService()
.getInputStream(imgPath) != null ||
XprHelper.getInputStream(imgPath) != null ||
XprHelper.onErrorImageSilentMode())
{
// try to get image object
XprObjImage xprImage = new XprObjImage(rowBk, colBk, rowCurr,
colCurr, imgPath);
xprImage.setMargins(leftMargin, topMargin);
objects.add(xprImage);
}
else
{
XprHelper.displayOrLogError(
String.format("XPR Entity can not find the image %s, ignore creation.",
imgPath));
}
}
else if (tagMatch(nextTag, XprTag.FONT))
{
currFontName = nextTag.substring(2,nextTag.length() - 1);
}
else if (tagMatch(nextTag, XprTag.FONT_SIZE))
{
// getting integer value from string
String intStr = nextTag.substring(2,nextTag.length() - 1);
// check if the string has valid digit
if (intStr.matches(INTEGER_DIGIT))
{
parSize = Integer.valueOf(intStr).intValue();
}
else
{
// not only integer digits, unsupported tag yet
XprHelper.displayOrLogError(
String.format("XPR Entity has found unsupported font size tag %s.",
nextTag));
}
}
else if (tagMatch(nextTag, XprTag.STOP_FONT_SIZE))
{
// this tag /P does not show any functionality at this time jusy logging
XprHelper.logInfo(
String.format("XPR Entity ignores the tag %s. The functionality is unknown.",
nextTag));
}
else if (tagMatch(nextTag, XprTag.BOLD))
{
isBoldFont = true;
}
else if (tagMatch(nextTag, XprTag.NO_BOLD))
{
isBoldFont = false;
}
else if (tagMatch(nextTag, XprTag.ITALIC))
{
isItalicFont = true;
}
else if (tagMatch(nextTag, XprTag.NO_ITALIC))
{
isItalicFont = false;
}
else if (tagMatch(nextTag, XprTag.BARCODE))
{
double rowBk = 0.0;
double colBk = 0.0;
int bkmkNdx = nextTag.indexOf(XprTag.CHR_SHARP);
int bkmkEnd = nextTag.indexOf(',');
String fullBCTag = new String(XprTag.BARCODE);
if (bkmkNdx != -1)
{
String bkmkName = nextTag.substring(bkmkNdx + 1, bkmkEnd);
// get bookmark coords
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
rowBk = bkmkObj.getRow();
colBk = bkmkObj.getColumn();
}
// append bookmark name to full tag value
fullBCTag = fullBCTag.concat(nextTag.substring(bkmkNdx, bkmkEnd));
}
else
{
rowBk = rowFrom;
colBk = colFrom;
}
fullBCTag = fullBCTag.concat(nextTag.substring(bkmkEnd, bkmkEnd + 1));
XprObjBarcode xprBarcode = new XprObjBarcode(rowBk, colBk, rowCurr, colCurr,
getTagValue(nextTag, fullBCTag));
xprBarcode.setMargins(leftMargin, topMargin);
objects.add(xprBarcode);
}
else if (tagMatch(nextTag, XprTag.AT))
{
String[] atValue = getTagValue(nextTag, XprTag.AT).split(",");
if (atValue != null)
{
// row change first
if (atValue[0] != null && !atValue[0].isEmpty())
{
char chFirst = atValue[0].charAt(0);
// get row from bookmark
if (chFirst == XprTag.CHR_SHARP)
{
String bkmkName = atValue[0].substring(1);
// get bookmark coords
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
rowCurr = bkmkObj.getRow();
}
}
// adding absolute value to the current one
else if (chFirst == XprTag.CHR_PLUS)
{
// getting number from string
String numStr = atValue[0].substring(1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
// take value in inch or mm
double rowInchMM = Double.valueOf(numStr).doubleValue();
// in case ov mm convert to inches
if (units == UNITS_MM)
{
rowInchMM /= INCH_2_MM;
}
// convert inch value to row
rowCurr += rowInchMM * linesPerInch;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
// subtract absolute value from the current one
else if (chFirst == XprTag.CHR_MINUS)
{
// getting number from string
String numStr = atValue[0].substring(1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
// take value in inch or mm
double rowInchMM = Double.valueOf(numStr).doubleValue();
// in case ov mm convert to inches
if (units == UNITS_MM)
{
rowInchMM /= INCH_2_MM;
}
// convert inch value to row
rowCurr -= rowInchMM * linesPerInch;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
// set absolute value as current one
else
{
// getting number from string
String numStr = atValue[0];
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
// take value in inch or mm
double rowInchMM = Double.valueOf(numStr).doubleValue();
// in case ov mm convert to inches
if (units == UNITS_MM)
{
rowInchMM /= INCH_2_MM;
}
// convert inch value to row
rowCurr = rowInchMM * linesPerInch;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
}
// then column
if (atValue.length > 1 && atValue[1] != null && !atValue[1].isEmpty())
{
char chFirst = atValue[1].charAt(0);
// get column from bookmark
if (chFirst == XprTag.CHR_SHARP)
{
String bkmkName = atValue[1].substring(1);
// get bookmark coords
XprObjBookmark bkmkObj = bkmks.get(bkmkName);
if (bkmkObj != null)
{
colCurr = bkmkObj.getColumn();
}
}
// adding absolute value to the current one
else if (chFirst == XprTag.CHR_PLUS)
{
// getting number from string
String numStr = atValue[1].substring(1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
double colInchMM = Double.valueOf(numStr).doubleValue();
// in case ov mm convert to inches
if (units == UNITS_MM)
{
colInchMM /= INCH_2_MM;
}
// convert inch value to column
colCurr += colInchMM * CPI_DEFAULT;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
// subtract absolute value from the current one
else if (chFirst == XprTag.CHR_MINUS)
{
// getting number from string
String numStr = atValue[1].substring(1);
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
double colInchMM = Double.valueOf(numStr).doubleValue();
// in case ov mm convert to inches
if (units == UNITS_MM)
{
colInchMM /= INCH_2_MM;
}
// convert inch value to column
colCurr -= colInchMM * CPI_DEFAULT;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
// set absolute value as current one
else
{
// getting number from string
String numStr = atValue[1];
// check if the string has valid digit
if (numStr.matches(DECIMAL_DIGIT))
{
double colInchMM = Double.valueOf(numStr).doubleValue();
// in case ov mm convert to inches
if (units == UNITS_MM)
{
colInchMM /= INCH_2_MM;
}
// convert inch value to column
colCurr = colInchMM * CPI_DEFAULT;
}
else
{
// not only digits, the format is invalid
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid tag %s format.",
nextTag));
}
}
}
}
}
else if (tagMatch(nextTag, XprTag.UNITS))
{
String unitsValue = getTagValue(nextTag, XprTag.UNITS);
if (unitsValue.equals("INCHES"))
{
units = UNITS_INCHES;
}
else if (unitsValue.equals("MM"))
{
units = UNITS_MM;
}
}
else if (tagMatch(nextTag, XprTag.LEFT))
{
// left margin declaration
String leftMarginStr = getTagValue(nextTag, XprTag.LEFT).toUpperCase();
if (leftMarginStr != null && !leftMarginStr.isEmpty())
{
double margin = 0.0;
if (leftMarginStr.endsWith("MM"))
{
String numStr = leftMarginStr.substring(0, leftMarginStr.length() - 2);
if (numStr.matches(DECIMAL_DIGIT))
{
margin = Double.valueOf(numStr).doubleValue();
// convert mm to inches
margin = margin / INCH_2_MM;
}
else
{
// not only digits, unsupported tag yet
XprHelper.displayOrLogError(
String.format("XPR Entity has found unsupported LEFT tag %s.",
nextTag));
}
}
else
{
String numStr = leftMarginStr.substring(0, leftMarginStr.length() - 1);
if (numStr.matches(DECIMAL_DIGIT))
{
margin = Double.valueOf(numStr).doubleValue();
}
else
{
// not only digits, unsupported tag yet
XprHelper.displayOrLogError(
String.format("XPR Entity has found unsupported LEFT tag %s.",
nextTag));
}
}
leftMargin = margin * CPI_DEFAULT / dpiScalingFactor;
}
}
else if (tagMatch(nextTag, XprTag.TOP))
{
// left margin declaration
String topMarginStr = getTagValue(nextTag, XprTag.TOP).toUpperCase();
if (topMarginStr != null && !topMarginStr.isEmpty())
{
double margin = 0.0;
if (topMarginStr.endsWith("MM"))
{
String numStr = topMarginStr.substring(0, topMarginStr.length() - 2);
if (numStr.matches(DECIMAL_DIGIT))
{
margin = Double.valueOf(numStr).doubleValue();
// convert mm to inches
margin = margin / INCH_2_MM;
}
else
{
// not only digits, unsupported tag yet
XprHelper.displayOrLogError(
String.format("XPR Entity has found unsupported TOP tag %s.",
nextTag));
}
}
else
{
String numStr = topMarginStr.substring(0, topMarginStr.length() - 1);
if (numStr.matches(DECIMAL_DIGIT))
{
margin = Double.valueOf(numStr).doubleValue();
}
else
{
// not only digits, unsupported tag yet
XprHelper.displayOrLogError(
String.format("XPR Entity has found unsupported TOP tag %s.",
nextTag));
}
}
topMargin = margin * linesPerInch / dpiScalingFactor;
}
}
else if (!tagMatch(nextTag, XprTag.START))
{
// anything but the starting as tag can be considered as a text
// but first we need to restore possible <> chars to be considered as text
String txtLine = nextTag.replace(LT_IN_TEXT_SUBST, LT_AS_TEXT)
.replace(GT_IN_TEXT_SUBST, GT_AS_TEXT);
xprText = new XprObjText(currFontName, parSize, isBoldFont, isItalicFont,
fgColor, rowCurr, colCurr, txtLine);
xprText.setMargins(leftMargin, topMargin);
objects.add(xprText);
// current column value shofted to the text length
colCurr += (double)txtLine.length() * (double)parSize /
(double)FONT_SIZE_DEFAULT;
}
else
{
// all unsupported tags should be here
XprHelper.displayOrLogError(
String.format("XPR Entity has found unsupported tag %s.", nextTag));
}
}
// need to cut current line to the length of the tag
int tagStart = currLine.indexOf(nextTag);
if (tagStart + nextTag.length() <= currLine.length())
{
currLine = currLine.substring(tagStart + nextTag.length());
}
}
// end of the new line
// reset cursor position
colCurr = 1.0;
rowCurr += 1.0 * LPI_DEFAULT / linesPerInch;
}
// store next page to container
pages.add(objects);
// and new page specific options for current page
pageOptions.add(pgOpt);
}
// if we are here - evrything is OK.
return true;
}
//-------------------- Implementation of the PdfProvoder interface ---------------------------
/**
* Getting internal object list from XPR object for particular page.
*
* @param pageNum
* 0 based page number for objects to get.
*
* @return Z-ordered list of the objects recognized inside currently processed XPR file
* for given page number.
*/
@Override
public List<XprObjBase> getObjectsInPage(int pageNum)
{
return pages.get(pageNum);
}
/**
* Getting total number of pages in document.
*
* @return The number of pages with objects.
*/
@Override
public int getTotalPageNumbers()
{
return pages.size();
}
/**
* Getting the page width for given page numbers.
*
* @param pageNum
* 0 based page number for option to get.
*
* @return The page width in pixels or -1 for invalid page num.
*/
@Override
public int getPageWidth(int pageNum)
{
return pageNum < 0 || pageNum > pageOptions.size() - 1
? -1 : pageOptions.get(pageNum).getWidthPix();
}
/**
* Getting the page height for given page numbers.
*
* @param pageNum
* 0 based page number for option to get.
*
* @return The page width in pixels.
*/
@Override
public int getPageHeight(int pageNum)
{
return pageNum < 0 || pageNum > pageOptions.size() - 1
? -1 : pageOptions.get(pageNum).getHeightPix();
}
//-------------------- Implementation of the PdfProvoder interface ---------------------------
/**
* Initializes global variables.
*
* @return <code>TRUE</code> if success, <code>FALSE</code> otherwise.
*/
private boolean initGlobals()
{
// flags that commons for whole document
preview = findSingleTag(XprTag.PREVIEW);
String tagValue = getSingleTagValue(XprTag.MODAL);
noModal = !tagValue.isEmpty() && tagValue.indexOf("=NO") != -1;
noProgressStyle = findSingleTag(XprTag.NO_PROGRESS);
tagValue = getSingleTagValue(XprTag.COPIES);
if (!tagValue.isEmpty() && !tagValue.equals(TAG_VALUE_ERROR) &&
tagValue.matches(INTEGER_DIGIT))
{
numCopies = Integer.valueOf(tagValue).intValue();
}
// initialize device independent scaling factor
dpiScalingFactor = (double)XprHelper.getPdfDPI() / (double)DPI_PDF_DEFAULT;
// if we are here - evrything is OK.
return true;
}
/**
* Gets the line for the given single tag.
*
* @param tagToSearch
* The tag to look for in whole lines buffer.
*
* @return <code>TRUE</code> if tag has been found, <code>FALSE</code> otherwise.
*/
private boolean findSingleTag(String tagToSearch)
{
// the first occurence means tag has found
for (int i = 0; i < origPagesBuffer.size(); i++)
{
// page by page
List<String> origLinesBuffer = origPagesBuffer.get(i);
for (int j = 0; j < origLinesBuffer.size(); j++)
{
String currLine = origLinesBuffer.get(j);
if (currLine.indexOf(tagToSearch) != -1)
{
return true;
}
}
}
// no tag found so far
return false;
}
/**
* Gets the next tag value or text part for the given text line.
*
* @param lineToScan
* The text line to search.
*
* @return The tag value if tag has been found or text substring.
* <code>NULL</code> in case of empty string.
*/
private String getNextTagOrTextInLine(String lineToScan)
{
// nothing to scan
if (lineToScan == null || lineToScan.isEmpty())
{
return null;
}
int tagStart = 0;
int tagEnd = -1;
String resStr = null;
if (lineToScan.startsWith(XprTag.START))
{
tagEnd = lineToScan.indexOf(XprTag.END);
if (tagEnd != -1)
{
// extract next tag from string
resStr = lineToScan.substring(tagStart, tagEnd + 1);
}
}
else
{
// the text is considering to be here
tagEnd = lineToScan.indexOf(XprTag.START);
if (tagEnd == -1)
{
// only text has left
resStr = lineToScan.substring(tagStart);
}
else
{
// extract text part from string not including tag start
resStr = lineToScan.substring(tagStart, tagEnd);
}
}
return resStr;
}
/**
* Gets the single tag value for the given line. Works for tags that can only be in single
* occurence per file.
*
* @param tagToSearch
* The tag to search.
*
* @return The tag value if tag has been found or TAG_VALUE_ERROR otherwise.
*/
private String getSingleTagValue(String tagToSearch)
{
// the first occurence means tag has found
for (int i = 0; i < origPagesBuffer.size(); i++)
{
// page by page
List<String> origLinesBuffer = origPagesBuffer.get(i);
for (int j = 0; j < origLinesBuffer.size(); j++)
{
String currLine = origLinesBuffer.get(j);
int tagStart = currLine.indexOf(tagToSearch);
if (tagStart != -1)
{
currLine = currLine.substring(tagStart);
int tagEnd = currLine.indexOf(XprTag.END);
if (tagEnd != -1)
{
String resStr = currLine.substring(tagToSearch.length(), tagEnd);
return resStr;
}
}
}
}
// if we are here the tag value does not exist
return TAG_VALUE_ERROR;
}
/**
* Gets the tag value for the given full tag string.
*
* @param fullTag
* The full tag text including braces enclosed (<...>).
* @param tagMatch
* The tag used to locate this entry.
*
* @return The tag value without any extra info, only what inside braces.
*/
private String getTagValue(String fullTag, String tagMatch)
{
return fullTag.substring(tagMatch.length(), fullTag.length() - 1);
}
/**
* Extract the color nalue from the given tag value. Different color specification formats
* are possible.
*
* @param tagValue
* The tag value to check without tag start and end markers.
*
* @return The color value as RGB integer.
*/
private int getColorFromTag(String tagValue)
{
// default color in case of error
int retColor = 0xFF000000;
// first check if the color is the name in XPR palette
ColorRgb paletteColor = xprPalette.get(tagValue.toUpperCase());
if (paletteColor != null)
{
// we keep alpha channel as opaque
retColor |= paletteColor.getGuiRgb();
}
// not found in palette, try to consider as "r,g,b" format
else
{
// currently we properly handle "r,g,b" format, any non-digit can be the delimiter
String [] colors = tagValue.split(ANY_CHAR_BUT_DIGIT);
// the colors array has valid size and content
if (colors.length == 3 && colors[0].matches(INTEGER_DIGIT) &&
colors[1].matches(INTEGER_DIGIT) && colors[2].matches(INTEGER_DIGIT))
{
int redValue = Integer.valueOf(colors[0]).intValue();
int greenValue = Integer.valueOf(colors[1]).intValue();
int blueValue = Integer.valueOf(colors[2]).intValue();
// compute the final value to be Java compatible
// ((blueValue & 0xFF) << 16) | ((greenValue & 0xFF) << 8) | (redValue & 0xFF)
// we keep alpha channel as opaque
retColor |= new ColorRgb(redValue, greenValue, blueValue).getGuiRgb();
}
else
{
// badly formatted color value
XprHelper.displayOrLogError(
String.format("XPR Entity has found invalid color format in tag %s.", tagValue));
}
}
return retColor;
}
/**
* Resets current variables to initial values. Need to run this before processing new page.
*/
private void resetInitials()
{
// reset constans
colCurr = 1.0;
rowCurr = 1.0;
colFrom = 1.0;
rowFrom = 1.0;
lineWidth = 1;
currFontName = FONT_NAME_DEFAULT;
parSize = FONT_SIZE_DEFAULT;
// TODO: find out if LPI and CPI values are resetting from page to page
// linesPerInch = 6.0;
// charsPerInch = 10.0;
isBoldFont = false;
isItalicFont = false;
bgColor = 0xFFFFFFFF;
fgColor = 0xFF000000;
lineColor = 0xFF000000;
// erase bookmarks
bkmks.clear();
}
/**
* Calculate if the given text match the tag value provided. The condition is the text must
* be started with tag value, not necessary to be the same length. Case sensitivity is not
* important.
*
* @param textToScan
* The text to compute tag matching.
* @param tag
* The uppercased tag value to find within text.
*
* @return <code>TRUE</code> if tag found, <code>FALSE</code> otherwise.
*/
private boolean tagMatch(String textToScan, String tag)
{
// the tag and text should not be null or empty
if (textToScan == null || textToScan.isEmpty() || tag == null || tag.isEmpty())
{
return false;
}
// the text should not be shorted than tag
int tagLength = tag.length();
if (textToScan.length() < tagLength)
{
return false;
}
// now check the text body
for (int i = 0; i < tagLength; i ++)
{
// the code below makes comparison case insensitive
if (Character.toUpperCase(textToScan.charAt(i)) != tag.charAt(i))
{
// first deviation, tag does not match
return false;
}
}
// here means all tag chars matches the text to scan
return true;
}
}