KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > pdf > ByteBuffer


1 /*
2  * $Id: ByteBuffer.java 2382 2006-09-15 23:37:38Z xlv $
3  * $Name$
4  *
5  * Copyright 2000, 2001, 2002 by Paulo Soares.
6  *
7  * The contents of this file are subject to the Mozilla Public License Version 1.1
8  * (the "License"); you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the License.
14  *
15  * The Original Code is 'iText, a free JAVA-PDF library'.
16  *
17  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
18  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
19  * All Rights Reserved.
20  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
21  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
22  *
23  * Contributor(s): all the names of the contributors are added in the source code
24  * where applicable.
25  *
26  * Alternatively, the contents of this file may be used under the terms of the
27  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
28  * provisions of LGPL are applicable instead of those above. If you wish to
29  * allow use of your version of this file only under the terms of the LGPL
30  * License and not to allow others to use your version of this file under
31  * the MPL, indicate your decision by deleting the provisions above and
32  * replace them with the notice and other provisions required by the LGPL.
33  * If you do not delete the provisions above, a recipient may use your version
34  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
35  *
36  * This library is free software; you can redistribute it and/or modify it
37  * under the terms of the MPL as stated above or under the terms of the GNU
38  * Library General Public License as published by the Free Software Foundation;
39  * either version 2 of the License, or any later version.
40  *
41  * This library is distributed in the hope that it will be useful, but WITHOUT
42  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
43  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
44  * details.
45  *
46  * If you didn't download this code from the following link, you should check if
47  * you aren't using an obsolete version:
48  * http://www.lowagie.com/iText/
49  */

50
51 package com.lowagie.text.pdf;
52 import java.io.IOException JavaDoc;
53 import java.io.OutputStream JavaDoc;
54 import java.io.UnsupportedEncodingException JavaDoc;
55 import java.text.DecimalFormat JavaDoc;
56 import java.text.DecimalFormatSymbols JavaDoc;
57 import java.util.Locale JavaDoc;
58
59 import com.lowagie.text.DocWriter;
60
61 /**
62  * Acts like a <CODE>StringBuffer</CODE> but works with <CODE>byte</CODE> arrays.
63  * Floating point is converted to a format suitable to the PDF.
64  * @author Paulo Soares (psoares@consiste.pt)
65  */

66
67 public class ByteBuffer extends OutputStream JavaDoc {
68     /** The count of bytes in the buffer. */
69     protected int count;
70     
71     /** The buffer where the bytes are stored. */
72     protected byte buf[];
73     
74     private static int byteCacheSize = 0;
75     
76     private static byte[][] byteCache = new byte[byteCacheSize][];
77     public static final byte ZERO = (byte)'0';
78     private static final char[] chars = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
79     private static final byte[] bytes = new byte[] {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102};
80     /**
81      * If <CODE>true</CODE> always output floating point numbers with 6 decimal digits.
82      * If <CODE>false</CODE> uses the faster, although less precise, representation.
83      */

84     public static boolean HIGH_PRECISION = false;
85     private static final DecimalFormatSymbols JavaDoc dfs = new DecimalFormatSymbols JavaDoc(Locale.US);
86     
87     /** Creates new ByteBuffer with capacity 128 */
88     public ByteBuffer() {
89         this(128);
90     }
91     
92     /**
93      * Creates a byte buffer with a certain capacity.
94      * @param size the initial capacity
95      */

96     public ByteBuffer(int size) {
97         if (size < 1)
98             size = 128;
99         buf = new byte[size];
100     }
101     
102     /**
103      * Sets the cache size.
104      * <P>
105      * This can only be used to increment the size.
106      * If the size that is passed through is smaller than the current size, nothing happens.
107      *
108      * @param size the size of the cache
109      */

110     
111     public static void setCacheSize(int size) {
112         if (size > 3276700) size = 3276700;
113         if (size <= byteCacheSize) return;
114         byte[][] tmpCache = new byte[size][];
115         System.arraycopy(byteCache, 0, tmpCache, 0, byteCacheSize);
116         byteCache = tmpCache;
117         byteCacheSize = size;
118     }
119     
120     /**
121      * You can fill the cache in advance if you want to.
122      *
123      * @param decimals
124      */

125     
126     public static void fillCache(int decimals) {
127         int step = 1;
128         switch(decimals) {
129             case 0:
130                 step = 100;
131                 break;
132             case 1:
133                 step = 10;
134                 break;
135         }
136         for (int i = 1; i < byteCacheSize; i += step) {
137             if (byteCache[i] != null) continue;
138             byteCache[i] = convertToBytes(i);
139         }
140     }
141     
142     /**
143      * Converts an double (multiplied by 100 and cast to an int) into an array of bytes.
144      *
145      * @param i the int
146      * @return a bytearray
147      */

148     
149     private static byte[] convertToBytes(int i) {
150         int size = (int)Math.floor(Math.log(i) / Math.log(10));
151         if (i % 100 != 0) {
152             size += 2;
153         }
154         if (i % 10 != 0) {
155             size++;
156         }
157         if (i < 100) {
158             size++;
159             if (i < 10) {
160                 size++;
161             }
162         }
163         size--;
164         byte[] cache = new byte[size];
165         size --;
166         if (i < 100) {
167             cache[0] = (byte)'0';
168         }
169         if (i % 10 != 0) {
170             cache[size--] = bytes[i % 10];
171         }
172         if (i % 100 != 0) {
173             cache[size--] = bytes[(i / 10) % 10];
174             cache[size--] = (byte)'.';
175         }
176         size = (int)Math.floor(Math.log(i) / Math.log(10)) - 1;
177         int add = 0;
178         while (add < size) {
179             cache[add] = bytes[(i / (int)Math.pow(10, size - add + 1)) % 10];
180             add++;
181         }
182         return cache;
183     }
184     
185     /**
186      * Appends an <CODE>int</CODE>. The size of the array will grow by one.
187      * @param b the int to be appended
188      * @return a reference to this <CODE>ByteBuffer</CODE> object
189      */

190     public ByteBuffer append_i(int b) {
191         int newcount = count + 1;
192         if (newcount > buf.length) {
193             byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
194             System.arraycopy(buf, 0, newbuf, 0, count);
195             buf = newbuf;
196         }
197         buf[count] = (byte)b;
198         count = newcount;
199         return this;
200     }
201     
202     /**
203      * Appends the subarray of the <CODE>byte</CODE> array. The buffer will grow by
204      * <CODE>len</CODE> bytes.
205      * @param b the array to be appended
206      * @param off the offset to the start of the array
207      * @param len the length of bytes to append
208      * @return a reference to this <CODE>ByteBuffer</CODE> object
209      */

210     public ByteBuffer append(byte b[], int off, int len) {
211         if ((off < 0) || (off > b.length) || (len < 0) ||
212         ((off + len) > b.length) || ((off + len) < 0) || len == 0)
213             return this;
214         int newcount = count + len;
215         if (newcount > buf.length) {
216             byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
217             System.arraycopy(buf, 0, newbuf, 0, count);
218             buf = newbuf;
219         }
220         System.arraycopy(b, off, buf, count, len);
221         count = newcount;
222         return this;
223     }
224     
225     /**
226      * Appends an array of bytes.
227      * @param b the array to be appended
228      * @return a reference to this <CODE>ByteBuffer</CODE> object
229      */

230     public ByteBuffer append(byte b[]) {
231         return append(b, 0, b.length);
232     }
233     
234     /**
235      * Appends a <CODE>String</CODE> to the buffer. The <CODE>String</CODE> is
236      * converted according to the encoding ISO-8859-1.
237      * @param str the <CODE>String</CODE> to be appended
238      * @return a reference to this <CODE>ByteBuffer</CODE> object
239      */

240     public ByteBuffer append(String JavaDoc str) {
241         if (str != null)
242             return append(DocWriter.getISOBytes(str));
243         return this;
244     }
245     
246     /**
247      * Appends a <CODE>char</CODE> to the buffer. The <CODE>char</CODE> is
248      * converted according to the encoding ISO-8859-1.
249      * @param c the <CODE>char</CODE> to be appended
250      * @return a reference to this <CODE>ByteBuffer</CODE> object
251      */

252     public ByteBuffer append(char c) {
253         return append_i(c);
254     }
255     
256     /**
257      * Appends another <CODE>ByteBuffer</CODE> to this buffer.
258      * @param buf the <CODE>ByteBuffer</CODE> to be appended
259      * @return a reference to this <CODE>ByteBuffer</CODE> object
260      */

261     public ByteBuffer append(ByteBuffer buf) {
262         return append(buf.buf, 0, buf.count);
263     }
264     
265     /**
266      * Appends the string representation of an <CODE>int</CODE>.
267      * @param i the <CODE>int</CODE> to be appended
268      * @return a reference to this <CODE>ByteBuffer</CODE> object
269      */

270     public ByteBuffer append(int i) {
271         return append((double)i);
272     }
273     
274     public ByteBuffer append(byte b) {
275         return append_i(b);
276     }
277     
278     public ByteBuffer appendHex(byte b) {
279         append(bytes[(b >> 4) & 0x0f]);
280         return append(bytes[b & 0x0f]);
281     }
282     
283     /**
284      * Appends a string representation of a <CODE>float</CODE> according
285      * to the Pdf conventions.
286      * @param i the <CODE>float</CODE> to be appended
287      * @return a reference to this <CODE>ByteBuffer</CODE> object
288      */

289     public ByteBuffer append(float i) {
290         return append((double)i);
291     }
292     
293     /**
294      * Appends a string representation of a <CODE>double</CODE> according
295      * to the Pdf conventions.
296      * @param d the <CODE>double</CODE> to be appended
297      * @return a reference to this <CODE>ByteBuffer</CODE> object
298      */

299     public ByteBuffer append(double d) {
300         append(formatDouble(d, this));
301         return this;
302     }
303     
304     /**
305      * Outputs a <CODE>double</CODE> into a format suitable for the PDF.
306      * @param d a double
307      * @return the <CODE>String</CODE> representation of the <CODE>double</CODE>
308      */

309     public static String JavaDoc formatDouble(double d) {
310         return formatDouble(d, null);
311     }
312     
313     /**
314      * Outputs a <CODE>double</CODE> into a format suitable for the PDF.
315      * @param d a double
316      * @param buf a ByteBuffer
317      * @return the <CODE>String</CODE> representation of the <CODE>double</CODE> if
318      * <CODE>buf</CODE> is <CODE>null</CODE>. If <CODE>buf</CODE> is <B>not</B> <CODE>null</CODE>,
319      * then the double is appended directly to the buffer and this methods returns <CODE>null</CODE>.
320      */

321     public static String JavaDoc formatDouble(double d, ByteBuffer buf) {
322         if (HIGH_PRECISION) {
323             DecimalFormat JavaDoc dn = new DecimalFormat JavaDoc("0.######", dfs);
324             String JavaDoc sform = dn.format(d);
325             if (buf == null)
326                 return sform;
327             else {
328                 buf.append(sform);
329                 return null;
330             }
331         }
332         boolean negative = false;
333         if (Math.abs(d) < 0.000015) {
334             if (buf != null) {
335                 buf.append(ZERO);
336                 return null;
337             } else {
338                 return "0";
339             }
340         }
341         if (d < 0) {
342             negative = true;
343             d = -d;
344         }
345         if (d < 1.0) {
346             d += 0.000005;
347             if (d >= 1) {
348                 if (negative) {
349                     if (buf != null) {
350                         buf.append((byte)'-');
351                         buf.append((byte)'1');
352                         return null;
353                     } else {
354                         return "-1";
355                     }
356                 } else {
357                     if (buf != null) {
358                         buf.append((byte)'1');
359                         return null;
360                     } else {
361                         return "1";
362                     }
363                 }
364             }
365             if (buf != null) {
366                 int v = (int) (d * 100000);
367                 
368                 if (negative) buf.append((byte)'-');
369                 buf.append((byte)'0');
370                 buf.append((byte)'.');
371                 
372                 buf.append( (byte)(v / 10000 + ZERO) );
373                 if (v % 10000 != 0) {
374                     buf.append( (byte)((v / 1000) % 10 + ZERO) );
375                     if (v % 1000 != 0) {
376                         buf.append( (byte)((v / 100) % 10 + ZERO) );
377                         if (v % 100 != 0) {
378                             buf.append((byte)((v / 10) % 10 + ZERO) );
379                             if (v % 10 != 0) {
380                                 buf.append((byte)((v) % 10 + ZERO) );
381                             }
382                         }
383                     }
384                 }
385                 return null;
386             } else {
387                 int x = 100000;
388                 int v = (int) (d * x);
389                 
390                 StringBuffer JavaDoc res = new StringBuffer JavaDoc();
391                 if (negative) res.append('-');
392                 res.append("0.");
393                 
394                 while( v < x/10 ) {
395                     res.append('0');
396                     x /= 10;
397                 }
398                 res.append(v);
399                 int cut = res.length() - 1;
400                 while (res.charAt(cut) == '0') {
401                     --cut;
402                 }
403                 res.setLength(cut + 1);
404                 return res.toString();
405             }
406         } else if (d <= 32767) {
407             d += 0.005;
408             int v = (int) (d * 100);
409             
410             if (v < byteCacheSize && byteCache[v] != null) {
411                 if (buf != null) {
412                     if (negative) buf.append((byte)'-');
413                     buf.append(byteCache[v]);
414                     return null;
415                 } else {
416                     String JavaDoc tmp = PdfEncodings.convertToString(byteCache[v], null);
417                     if (negative) tmp = "-" + tmp;
418                     return tmp;
419                 }
420             }
421             if (buf != null) {
422                 if (v < byteCacheSize) {
423                     //create the cachebyte[]
424
byte[] cache;
425                     int size = 0;
426                     if (v >= 1000000) {
427                         //the original number is >=10000, we need 5 more bytes
428
size += 5;
429                     } else if (v >= 100000) {
430                         //the original number is >=1000, we need 4 more bytes
431
size += 4;
432                     } else if (v >= 10000) {
433                         //the original number is >=100, we need 3 more bytes
434
size += 3;
435                     } else if (v >= 1000) {
436                         //the original number is >=10, we need 2 more bytes
437
size += 2;
438                     } else if (v >= 100) {
439                         //the original number is >=1, we need 1 more bytes
440
size += 1;
441                     }
442                     
443                     //now we must check if we have a decimal number
444
if (v % 100 != 0) {
445                         //yes, do not forget the "."
446
size += 2;
447                     }
448                     if (v % 10 != 0) {
449                         size++;
450                     }
451                     cache = new byte[size];
452                     int add = 0;
453                     if (v >= 1000000) {
454                         cache[add++] = bytes[(v / 1000000)];
455                     }
456                     if (v >= 100000) {
457                         cache[add++] = bytes[(v / 100000) % 10];
458                     }
459                     if (v >= 10000) {
460                         cache[add++] = bytes[(v / 10000) % 10];
461                     }
462                     if (v >= 1000) {
463                         cache[add++] = bytes[(v / 1000) % 10];
464                     }
465                     if (v >= 100) {
466                         cache[add++] = bytes[(v / 100) % 10];
467                     }
468                     
469                     if (v % 100 != 0) {
470                         cache[add++] = (byte)'.';
471                         cache[add++] = bytes[(v / 10) % 10];
472                         if (v % 10 != 0) {
473                             cache[add++] = bytes[v % 10];
474                         }
475                     }
476                     byteCache[v] = cache;
477                 }
478                 
479                 if (negative) buf.append((byte)'-');
480                 if (v >= 1000000) {
481                     buf.append( bytes[(v / 1000000)] );
482                 }
483                 if (v >= 100000) {
484                     buf.append( bytes[(v / 100000) % 10] );
485                 }
486                 if (v >= 10000) {
487                     buf.append( bytes[(v / 10000) % 10] );
488                 }
489                 if (v >= 1000) {
490                     buf.append( bytes[(v / 1000) % 10] );
491                 }
492                 if (v >= 100) {
493                     buf.append( bytes[(v / 100) % 10] );
494                 }
495                 
496                 if (v % 100 != 0) {
497                     buf.append((byte)'.');
498                     buf.append( bytes[(v / 10) % 10] );
499                     if (v % 10 != 0) {
500                         buf.append( bytes[v % 10] );
501                     }
502                 }
503                 return null;
504             } else {
505                 StringBuffer JavaDoc res = new StringBuffer JavaDoc();
506                 if (negative) res.append('-');
507                 if (v >= 1000000) {
508                     res.append( chars[(v / 1000000)] );
509                 }
510                 if (v >= 100000) {
511                     res.append( chars[(v / 100000) % 10] );
512                 }
513                 if (v >= 10000) {
514                     res.append( chars[(v / 10000) % 10] );
515                 }
516                 if (v >= 1000) {
517                     res.append( chars[(v / 1000) % 10] );
518                 }
519                 if (v >= 100) {
520                     res.append( chars[(v / 100) % 10] );
521                 }
522                 
523                 if (v % 100 != 0) {
524                     res.append('.');
525                     res.append( chars[(v / 10) % 10] );
526                     if (v % 10 != 0) {
527                         res.append( chars[v % 10] );
528                     }
529                 }
530                 return res.toString();
531             }
532         } else {
533             StringBuffer JavaDoc res = new StringBuffer JavaDoc();
534             if (negative) res.append('-');
535             d += 0.5;
536             long v = (long) d;
537             return res.append(v).toString();
538         }
539     }
540     
541     /**
542      * Sets the size to zero.
543      */

544     public void reset() {
545         count = 0;
546     }
547     
548     /**
549      * Creates a newly allocated byte array. Its size is the current
550      * size of this output stream and the valid contents of the buffer
551      * have been copied into it.
552      *
553      * @return the current contents of this output stream, as a byte array.
554      */

555     public byte[] toByteArray() {
556         byte newbuf[] = new byte[count];
557         System.arraycopy(buf, 0, newbuf, 0, count);
558         return newbuf;
559     }
560     
561     /**
562      * Returns the current size of the buffer.
563      *
564      * @return the value of the <code>count</code> field, which is the number of valid bytes in this byte buffer.
565      */

566     public int size() {
567         return count;
568     }
569     
570     public void setSize(int size) {
571         if (size > count || size < 0)
572             throw new IndexOutOfBoundsException JavaDoc("The new size must be positive and <= of the current size");
573         count = size;
574     }
575     
576     /**
577      * Converts the buffer's contents into a string, translating bytes into
578      * characters according to the platform's default character encoding.
579      *
580      * @return String translated from the buffer's contents.
581      */

582     public String JavaDoc toString() {
583         return new String JavaDoc(buf, 0, count);
584     }
585     
586     /**
587      * Converts the buffer's contents into a string, translating bytes into
588      * characters according to the specified character encoding.
589      *
590      * @param enc a character-encoding name.
591      * @return String translated from the buffer's contents.
592      * @throws UnsupportedEncodingException
593      * If the named encoding is not supported.
594      */

595     public String JavaDoc toString(String JavaDoc enc) throws UnsupportedEncodingException JavaDoc {
596         return new String JavaDoc(buf, 0, count, enc);
597     }
598     
599     /**
600      * Writes the complete contents of this byte buffer output to
601      * the specified output stream argument, as if by calling the output
602      * stream's write method using <code>out.write(buf, 0, count)</code>.
603      *
604      * @param out the output stream to which to write the data.
605      * @exception IOException if an I/O error occurs.
606      */

607     public void writeTo(OutputStream JavaDoc out) throws IOException JavaDoc {
608         out.write(buf, 0, count);
609     }
610     
611     public void write(int b) throws IOException JavaDoc {
612         append((byte)b);
613     }
614     
615     public void write(byte[] b, int off, int len) {
616         append(b, off, len);
617     }
618     
619     public byte[] getBuffer() {
620         return buf;
621     }
622 }
Popular Tags