/* ******************************************************************************* * Copyright (C) 2001-2009, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************* */ package com.ibm.icu.dev.test.shaping; import com.ibm.icu.text.ArabicShaping; import com.ibm.icu.text.ArabicShapingException; /** * Interactive test for Arabic shaping. * Invoke from a command line passing args and strings. Use '-help' to see description of arguments. */ public class ArabicShapingTest{ private static final int COPY = 0; private static final int INPLACE = 1; private static final int STRING = 2; public static final void main(String[] args) { int testtype = COPY; int options = 0; int ss = 0; int sl = -1; int ds = 0; int dl = -1; String text = "$22.4 test 123 \ufef6\u0644\u0622 456 \u0664\u0665\u0666!"; for (int i = 0; i < args.length; ++i) { String arg = args[i]; if (arg.charAt(0) == '-') { String opt = arg.substring(1); String val = opt; int index = arg.indexOf(':'); if (index != -1) { opt = opt.substring(0, Math.min(index, 3)); val = arg.substring(index + 1); } if (opt.equalsIgnoreCase("len")) { options &= ~ArabicShaping.LENGTH_MASK; if (val.equalsIgnoreCase("gs")) { options |= ArabicShaping.LENGTH_GROW_SHRINK; } else if (val.equalsIgnoreCase("sn")) { options |= ArabicShaping.LENGTH_FIXED_SPACES_NEAR; } else if (val.equalsIgnoreCase("se")) { options |= ArabicShaping.LENGTH_FIXED_SPACES_AT_END; } else if (val.equalsIgnoreCase("sb")) { options |= ArabicShaping.LENGTH_FIXED_SPACES_AT_BEGINNING; } else { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("dir")) { options &= ~ArabicShaping.TEXT_DIRECTION_MASK; if (val.equalsIgnoreCase("log")) { options |= ArabicShaping.TEXT_DIRECTION_LOGICAL; } else if (val.equalsIgnoreCase("vis")) { options |= ArabicShaping.TEXT_DIRECTION_VISUAL_LTR; } else { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("let")) { options &= ~ArabicShaping.LETTERS_MASK; if (val.equalsIgnoreCase("no")) { options |= ArabicShaping.LETTERS_NOOP; } else if (val.equalsIgnoreCase("sh")) { options |= ArabicShaping.LETTERS_SHAPE; } else if (val.equalsIgnoreCase("un")) { options |= ArabicShaping.LETTERS_UNSHAPE; } else if (val.equalsIgnoreCase("ta")) { options |= ArabicShaping.LETTERS_SHAPE_TASHKEEL_ISOLATED; } else { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("dig")) { options &= ~ArabicShaping.DIGITS_MASK; if (val.equalsIgnoreCase("no")) { options |= ArabicShaping.DIGITS_NOOP; } else if (val.equalsIgnoreCase("ea")) { options |= ArabicShaping.DIGITS_EN2AN; } else if (val.equalsIgnoreCase("ae")) { options |= ArabicShaping.DIGITS_AN2EN; } else if (val.equalsIgnoreCase("lr")) { options |= ArabicShaping.DIGITS_EN2AN_INIT_LR; } else if (val.equalsIgnoreCase("al")) { options |= ArabicShaping.DIGITS_EN2AN_INIT_AL; } else { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("typ")) { options &= ~ArabicShaping.DIGIT_TYPE_MASK; if (val.equalsIgnoreCase("an")) { options |= ArabicShaping.DIGIT_TYPE_AN; } else if (val.equalsIgnoreCase("ex")) { options |= ArabicShaping.DIGIT_TYPE_AN_EXTENDED; } else { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("dst")) { try { ds = Integer.parseInt(val); } catch (Exception e) { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("dln")) { try { dl = Integer.parseInt(val); } catch (Exception e) { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("sst")) { try { ss = Integer.parseInt(val); } catch (Exception e) { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("sln")) { try { sl = Integer.parseInt(val); } catch (Exception e) { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("tes")) { if (val.equalsIgnoreCase("cp")) { testtype = COPY; } else if (val.equalsIgnoreCase("ip")) { testtype = INPLACE; } else if (val.equalsIgnoreCase("st")) { testtype = STRING; } else { throwValError(opt, val); } } else if (opt.equalsIgnoreCase("help")) { System.out.println(usage); } else { throwOptError(opt); } } else { // assume text text = parseText(arg); } } if (sl < 0) { sl = text.length() - ss; System.out.println("sl defaulting to " + sl); } if (dl < 0) { dl = 2 * sl; System.out.println("dl defaulting to " + dl); } ArabicShaping shaper = new ArabicShaping(options); System.out.println("shaper: " + shaper); char[] src = text.toCharArray(); System.out.println(" input: '" + escapedText(src, ss, sl) + "'"); if (testtype != STRING) { System.out.println("start: " + ss + " length: " + sl + " total length: " + src.length); } int result = -1; char[] dest = null; try { switch (testtype) { case COPY: dest = new char[ds + dl]; result = shaper.shape(src, ss, sl, dest, ds, dl); break; case INPLACE: shaper.shape(src, ss, sl); ds = ss; result = sl; dest = src; break; case STRING: dest = shaper.shape(text).toCharArray(); ds = 0; result = dest.length; break; } System.out.println("output: '" + escapedText(dest, ds, result) + "'"); System.out.println("length: " + result); if (ds != 0 || result != dest.length) { System.out.println("full output: '" + escapedText(dest, 0, dest.length) + "'"); } } catch (ArabicShapingException e) { System.out.println("Caught ArabicShapingException"); System.out.println(e); } catch (Exception e) { System.out.println("Caught Exception"); System.out.println(e); } } private static void throwOptError(String opt) { throwUsageError("unknown option: " + opt); } private static void throwValError(String opt, String val) { throwUsageError("unknown value: " + val + " for option: " + opt); } private static void throwUsageError(String message) { StringBuffer buf = new StringBuffer("*** usage error ***\n"); buf.append(message); buf.append("\n"); buf.append(usage); throw new Error(buf.toString()); } private static final String usage = "Usage: [option]* [text]\n" + " where option is in the format '-opt[:val]'\n" + " options are:\n" + " -len:[gs|sn|se|sb] (length: grow/shrink, spaces near, spaces end, spaces beginning)\n" + " -dir:[log|vis] (direction: logical, visual)\n" + " -let:[no|sh|un|ta] (letters: noop, shape, unshape, tashkeel)\n" + // " -let:[no|sh|un] (letters: noop, shape, unshape)\n" + " -dig:[no|ea|ae|lr|al] (digits: noop, en2an, an2en, en2an_lr, en2an_al)\n" + " -typ:[an|ex] (digit type: arabic, arabic extended)\n" + " -dst:# (dest start: [integer])\n" + " -dln:# (dest length (max size): [integer])\n" + " -sst:# (source start: [integer])\n" + " -sln:# (source length: [integer])\n" + " -tes:[cp|ip|st] (test type: copy, in place, string)\n" + " -help (print this help message)\n" + " text can contain unicode escape values in the format '\\uXXXX' only\n"; private static String escapedText(char[] text, int start, int length) { StringBuffer buf = new StringBuffer(); for (int i = start, e = start + length; i < e; ++i) { char ch = text[i]; if (ch < 0x20 || ch > 0x7e) { buf.append("\\u"); if (ch < 0x1000) { buf.append('0'); } if (ch < 0x100) { buf.append('0'); } if (ch < 0x10) { buf.append('0'); } buf.append(Integer.toHexString(ch)); } else { buf.append(ch); } } return buf.toString(); } private static String parseText(String text) { // process unicode escapes (only) StringBuffer buf = new StringBuffer(); char[] chars = text.toCharArray(); for (int i = 0; i < chars.length; ++i) { char ch = chars[i]; if (ch == '\\') { if ((i < chars.length - 1) && (chars[i+1] == 'u')) { int val = Integer.parseInt(text.substring(i+2, i+6), 16); buf.append((char)val); i += 5; } else { buf.append('\\'); } } else { buf.append(ch); } } return buf.toString(); } }