001: /*
002: * Copyright 2002 Paulo Soares
003: *
004: * The contents of this file are subject to the Mozilla Public License Version 1.1
005: * (the "License"); you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the License.
011: *
012: * The Original Code is 'iText, a free JAVA-PDF library'.
013: *
014: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
015: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
016: * All Rights Reserved.
017: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
018: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
019: *
020: * Contributor(s): all the names of the contributors are added in the source code
021: * where applicable.
022: *
023: * Alternatively, the contents of this file may be used under the terms of the
024: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
025: * provisions of LGPL are applicable instead of those above. If you wish to
026: * allow use of your version of this file only under the terms of the LGPL
027: * License and not to allow others to use your version of this file under
028: * the MPL, indicate your decision by deleting the provisions above and
029: * replace them with the notice and other provisions required by the LGPL.
030: * If you do not delete the provisions above, a recipient may use your version
031: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
032: *
033: * This library is free software; you can redistribute it and/or modify it
034: * under the terms of the MPL as stated above or under the terms of the GNU
035: * Library General Public License as published by the Free Software Foundation;
036: * either version 2 of the License, or any later version.
037: *
038: * This library is distributed in the hope that it will be useful, but WITHOUT
039: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
040: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
041: * details.
042: *
043: * If you didn't download this code from the following link, you should check if
044: * you aren't using an obsolete version:
045: * http://www.lowagie.com/iText/
046: */
047:
048: package com.lowagie.text.pdf;
049:
050: import java.io.BufferedReader;
051: import java.io.IOException;
052: import java.io.InputStream;
053: import java.io.InputStreamReader;
054: import java.io.UnsupportedEncodingException;
055: import java.util.ArrayList;
056: import java.util.HashMap;
057: import java.util.StringTokenizer;
058:
059: import com.lowagie.text.ExceptionConverter;
060:
061: /** Supports fast encodings for winansi and PDFDocEncoding.
062: * Supports conversions from CJK encodings to CID.
063: * Supports custom encodings.
064: * @author Paulo Soares (psoares@consiste.pt)
065: */
066: public class PdfEncodings {
067: protected static final int CIDNONE = 0;
068: protected static final int CIDRANGE = 1;
069: protected static final int CIDCHAR = 2;
070:
071: static final char winansiByteToChar[] = { 0, 1, 2, 3, 4, 5, 6, 7,
072: 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
073: 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
074: 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
075: 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
076: 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
077: 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
078: 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
079: 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
080: 122, 123, 124, 125, 126, 127, 8364, 65533, 8218, 402, 8222,
081: 8230, 8224, 8225, 710, 8240, 352, 8249, 338, 65533, 381,
082: 65533, 65533, 8216, 8217, 8220, 8221, 8226, 8211, 8212,
083: 732, 8482, 353, 8250, 339, 65533, 382, 376, 160, 161, 162,
084: 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
085: 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
086: 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
087: 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
088: 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
089: 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234,
090: 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246,
091: 247, 248, 249, 250, 251, 252, 253, 254, 255 };
092:
093: static final char pdfEncodingByteToChar[] = { 0, 1, 2, 3, 4, 5, 6,
094: 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
095: 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
096: 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
097: 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
098: 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
099: 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
100: 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
101: 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
102: 121, 122, 123, 124, 125, 126, 127, 0x2022, 0x2020, 0x2021,
103: 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, 0x2039, 0x203a,
104: 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019,
105: 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160,
106: 0x0178, 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e,
107: 65533, 0x20ac, 161, 162, 163, 164, 165, 166, 167, 168, 169,
108: 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
109: 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
110: 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205,
111: 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217,
112: 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
113: 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
114: 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253,
115: 254, 255 };
116:
117: static final IntHashtable winansi = new IntHashtable();
118:
119: static final IntHashtable pdfEncoding = new IntHashtable();
120:
121: static HashMap extraEncodings = new HashMap();
122:
123: static {
124: for (int k = 128; k < 160; ++k) {
125: char c = winansiByteToChar[k];
126: if (c != 65533)
127: winansi.put(c, k);
128: }
129:
130: for (int k = 128; k < 161; ++k) {
131: char c = pdfEncodingByteToChar[k];
132: if (c != 65533)
133: pdfEncoding.put(c, k);
134: }
135:
136: addExtraEncoding("Wingdings", new WingdingsConversion());
137: addExtraEncoding("Symbol", new SymbolConversion(true));
138: addExtraEncoding("ZapfDingbats", new SymbolConversion(false));
139: addExtraEncoding("SymbolTT", new SymbolTTConversion());
140: addExtraEncoding("Cp437", new Cp437Conversion());
141: }
142:
143: /** Converts a <CODE>String</CODE> to a </CODE>byte</CODE> array according
144: * to the font's encoding.
145: * @return an array of <CODE>byte</CODE> representing the conversion according to the font's encoding
146: * @param encoding the encoding
147: * @param text the <CODE>String</CODE> to be converted
148: */
149: public static final byte[] convertToBytes(String text,
150: String encoding) {
151: if (text == null)
152: return new byte[0];
153: if (encoding == null || encoding.length() == 0) {
154: int len = text.length();
155: byte b[] = new byte[len];
156: for (int k = 0; k < len; ++k)
157: b[k] = (byte) text.charAt(k);
158: return b;
159: }
160: ExtraEncoding extra = (ExtraEncoding) extraEncodings
161: .get(encoding.toLowerCase());
162: if (extra != null) {
163: byte b[] = extra.charToByte(text, encoding);
164: if (b != null)
165: return b;
166: }
167: IntHashtable hash = null;
168: if (encoding.equals(BaseFont.WINANSI))
169: hash = winansi;
170: else if (encoding.equals(PdfObject.TEXT_PDFDOCENCODING))
171: hash = pdfEncoding;
172: if (hash != null) {
173: char cc[] = text.toCharArray();
174: int len = cc.length;
175: int ptr = 0;
176: byte b[] = new byte[len];
177: int c = 0;
178: for (int k = 0; k < len; ++k) {
179: char char1 = cc[k];
180: if (char1 < 128 || (char1 >= 160 && char1 <= 255))
181: c = char1;
182: else
183: c = hash.get(char1);
184: if (c != 0)
185: b[ptr++] = (byte) c;
186: }
187: if (ptr == len)
188: return b;
189: byte b2[] = new byte[ptr];
190: System.arraycopy(b, 0, b2, 0, ptr);
191: return b2;
192: }
193: if (encoding.equals(PdfObject.TEXT_UNICODE)) {
194: // workaround for jdk 1.2.2 bug
195: char cc[] = text.toCharArray();
196: int len = cc.length;
197: byte b[] = new byte[cc.length * 2 + 2];
198: b[0] = -2;
199: b[1] = -1;
200: int bptr = 2;
201: for (int k = 0; k < len; ++k) {
202: char c = cc[k];
203: b[bptr++] = (byte) (c >> 8);
204: b[bptr++] = (byte) (c & 0xff);
205: }
206: return b;
207: }
208: try {
209: return text.getBytes(encoding);
210: } catch (UnsupportedEncodingException e) {
211: throw new ExceptionConverter(e);
212: }
213: }
214:
215: /** Converts a <CODE>String</CODE> to a </CODE>byte</CODE> array according
216: * to the font's encoding.
217: * @return an array of <CODE>byte</CODE> representing the conversion according to the font's encoding
218: * @param encoding the encoding
219: * @param char1 the <CODE>char</CODE> to be converted
220: */
221: public static final byte[] convertToBytes(char char1,
222: String encoding) {
223: if (encoding == null || encoding.length() == 0)
224: return new byte[] { (byte) char1 };
225: ExtraEncoding extra = (ExtraEncoding) extraEncodings
226: .get(encoding.toLowerCase());
227: if (extra != null) {
228: byte b[] = extra.charToByte(char1, encoding);
229: if (b != null)
230: return b;
231: }
232: IntHashtable hash = null;
233: if (encoding.equals(BaseFont.WINANSI))
234: hash = winansi;
235: else if (encoding.equals(PdfObject.TEXT_PDFDOCENCODING))
236: hash = pdfEncoding;
237: if (hash != null) {
238: int c = 0;
239: if (char1 < 128 || (char1 >= 160 && char1 <= 255))
240: c = char1;
241: else
242: c = hash.get(char1);
243: if (c != 0)
244: return new byte[] { (byte) c };
245: else
246: return new byte[0];
247: }
248: if (encoding.equals(PdfObject.TEXT_UNICODE)) {
249: // workaround for jdk 1.2.2 bug
250: byte b[] = new byte[4];
251: b[0] = -2;
252: b[1] = -1;
253: b[2] = (byte) (char1 >> 8);
254: b[3] = (byte) (char1 & 0xff);
255: return b;
256: }
257: try {
258: return String.valueOf(char1).getBytes(encoding);
259: } catch (UnsupportedEncodingException e) {
260: throw new ExceptionConverter(e);
261: }
262: }
263:
264: /** Converts a </CODE>byte</CODE> array to a <CODE>String</CODE> according
265: * to the some encoding.
266: * @param bytes the bytes to convert
267: * @param encoding the encoding
268: * @return the converted <CODE>String</CODE>
269: */
270: public static final String convertToString(byte bytes[],
271: String encoding) {
272: if (bytes == null)
273: return PdfObject.NOTHING;
274: if (encoding == null || encoding.length() == 0) {
275: char c[] = new char[bytes.length];
276: for (int k = 0; k < bytes.length; ++k)
277: c[k] = (char) (bytes[k] & 0xff);
278: return new String(c);
279: }
280: ExtraEncoding extra = (ExtraEncoding) extraEncodings
281: .get(encoding.toLowerCase());
282: if (extra != null) {
283: String text = extra.byteToChar(bytes, encoding);
284: if (text != null)
285: return text;
286: }
287: char ch[] = null;
288: if (encoding.equals(BaseFont.WINANSI))
289: ch = winansiByteToChar;
290: else if (encoding.equals(PdfObject.TEXT_PDFDOCENCODING))
291: ch = pdfEncodingByteToChar;
292: if (ch != null) {
293: int len = bytes.length;
294: char c[] = new char[len];
295: for (int k = 0; k < len; ++k) {
296: c[k] = ch[bytes[k] & 0xff];
297: }
298: return new String(c);
299: }
300: try {
301: return new String(bytes, encoding);
302: } catch (UnsupportedEncodingException e) {
303: throw new ExceptionConverter(e);
304: }
305: }
306:
307: /** Checks is <CODE>text</CODE> only has PdfDocEncoding characters.
308: * @param text the <CODE>String</CODE> to test
309: * @return <CODE>true</CODE> if only PdfDocEncoding characters are present
310: */
311: public static boolean isPdfDocEncoding(String text) {
312: if (text == null)
313: return true;
314: int len = text.length();
315: for (int k = 0; k < len; ++k) {
316: char char1 = text.charAt(k);
317: if (char1 < 128 || (char1 >= 160 && char1 <= 255))
318: continue;
319: if (!pdfEncoding.containsKey(char1))
320: return false;
321: }
322: return true;
323: }
324:
325: static final HashMap cmaps = new HashMap();
326: /** Assumes that '\\n' and '\\r\\n' are the newline sequences. It may not work for
327: * all CJK encodings. To be used with loadCmap().
328: */
329: public static final byte CRLF_CID_NEWLINE[][] = new byte[][] {
330: { (byte) '\n' }, { (byte) '\r', (byte) '\n' } };
331:
332: /** Clears the CJK cmaps from the cache. If <CODE>name</CODE> is the
333: * empty string then all the cache is cleared. Calling this method
334: * has no consequences other than the need to reload the cmap
335: * if needed.
336: * @param name the name of the cmap to clear or all the cmaps if the empty string
337: */
338: public static void clearCmap(String name) {
339: synchronized (cmaps) {
340: if (name.length() == 0)
341: cmaps.clear();
342: else
343: cmaps.remove(name);
344: }
345: }
346:
347: /** Loads a CJK cmap to the cache with the option of associating
348: * sequences to the newline.
349: * @param name the CJK cmap name
350: * @param newline the sequences to be replaced bi a newline in the resulting CID. See <CODE>CRLF_CID_NEWLINE</CODE>
351: */
352: public static void loadCmap(String name, byte newline[][]) {
353: try {
354: char planes[][] = null;
355: synchronized (cmaps) {
356: planes = (char[][]) cmaps.get(name);
357: }
358: if (planes == null) {
359: planes = readCmap(name, newline);
360: synchronized (cmaps) {
361: cmaps.put(name, planes);
362: }
363: }
364: } catch (IOException e) {
365: throw new ExceptionConverter(e);
366: }
367: }
368:
369: /** Converts a <CODE>byte</CODE> array encoded as <CODE>name</CODE>
370: * to a CID string. This is needed to reach some CJK characters
371: * that don't exist in 16 bit Unicode.</p>
372: * The font to use this result must use the encoding "Identity-H"
373: * or "Identity-V".</p>
374: * See ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/.
375: * @param name the CJK encoding name
376: * @param seq the <CODE>byte</CODE> array to be decoded
377: * @return the CID string
378: */
379: public static String convertCmap(String name, byte seq[]) {
380: return convertCmap(name, seq, 0, seq.length);
381: }
382:
383: /** Converts a <CODE>byte</CODE> array encoded as <CODE>name</CODE>
384: * to a CID string. This is needed to reach some CJK characters
385: * that don't exist in 16 bit Unicode.</p>
386: * The font to use this result must use the encoding "Identity-H"
387: * or "Identity-V".</p>
388: * See ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/.
389: * @param name the CJK encoding name
390: * @param start the start offset in the data
391: * @param length the number of bytes to convert
392: * @param seq the <CODE>byte</CODE> array to be decoded
393: * @return the CID string
394: */
395: public static String convertCmap(String name, byte seq[],
396: int start, int length) {
397: try {
398: char planes[][] = null;
399: synchronized (cmaps) {
400: planes = (char[][]) cmaps.get(name);
401: }
402: if (planes == null) {
403: planes = readCmap(name, (byte[][]) null);
404: synchronized (cmaps) {
405: cmaps.put(name, planes);
406: }
407: }
408: return decodeSequence(seq, start, length, planes);
409: } catch (IOException e) {
410: throw new ExceptionConverter(e);
411: }
412: }
413:
414: static String decodeSequence(byte seq[], int start, int length,
415: char planes[][]) {
416: StringBuffer buf = new StringBuffer();
417: int end = start + length;
418: int currentPlane = 0;
419: for (int k = start; k < end; ++k) {
420: int one = (int) seq[k] & 0xff;
421: char plane[] = planes[currentPlane];
422: int cid = plane[one];
423: if ((cid & 0x8000) == 0) {
424: buf.append((char) cid);
425: currentPlane = 0;
426: } else
427: currentPlane = cid & 0x7fff;
428: }
429: return buf.toString();
430: }
431:
432: static char[][] readCmap(String name, byte newline[][])
433: throws IOException {
434: ArrayList planes = new ArrayList();
435: planes.add(new char[256]);
436: readCmap(name, planes);
437: if (newline != null) {
438: for (int k = 0; k < newline.length; ++k)
439: encodeSequence(newline[k].length, newline[k],
440: BaseFont.CID_NEWLINE, planes);
441: }
442: char ret[][] = new char[planes.size()][];
443: return (char[][]) planes.toArray(ret);
444: }
445:
446: static void readCmap(String name, ArrayList planes)
447: throws IOException {
448: String fullName = BaseFont.RESOURCE_PATH + "cmaps/" + name;
449: InputStream in = BaseFont.getResourceStream(fullName);
450: if (in == null)
451: throw new IOException("The Cmap " + name
452: + " was not found.");
453: encodeStream(in, planes);
454: in.close();
455: }
456:
457: static void encodeStream(InputStream in, ArrayList planes)
458: throws IOException {
459: BufferedReader rd = new BufferedReader(new InputStreamReader(
460: in, "iso-8859-1"));
461: String line = null;
462: int state = CIDNONE;
463: byte seqs[] = new byte[7];
464: while ((line = rd.readLine()) != null) {
465: if (line.length() < 6)
466: continue;
467: switch (state) {
468: case CIDNONE: {
469: if (line.indexOf("begincidrange") >= 0)
470: state = CIDRANGE;
471: else if (line.indexOf("begincidchar") >= 0)
472: state = CIDCHAR;
473: else if (line.indexOf("usecmap") >= 0) {
474: StringTokenizer tk = new StringTokenizer(line);
475: String t = tk.nextToken();
476: readCmap(t.substring(1), planes);
477: }
478: break;
479: }
480: case CIDRANGE: {
481: if (line.indexOf("endcidrange") >= 0) {
482: state = CIDNONE;
483: break;
484: }
485: StringTokenizer tk = new StringTokenizer(line);
486: String t = tk.nextToken();
487: int size = t.length() / 2 - 1;
488: long start = Long.parseLong(t.substring(1,
489: t.length() - 1), 16);
490: t = tk.nextToken();
491: long end = Long.parseLong(t
492: .substring(1, t.length() - 1), 16);
493: t = tk.nextToken();
494: int cid = Integer.parseInt(t);
495: for (long k = start; k <= end; ++k) {
496: breakLong(k, size, seqs);
497: encodeSequence(size, seqs, (char) cid, planes);
498: ++cid;
499: }
500: break;
501: }
502: case CIDCHAR: {
503: if (line.indexOf("endcidchar") >= 0) {
504: state = CIDNONE;
505: break;
506: }
507: StringTokenizer tk = new StringTokenizer(line);
508: String t = tk.nextToken();
509: int size = t.length() / 2 - 1;
510: long start = Long.parseLong(t.substring(1,
511: t.length() - 1), 16);
512: t = tk.nextToken();
513: int cid = Integer.parseInt(t);
514: breakLong(start, size, seqs);
515: encodeSequence(size, seqs, (char) cid, planes);
516: break;
517: }
518: }
519: }
520: }
521:
522: static void breakLong(long n, int size, byte seqs[]) {
523: for (int k = 0; k < size; ++k) {
524: seqs[k] = (byte) (n >> ((size - 1 - k) * 8));
525: }
526: }
527:
528: static void encodeSequence(int size, byte seqs[], char cid,
529: ArrayList planes) {
530: --size;
531: int nextPlane = 0;
532: for (int idx = 0; idx < size; ++idx) {
533: char plane[] = (char[]) planes.get(nextPlane);
534: int one = (int) seqs[idx] & 0xff;
535: char c = plane[one];
536: if (c != 0 && (c & 0x8000) == 0)
537: throw new RuntimeException("Inconsistent mapping.");
538: if (c == 0) {
539: planes.add(new char[256]);
540: c = (char) ((planes.size() - 1) | 0x8000);
541: plane[one] = c;
542: }
543: nextPlane = c & 0x7fff;
544: }
545: char plane[] = (char[]) planes.get(nextPlane);
546: int one = (int) seqs[size] & 0xff;
547: char c = plane[one];
548: if ((c & 0x8000) != 0)
549: throw new RuntimeException("Inconsistent mapping.");
550: plane[one] = cid;
551: }
552:
553: /** Adds an extra encoding.
554: * @param name the name of the encoding. The encoding recognition is case insensitive
555: * @param enc the conversion class
556: */
557: public static void addExtraEncoding(String name, ExtraEncoding enc) {
558: synchronized (extraEncodings) { // This serializes concurrent updates
559: HashMap newEncodings = (HashMap) extraEncodings.clone();
560: newEncodings.put(name.toLowerCase(), enc);
561: extraEncodings = newEncodings; // This swap does not require synchronization with reader
562: }
563: }
564:
565: private static class WingdingsConversion implements ExtraEncoding {
566:
567: public byte[] charToByte(char char1, String encoding) {
568: if (char1 == ' ')
569: return new byte[] { (byte) char1 };
570: else if (char1 >= '\u2701' && char1 <= '\u27BE') {
571: byte v = table[char1 - 0x2700];
572: if (v != 0)
573: return new byte[] { v };
574: }
575: return new byte[0];
576: }
577:
578: public byte[] charToByte(String text, String encoding) {
579: char cc[] = text.toCharArray();
580: byte b[] = new byte[cc.length];
581: int ptr = 0;
582: int len = cc.length;
583: for (int k = 0; k < len; ++k) {
584: char c = cc[k];
585: if (c == ' ')
586: b[ptr++] = (byte) c;
587: else if (c >= '\u2701' && c <= '\u27BE') {
588: byte v = table[c - 0x2700];
589: if (v != 0)
590: b[ptr++] = v;
591: }
592: }
593: if (ptr == len)
594: return b;
595: byte b2[] = new byte[ptr];
596: System.arraycopy(b, 0, b2, 0, ptr);
597: return b2;
598: }
599:
600: public String byteToChar(byte[] b, String encoding) {
601: return null;
602: }
603:
604: private final static byte table[] = { 0, 35, 34, 0, 0, 0, 41,
605: 62, 81, 42, 0, 0, 65, 63, 0, 0, 0, 0, 0, -4, 0, 0, 0,
606: -5, 0, 0, 0, 0, 0, 0, 86, 0, 88, 89, 0, 0, 0, 0, 0, 0,
607: 0, 0, -75, 0, 0, 0, 0, 0, -74, 0, 0, 0, -83, -81, -84,
608: 0, 0, 0, 0, 0, 0, 0, 0, 124, 123, 0, 0, 0, 84, 0, 0, 0,
609: 0, 0, 0, 0, 0, -90, 0, 0, 0, 113, 114, 0, 0, 0, 117, 0,
610: 0, 0, 0, 0, 0, 125, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
611: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -116, -115,
612: -114, -113, -112, -111, -110, -109, -108, -107, -127,
613: -126, -125, -124, -123, -122, -121, -120, -119, -118,
614: -116, -115, -114, -113, -112, -111, -110, -109, -108,
615: -107, -24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24,
616: -40, 0, 0, -60, -58, 0, 0, -16, 0, 0, 0, 0, 0, 0, 0, 0,
617: 0, -36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
618: }
619:
620: private static class Cp437Conversion implements ExtraEncoding {
621: private static IntHashtable c2b = new IntHashtable();
622:
623: public byte[] charToByte(String text, String encoding) {
624: char cc[] = text.toCharArray();
625: byte b[] = new byte[cc.length];
626: int ptr = 0;
627: int len = cc.length;
628: for (int k = 0; k < len; ++k) {
629: char c = cc[k];
630: if (c < ' ')
631: continue;
632: if (c < 128)
633: b[ptr++] = (byte) c;
634: else {
635: byte v = (byte) c2b.get(c);
636: if (v != 0)
637: b[ptr++] = v;
638: }
639: }
640: if (ptr == len)
641: return b;
642: byte b2[] = new byte[ptr];
643: System.arraycopy(b, 0, b2, 0, ptr);
644: return b2;
645: }
646:
647: public byte[] charToByte(char char1, String encoding) {
648: if (char1 < ' ')
649: return new byte[0];
650: if (char1 < 128)
651: return new byte[] { (byte) char1 };
652: else {
653: byte v = (byte) c2b.get(char1);
654: if (v != 0)
655: return new byte[] { v };
656: else
657: return new byte[0];
658: }
659: }
660:
661: public String byteToChar(byte[] b, String encoding) {
662: int len = b.length;
663: char cc[] = new char[len];
664: int ptr = 0;
665: for (int k = 0; k < len; ++k) {
666: int c = b[k] & 0xff;
667: if (c < ' ')
668: continue;
669: if (c < 128)
670: cc[ptr++] = (char) c;
671: else {
672: char v = table[c - 128];
673: cc[ptr++] = v;
674: }
675: }
676: return new String(cc, 0, ptr);
677: }
678:
679: private final static char table[] = { '\u00C7', '\u00FC',
680: '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5',
681: '\u00E7', '\u00EA', '\u00EB', '\u00E8', '\u00EF',
682: '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9',
683: '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2',
684: '\u00FB', '\u00F9', '\u00FF', '\u00D6', '\u00DC',
685: '\u00A2', '\u00A3', '\u00A5', '\u20A7', '\u0192',
686: '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1',
687: '\u00D1', '\u00AA', '\u00BA', '\u00BF', '\u2310',
688: '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB',
689: '\u00BB', '\u2591', '\u2592', '\u2593', '\u2502',
690: '\u2524', '\u2561', '\u2562', '\u2556', '\u2555',
691: '\u2563', '\u2551', '\u2557', '\u255D', '\u255C',
692: '\u255B', '\u2510', '\u2514', '\u2534', '\u252C',
693: '\u251C', '\u2500', '\u253C', '\u255E', '\u255F',
694: '\u255A', '\u2554', '\u2569', '\u2566', '\u2560',
695: '\u2550', '\u256C', '\u2567', '\u2568', '\u2564',
696: '\u2565', '\u2559', '\u2558', '\u2552', '\u2553',
697: '\u256B', '\u256A', '\u2518', '\u250C', '\u2588',
698: '\u2584', '\u258C', '\u2590', '\u2580', '\u03B1',
699: '\u00DF', '\u0393', '\u03C0', '\u03A3', '\u03C3',
700: '\u00B5', '\u03C4', '\u03A6', '\u0398', '\u03A9',
701: '\u03B4', '\u221E', '\u03C6', '\u03B5', '\u2229',
702: '\u2261', '\u00B1', '\u2265', '\u2264', '\u2320',
703: '\u2321', '\u00F7', '\u2248', '\u00B0', '\u2219',
704: '\u00B7', '\u221A', '\u207F', '\u00B2', '\u25A0',
705: '\u00A0' };
706:
707: static {
708: for (int k = 0; k < table.length; ++k)
709: c2b.put(table[k], k + 128);
710: }
711: }
712:
713: private static class SymbolConversion implements ExtraEncoding {
714:
715: private static final IntHashtable t1 = new IntHashtable();
716: private static final IntHashtable t2 = new IntHashtable();
717: private IntHashtable translation;
718:
719: SymbolConversion(boolean symbol) {
720: if (symbol)
721: translation = t1;
722: else
723: translation = t2;
724: }
725:
726: public byte[] charToByte(String text, String encoding) {
727: char cc[] = text.toCharArray();
728: byte b[] = new byte[cc.length];
729: int ptr = 0;
730: int len = cc.length;
731: for (int k = 0; k < len; ++k) {
732: char c = cc[k];
733: byte v = (byte) translation.get((int) c);
734: if (v != 0)
735: b[ptr++] = v;
736: }
737: if (ptr == len)
738: return b;
739: byte b2[] = new byte[ptr];
740: System.arraycopy(b, 0, b2, 0, ptr);
741: return b2;
742: }
743:
744: public byte[] charToByte(char char1, String encoding) {
745: byte v = (byte) translation.get((int) char1);
746: if (v != 0)
747: return new byte[] { v };
748: else
749: return new byte[0];
750: }
751:
752: public String byteToChar(byte[] b, String encoding) {
753: return null;
754: }
755:
756: private final static char table1[] = { ' ', '!', '\u2200', '#',
757: '\u2203', '%', '&', '\u220b', '(', ')', '*', '+', ',',
758: '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7',
759: '8', '9', ':', ';', '<', '=', '>', '?', '\u2245',
760: '\u0391', '\u0392', '\u03a7', '\u0394', '\u0395',
761: '\u03a6', '\u0393', '\u0397', '\u0399', '\u03d1',
762: '\u039a', '\u039b', '\u039c', '\u039d', '\u039f',
763: '\u03a0', '\u0398', '\u03a1', '\u03a3', '\u03a4',
764: '\u03a5', '\u03c2', '\u03a9', '\u039e', '\u03a8',
765: '\u0396', '[', '\u2234', ']', '\u22a5', '_', '\u0305',
766: '\u03b1', '\u03b2', '\u03c7', '\u03b4', '\u03b5',
767: '\u03d5', '\u03b3', '\u03b7', '\u03b9', '\u03c6',
768: '\u03ba', '\u03bb', '\u03bc', '\u03bd', '\u03bf',
769: '\u03c0', '\u03b8', '\u03c1', '\u03c3', '\u03c4',
770: '\u03c5', '\u03d6', '\u03c9', '\u03be', '\u03c8',
771: '\u03b6', '{', '|', '}', '~', '\0', '\0', '\0', '\0',
772: '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
773: '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
774: '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
775: '\0', '\0', '\u20ac', '\u03d2', '\u2032', '\u2264',
776: '\u2044', '\u221e', '\u0192', '\u2663', '\u2666',
777: '\u2665', '\u2660', '\u2194', '\u2190', '\u2191',
778: '\u2192', '\u2193', '\u00b0', '\u00b1', '\u2033',
779: '\u2265', '\u00d7', '\u221d', '\u2202', '\u2022',
780: '\u00f7', '\u2260', '\u2261', '\u2248', '\u2026',
781: '\u2502', '\u2500', '\u21b5', '\u2135', '\u2111',
782: '\u211c', '\u2118', '\u2297', '\u2295', '\u2205',
783: '\u2229', '\u222a', '\u2283', '\u2287', '\u2284',
784: '\u2282', '\u2286', '\u2208', '\u2209', '\u2220',
785: '\u2207', '\u00ae', '\u00a9', '\u2122', '\u220f',
786: '\u221a', '\u2022', '\u00ac', '\u2227', '\u2228',
787: '\u21d4', '\u21d0', '\u21d1', '\u21d2', '\u21d3',
788: '\u25ca', '\u2329', '\0', '\0', '\0', '\u2211',
789: '\u239b', '\u239c', '\u239d', '\u23a1', '\u23a2',
790: '\u23a3', '\u23a7', '\u23a8', '\u23a9', '\u23aa', '\0',
791: '\u232a', '\u222b', '\u2320', '\u23ae', '\u2321',
792: '\u239e', '\u239f', '\u23a0', '\u23a4', '\u23a5',
793: '\u23a6', '\u23ab', '\u23ac', '\u23ad', '\0' };
794:
795: private final static char table2[] = { '\u0020', '\u2701',
796: '\u2702', '\u2703', '\u2704', '\u260e', '\u2706',
797: '\u2707', '\u2708', '\u2709', '\u261b', '\u261e',
798: '\u270C', '\u270D', '\u270E', '\u270F', '\u2710',
799: '\u2711', '\u2712', '\u2713', '\u2714', '\u2715',
800: '\u2716', '\u2717', '\u2718', '\u2719', '\u271A',
801: '\u271B', '\u271C', '\u271D', '\u271E', '\u271F',
802: '\u2720', '\u2721', '\u2722', '\u2723', '\u2724',
803: '\u2725', '\u2726', '\u2727', '\u2605', '\u2729',
804: '\u272A', '\u272B', '\u272C', '\u272D', '\u272E',
805: '\u272F', '\u2730', '\u2731', '\u2732', '\u2733',
806: '\u2734', '\u2735', '\u2736', '\u2737', '\u2738',
807: '\u2739', '\u273A', '\u273B', '\u273C', '\u273D',
808: '\u273E', '\u273F', '\u2740', '\u2741', '\u2742',
809: '\u2743', '\u2744', '\u2745', '\u2746', '\u2747',
810: '\u2748', '\u2749', '\u274A', '\u274B', '\u25cf',
811: '\u274D', '\u25a0', '\u274F', '\u2750', '\u2751',
812: '\u2752', '\u25b2', '\u25bc', '\u25c6', '\u2756',
813: '\u25d7', '\u2758', '\u2759', '\u275A', '\u275B',
814: '\u275C', '\u275D', '\u275E', '\u0000', '\0', '\0',
815: '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
816: '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
817: '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
818: '\0', '\0', '\0', '\u0000', '\u2761', '\u2762',
819: '\u2763', '\u2764', '\u2765', '\u2766', '\u2767',
820: '\u2663', '\u2666', '\u2665', '\u2660', '\u2460',
821: '\u2461', '\u2462', '\u2463', '\u2464', '\u2465',
822: '\u2466', '\u2467', '\u2468', '\u2469', '\u2776',
823: '\u2777', '\u2778', '\u2779', '\u277A', '\u277B',
824: '\u277C', '\u277D', '\u277E', '\u277F', '\u2780',
825: '\u2781', '\u2782', '\u2783', '\u2784', '\u2785',
826: '\u2786', '\u2787', '\u2788', '\u2789', '\u278A',
827: '\u278B', '\u278C', '\u278D', '\u278E', '\u278F',
828: '\u2790', '\u2791', '\u2792', '\u2793', '\u2794',
829: '\u2192', '\u2194', '\u2195', '\u2798', '\u2799',
830: '\u279A', '\u279B', '\u279C', '\u279D', '\u279E',
831: '\u279F', '\u27A0', '\u27A1', '\u27A2', '\u27A3',
832: '\u27A4', '\u27A5', '\u27A6', '\u27A7', '\u27A8',
833: '\u27A9', '\u27AA', '\u27AB', '\u27AC', '\u27AD',
834: '\u27AE', '\u27AF', '\u0000', '\u27B1', '\u27B2',
835: '\u27B3', '\u27B4', '\u27B5', '\u27B6', '\u27B7',
836: '\u27B8', '\u27B9', '\u27BA', '\u27BB', '\u27BC',
837: '\u27BD', '\u27BE', '\u0000' };
838:
839: static {
840: for (int k = 0; k < table1.length; ++k) {
841: int v = (int) table1[k];
842: if (v != 0)
843: t1.put(v, k + 32);
844: }
845: for (int k = 0; k < table2.length; ++k) {
846: int v = (int) table2[k];
847: if (v != 0)
848: t2.put(v, k + 32);
849: }
850: }
851: }
852:
853: private static class SymbolTTConversion implements ExtraEncoding {
854:
855: public byte[] charToByte(char char1, String encoding) {
856: if ((char1 & 0xff00) == 0 || (char1 & 0xff00) == 0xf000)
857: return new byte[] { (byte) char1 };
858: else
859: return new byte[0];
860: }
861:
862: public byte[] charToByte(String text, String encoding) {
863: char ch[] = text.toCharArray();
864: byte b[] = new byte[ch.length];
865: int ptr = 0;
866: int len = ch.length;
867: for (int k = 0; k < len; ++k) {
868: char c = ch[k];
869: if ((c & 0xff00) == 0 || (c & 0xff00) == 0xf000)
870: b[ptr++] = (byte) c;
871: }
872: if (ptr == len)
873: return b;
874: byte b2[] = new byte[ptr];
875: System.arraycopy(b, 0, b2, 0, ptr);
876: return b2;
877: }
878:
879: public String byteToChar(byte[] b, String encoding) {
880: return null;
881: }
882:
883: }
884: }
|