1. /*
  2. * @(#)Utility.java 1.10 00/01/19
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. /*
  11. * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  12. * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  13. *
  14. * The original version of this source code and documentation
  15. * is copyrighted and owned by Taligent, Inc., a wholly-owned
  16. * subsidiary of IBM. These materials are provided under terms
  17. * of a License Agreement between Taligent and Sun. This technology
  18. * is protected by multiple US and International patents.
  19. *
  20. * This notice and attribution to Taligent may not be removed.
  21. * Taligent is a registered trademark of Taligent, Inc.
  22. *
  23. */
  24. package java.text;
  25. final class Utility {
  26. /**
  27. * Convenience utility to compare two Object[]s.
  28. * Ought to be in System
  29. */
  30. final static boolean arrayEquals(Object[] source, Object target) {
  31. if (source == null) return (target == null);
  32. if (!(target instanceof Object[])) return false;
  33. Object[] targ = (Object[]) target;
  34. return (source.length == targ.length
  35. && arrayRegionMatches(source, 0, targ, 0, source.length));
  36. }
  37. /**
  38. * Convenience utility to compare two int[]s
  39. * Ought to be in System
  40. */
  41. final static boolean arrayEquals(int[] source, Object target) {
  42. if (source == null) return (target == null);
  43. if (!(target instanceof int[])) return false;
  44. int[] targ = (int[]) target;
  45. return (source.length == targ.length
  46. && arrayRegionMatches(source, 0, targ, 0, source.length));
  47. }
  48. /**
  49. * Convenience utility to compare two double[]s
  50. * Ought to be in System
  51. */
  52. final static boolean arrayEquals(double[] source, Object target) {
  53. if (source == null) return (target == null);
  54. if (!(target instanceof double[])) return false;
  55. double[] targ = (double[]) target;
  56. return (source.length == targ.length
  57. && arrayRegionMatches(source, 0, targ, 0, source.length));
  58. }
  59. /**
  60. * Convenience utility to compare two Object[]s
  61. * Ought to be in System
  62. */
  63. final static boolean arrayEquals(Object source, Object target) {
  64. if (source == null) return (target == null);
  65. // for some reason, the correct arrayEquals is not being called
  66. // so do it by hand for now.
  67. if (source instanceof Object[])
  68. return(arrayEquals((Object[]) source,target));
  69. if (source instanceof int[])
  70. return(arrayEquals((int[]) source,target));
  71. if (source instanceof double[])
  72. return(arrayEquals((int[]) source,target));
  73. return source.equals(target);
  74. }
  75. /**
  76. * Convenience utility to compare two Object[]s
  77. * Ought to be in System.
  78. * @param len the length to compare.
  79. * The start indices and start+len must be valid.
  80. */
  81. final static boolean arrayRegionMatches(Object[] source, int sourceStart,
  82. Object[] target, int targetStart,
  83. int len)
  84. {
  85. int sourceEnd = sourceStart + len;
  86. int delta = targetStart - sourceStart;
  87. for (int i = sourceStart; i < sourceEnd; i++) {
  88. if (!arrayEquals(source[i],target[i + delta]))
  89. return false;
  90. }
  91. return true;
  92. }
  93. /**
  94. * Convenience utility to compare two int[]s.
  95. * @param len the length to compare.
  96. * The start indices and start+len must be valid.
  97. * Ought to be in System
  98. */
  99. final static boolean arrayRegionMatches(int[] source, int sourceStart,
  100. int[] target, int targetStart,
  101. int len)
  102. {
  103. int sourceEnd = sourceStart + len;
  104. int delta = targetStart - sourceStart;
  105. for (int i = sourceStart; i < sourceEnd; i++) {
  106. if (source[i] != target[i + delta])
  107. return false;
  108. }
  109. return true;
  110. }
  111. /**
  112. * Convenience utility to compare two arrays of doubles.
  113. * @param len the length to compare.
  114. * The start indices and start+len must be valid.
  115. * Ought to be in System
  116. */
  117. final static boolean arrayRegionMatches(double[] source, int sourceStart,
  118. double[] target, int targetStart,
  119. int len)
  120. {
  121. int sourceEnd = sourceStart + len;
  122. int delta = targetStart - sourceStart;
  123. for (int i = sourceStart; i < sourceEnd; i++) {
  124. if (source[i] != target[i + delta])
  125. return false;
  126. }
  127. return true;
  128. }
  129. /**
  130. * Convenience utility. Does null checks on objects, then calls equals.
  131. */
  132. final static boolean objectEquals(Object source, Object target) {
  133. if (source == null)
  134. return (target == null);
  135. else
  136. return source.equals(target);
  137. }
  138. /**
  139. * The ESCAPE character is used during run-length encoding. It signals
  140. * a run of identical chars.
  141. */
  142. static final char ESCAPE = '\uA5A5';
  143. /**
  144. * The ESCAPE_BYTE character is used during run-length encoding. It signals
  145. * a run of identical bytes.
  146. */
  147. static final byte ESCAPE_BYTE = (byte)0xA5;
  148. /**
  149. * Construct a string representing a short array. Use run-length encoding.
  150. * A character represents itself, unless it is the ESCAPE character. Then
  151. * the following notations are possible:
  152. * ESCAPE ESCAPE ESCAPE literal
  153. * ESCAPE n c n instances of character c
  154. * Since an encoded run occupies 3 characters, we only encode runs of 4 or
  155. * more characters. Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF.
  156. * If we encounter a run where n == ESCAPE, we represent this as:
  157. * c ESCAPE n-1 c
  158. * The ESCAPE value is chosen so as not to collide with commonly
  159. * seen values.
  160. */
  161. static final String arrayToRLEString(short[] a) {
  162. StringBuffer buffer = new StringBuffer();
  163. // for (int i=0; i<a.length; ++i) buffer.append((char) a[i]);
  164. buffer.append((char) (a.length >> 16));
  165. buffer.append((char) a.length);
  166. short runValue = a[0];
  167. int runLength = 1;
  168. for (int i=1; i<a.length; ++i) {
  169. short s = a[i];
  170. if (s == runValue && runLength < 0xFFFF) ++runLength;
  171. else {
  172. encodeRun(buffer, runValue, runLength);
  173. runValue = s;
  174. runLength = 1;
  175. }
  176. }
  177. encodeRun(buffer, runValue, runLength);
  178. return buffer.toString();
  179. }
  180. /**
  181. * Construct a string representing a byte array. Use run-length encoding.
  182. * Two bytes are packed into a single char, with a single extra zero byte at
  183. * the end if needed. A byte represents itself, unless it is the
  184. * ESCAPE_BYTE. Then the following notations are possible:
  185. * ESCAPE_BYTE ESCAPE_BYTE ESCAPE_BYTE literal
  186. * ESCAPE_BYTE n b n instances of byte b
  187. * Since an encoded run occupies 3 bytes, we only encode runs of 4 or
  188. * more bytes. Thus we have n > 0 and n != ESCAPE_BYTE and n <= 0xFF.
  189. * If we encounter a run where n == ESCAPE_BYTE, we represent this as:
  190. * b ESCAPE_BYTE n-1 b
  191. * The ESCAPE_BYTE value is chosen so as not to collide with commonly
  192. * seen values.
  193. */
  194. static final String arrayToRLEString(byte[] a) {
  195. StringBuffer buffer = new StringBuffer();
  196. buffer.append((char) (a.length >> 16));
  197. buffer.append((char) a.length);
  198. byte runValue = a[0];
  199. int runLength = 1;
  200. byte[] state = new byte[2];
  201. for (int i=1; i<a.length; ++i) {
  202. byte b = a[i];
  203. if (b == runValue && runLength < 0xFF) ++runLength;
  204. else {
  205. encodeRun(buffer, runValue, runLength, state);
  206. runValue = b;
  207. runLength = 1;
  208. }
  209. }
  210. encodeRun(buffer, runValue, runLength, state);
  211. // We must save the final byte, if there is one, by padding
  212. // an extra zero.
  213. if (state[0] != 0) appendEncodedByte(buffer, (byte)0, state);
  214. return buffer.toString();
  215. }
  216. /**
  217. * Encode a run, possibly a degenerate run (of < 4 values).
  218. * @param length The length of the run; must be > 0 && <= 0xFFFF.
  219. */
  220. private static final void encodeRun(StringBuffer buffer, short value, int length) {
  221. if (length < 4) {
  222. for (int j=0; j<length; ++j) {
  223. if (value == (int) ESCAPE) buffer.append(ESCAPE);
  224. buffer.append((char) value);
  225. }
  226. }
  227. else {
  228. if (length == (int) ESCAPE) {
  229. if (value == (int) ESCAPE) buffer.append(ESCAPE);
  230. buffer.append((char) value);
  231. --length;
  232. }
  233. buffer.append(ESCAPE);
  234. buffer.append((char) length);
  235. buffer.append((char) value); // Don't need to escape this value
  236. }
  237. }
  238. /**
  239. * Encode a run, possibly a degenerate run (of < 4 values).
  240. * @param length The length of the run; must be > 0 && <= 0xFF.
  241. */
  242. private static final void encodeRun(StringBuffer buffer, byte value, int length,
  243. byte[] state) {
  244. if (length < 4) {
  245. for (int j=0; j<length; ++j) {
  246. if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
  247. appendEncodedByte(buffer, value, state);
  248. }
  249. }
  250. else {
  251. if (length == ESCAPE_BYTE) {
  252. if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
  253. appendEncodedByte(buffer, value, state);
  254. --length;
  255. }
  256. appendEncodedByte(buffer, ESCAPE_BYTE, state);
  257. appendEncodedByte(buffer, (byte)length, state);
  258. appendEncodedByte(buffer, value, state); // Don't need to escape this value
  259. }
  260. }
  261. /**
  262. * Append a byte to the given StringBuffer, packing two bytes into each
  263. * character. The state parameter maintains intermediary data between
  264. * calls.
  265. * @param state A two-element array, with state[0] == 0 if this is the
  266. * first byte of a pair, or state[0] != 0 if this is the second byte
  267. * of a pair, in which case state[1] is the first byte.
  268. */
  269. private static final void appendEncodedByte(StringBuffer buffer, byte value,
  270. byte[] state) {
  271. if (state[0] != 0) {
  272. char c = (char) ((state[1] << 8) | (((int) value) & 0xFF));
  273. buffer.append(c);
  274. state[0] = 0;
  275. }
  276. else {
  277. state[0] = 1;
  278. state[1] = value;
  279. }
  280. }
  281. /**
  282. * Construct an array of shorts from a run-length encoded string.
  283. */
  284. static final short[] RLEStringToShortArray(String s) {
  285. int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
  286. short[] array = new short[length];
  287. int ai = 0;
  288. for (int i=2; i<s.length(); ++i) {
  289. char c = s.charAt(i);
  290. if (c == ESCAPE) {
  291. c = s.charAt(++i);
  292. if (c == ESCAPE) array[ai++] = (short) c;
  293. else {
  294. int runLength = (int) c;
  295. short runValue = (short) s.charAt(++i);
  296. for (int j=0; j<runLength; ++j) array[ai++] = runValue;
  297. }
  298. }
  299. else {
  300. array[ai++] = (short) c;
  301. }
  302. }
  303. if (ai != length)
  304. throw new InternalError("Bad run-length encoded short array");
  305. return array;
  306. }
  307. /**
  308. * Construct an array of bytes from a run-length encoded string.
  309. */
  310. static final byte[] RLEStringToByteArray(String s) {
  311. int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
  312. byte[] array = new byte[length];
  313. boolean nextChar = true;
  314. char c = 0;
  315. int node = 0;
  316. int runLength = 0;
  317. int i = 2;
  318. for (int ai=0; ai<length; ) {
  319. // This part of the loop places the next byte into the local
  320. // variable 'b' each time through the loop. It keeps the
  321. // current character in 'c' and uses the boolean 'nextChar'
  322. // to see if we've taken both bytes out of 'c' yet.
  323. byte b;
  324. if (nextChar) {
  325. c = s.charAt(i++);
  326. b = (byte) (c >> 8);
  327. nextChar = false;
  328. }
  329. else {
  330. b = (byte) (c & 0xFF);
  331. nextChar = true;
  332. }
  333. // This part of the loop is a tiny state machine which handles
  334. // the parsing of the run-length encoding. This would be simpler
  335. // if we could look ahead, but we can't, so we use 'node' to
  336. // move between three nodes in the state machine.
  337. switch (node) {
  338. case 0:
  339. // Normal idle node
  340. if (b == ESCAPE_BYTE) {
  341. node = 1;
  342. }
  343. else {
  344. array[ai++] = b;
  345. }
  346. break;
  347. case 1:
  348. // We have seen one ESCAPE_BYTE; we expect either a second
  349. // one, or a run length and value.
  350. if (b == ESCAPE_BYTE) {
  351. array[ai++] = ESCAPE_BYTE;
  352. node = 0;
  353. }
  354. else {
  355. runLength = b;
  356. // Interpret signed byte as unsigned
  357. if (runLength < 0) runLength += 0x100;
  358. node = 2;
  359. }
  360. break;
  361. case 2:
  362. // We have seen an ESCAPE_BYTE and length byte. We interpret
  363. // the next byte as the value to be repeated.
  364. for (int j=0; j<runLength; ++j) array[ai++] = b;
  365. node = 0;
  366. break;
  367. }
  368. }
  369. if (node != 0)
  370. throw new InternalError("Bad run-length encoded byte array");
  371. if (i != s.length())
  372. throw new InternalError("Excess data in RLE byte array string");
  373. return array;
  374. }
  375. /**
  376. * Format a String for representation in a source file. This includes
  377. * breaking it into lines escaping characters using octal notation
  378. * when necessary (control characters and double quotes).
  379. */
  380. static final String formatForSource(String s) {
  381. StringBuffer buffer = new StringBuffer();
  382. for (int i=0; i<s.length();) {
  383. if (i > 0) buffer.append("+\n");
  384. buffer.append(" \"");
  385. int count = 11;
  386. while (i<s.length() && count<80) {
  387. char c = s.charAt(i++);
  388. if (c < '\u0020' || c == '"') {
  389. // Represent control characters and the double quote
  390. // using octal notation; otherwise the string we form
  391. // won't compile, since Unicode escape sequences are
  392. // processed before tokenization.
  393. buffer.append('\\');
  394. buffer.append(HEX_DIGIT[(c & 0700) >> 6]); // HEX_DIGIT works for octal
  395. buffer.append(HEX_DIGIT[(c & 0070) >> 3]);
  396. buffer.append(HEX_DIGIT[(c & 0007)]);
  397. count += 4;
  398. }
  399. else if (c <= '\u007E') {
  400. buffer.append(c);
  401. count += 1;
  402. }
  403. else {
  404. buffer.append("\\u");
  405. buffer.append(HEX_DIGIT[(c & 0xF000) >> 12]);
  406. buffer.append(HEX_DIGIT[(c & 0x0F00) >> 8]);
  407. buffer.append(HEX_DIGIT[(c & 0x00F0) >> 4]);
  408. buffer.append(HEX_DIGIT[(c & 0x000F)]);
  409. count += 6;
  410. }
  411. }
  412. buffer.append('"');
  413. }
  414. return buffer.toString();
  415. }
  416. static final char[] HEX_DIGIT = {'0','1','2','3','4','5','6','7',
  417. '8','9','A','B','C','D','E','F'};
  418. }