All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aowagie.text.pdf.ByteBuffer Maven / Gradle / Ivy

/*
 * $Id: ByteBuffer.java 3373 2008-05-12 16:21:24Z xlv $
 *
 * Copyright 2000, 2001, 2002 by Paulo Soares.
 *
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the License.
 *
 * The Original Code is 'iText, a free JAVA-PDF library'.
 *
 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
 * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
 * All Rights Reserved.
 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
 * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
 *
 * Contributor(s): all the names of the contributors are added in the source code
 * where applicable.
 *
 * Alternatively, the contents of this file may be used under the terms of the
 * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
 * provisions of LGPL are applicable instead of those above.  If you wish to
 * allow use of your version of this file only under the terms of the LGPL
 * License and not to allow others to use your version of this file under
 * the MPL, indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by the LGPL.
 * If you do not delete the provisions above, a recipient may use your version
 * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the MPL as stated above or under the terms of the GNU
 * Library General Public License as published by the Free Software Foundation;
 * either version 2 of the License, or any later version.
 *
 * This library 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 Library general Public License for more
 * details.
 *
 * If you didn't download this code from the following link, you should check if
 * you aren't using an obsolete version:
 * http://www.lowagie.com/iText/
 */

package com.aowagie.text.pdf;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;

import com.aowagie.text.DocWriter;

/**
 * Acts like a StringBuffer but works with byte arrays.
 * Floating point is converted to a format suitable to the PDF.
 * @author Paulo Soares ([email protected])
 */

public class ByteBuffer extends OutputStream {
    /** The count of bytes in the buffer. */
    private int count;

    /** The buffer where the bytes are stored. */
    private byte buf[];

    private static int byteCacheSize = 0;

    private static byte[][] byteCache = new byte[byteCacheSize][];
    private static final byte ZERO = (byte)'0';
    private static final char[] chars = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    private static final byte[] bytes = new byte[] {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102};
    /**
     * If true always output floating point numbers with 6 decimal digits.
     * If false uses the faster, although less precise, representation.
     */
    private static boolean HIGH_PRECISION = false;
    private static final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);

    /** Creates new ByteBuffer with capacity 128 */
    public ByteBuffer() {
        this(128);
    }

    /**
     * Creates a byte buffer with a certain capacity.
     * @param size the initial capacity
     */
    public ByteBuffer(int size) {
        if (size < 1) {
			size = 128;
		}
        this.buf = new byte[size];
    }





    /**
     * Converts an double (multiplied by 100 and cast to an int) into an array of bytes.
     *
     * @param   i   the int
     * @return  a byte array
     */

    private static byte[] convertToBytes(final int i) {
        int size = (int)Math.floor(Math.log(i) / Math.log(10));
        if (i % 100 != 0) {
            size += 2;
        }
        if (i % 10 != 0) {
            size++;
        }
        if (i < 100) {
            size++;
            if (i < 10) {
                size++;
            }
        }
        size--;
        final byte[] cache = new byte[size];
        size --;
        if (i < 100) {
            cache[0] = (byte)'0';
        }
        if (i % 10 != 0) {
            cache[size--] = bytes[i % 10];
        }
        if (i % 100 != 0) {
            cache[size--] = bytes[i / 10 % 10];
            cache[size--] = (byte)'.';
        }
        size = (int)Math.floor(Math.log(i) / Math.log(10)) - 1;
        int add = 0;
        while (add < size) {
            cache[add] = bytes[i / (int)Math.pow(10, size - add + 1) % 10];
            add++;
        }
        return cache;
    }

    /**
     * Appends an int. The size of the array will grow by one.
     * @param b the int to be appended
     * @return a reference to this ByteBuffer object
     */
    public ByteBuffer append_i(final int b) {
        final int newcount = this.count + 1;
        if (newcount > this.buf.length) {
            final byte newbuf[] = new byte[Math.max(this.buf.length << 1, newcount)];
            System.arraycopy(this.buf, 0, newbuf, 0, this.count);
            this.buf = newbuf;
        }
        this.buf[this.count] = (byte)b;
        this.count = newcount;
        return this;
    }

    /**
     * Appends the subarray of the byte array. The buffer will grow by
     * len bytes.
     * @param b the array to be appended
     * @param off the offset to the start of the array
     * @param len the length of bytes to append
     * @return a reference to this ByteBuffer object
     */
    ByteBuffer append(final byte b[], final int off, final int len) {
        if (off < 0 || off > b.length || len < 0 ||
        off + len > b.length || off + len < 0 || len == 0) {
			return this;
		}
        final int newcount = this.count + len;
        if (newcount > this.buf.length) {
            final byte newbuf[] = new byte[Math.max(this.buf.length << 1, newcount)];
            System.arraycopy(this.buf, 0, newbuf, 0, this.count);
            this.buf = newbuf;
        }
        System.arraycopy(b, off, this.buf, this.count, len);
        this.count = newcount;
        return this;
    }

    /**
     * Appends an array of bytes.
     * @param b the array to be appended
     * @return a reference to this ByteBuffer object
     */
    ByteBuffer append(final byte b[]) {
        return append(b, 0, b.length);
    }

    /**
     * Appends a String to the buffer. The String is
     * converted according to the encoding ISO-8859-1.
     * @param str the String to be appended
     * @return a reference to this ByteBuffer object
     */
    ByteBuffer append(final String str) {
        if (str != null) {
			return append(DocWriter.getISOBytes(str));
		}
        return this;
    }

    /**
     * Appends a char to the buffer. The char is
     * converted according to the encoding ISO-8859-1.
     * @param c the char to be appended
     * @return a reference to this ByteBuffer object
     */
    ByteBuffer append(final char c) {
        return append_i(c);
    }

    /**
     * Appends another ByteBuffer to this buffer.
     * @param buf the ByteBuffer to be appended
     * @return a reference to this ByteBuffer object
     */
    ByteBuffer append(final ByteBuffer buf) {
        return append(buf.buf, 0, buf.count);
    }

    /**
     * Appends the string representation of an int.
     * @param i the int to be appended
     * @return a reference to this ByteBuffer object
     */
    ByteBuffer append(final int i) {
        return append((double)i);
    }

    public ByteBuffer append(final byte b) {
        return append_i(b);
    }

    ByteBuffer appendHex(final byte b) {
        append(bytes[b >> 4 & 0x0f]);
        return append(bytes[b & 0x0f]);
    }

    /**
     * Appends a string representation of a float according
     * to the Pdf conventions.
     * @param i the float to be appended
     * @return a reference to this ByteBuffer object
     */
    ByteBuffer append(final float i) {
        return append((double)i);
    }

    /**
     * Appends a string representation of a double according
     * to the Pdf conventions.
     * @param d the double to be appended
     * @return a reference to this ByteBuffer object
     */
    private ByteBuffer append(final double d) {
        append(formatDouble(d, this));
        return this;
    }

    /**
     * Outputs a double into a format suitable for the PDF.
     * @param d a double
     * @return the String representation of the double
     */
    static String formatDouble(final double d) {
        return formatDouble(d, null);
    }

    /**
     * Outputs a double into a format suitable for the PDF.
     * @param d a double
     * @param buf a ByteBuffer
     * @return the String representation of the double if
     * buf is null. If buf is not null,
     * then the double is appended directly to the buffer and this methods returns null.
     */
    private static String formatDouble(double d, final ByteBuffer buf) {
        if (HIGH_PRECISION) {
            final DecimalFormat dn = new DecimalFormat("0.######", dfs);
            final String sform = dn.format(d);
            if (buf == null) {
				return sform;
			} else {
                buf.append(sform);
                return null;
            }
        }
        boolean negative = false;
        if (Math.abs(d) < 0.000015) {
            if (buf != null) {
                buf.append(ZERO);
                return null;
            } else {
                return "0";
            }
        }
        if (d < 0) {
            negative = true;
            d = -d;
        }
        if (d < 1.0) {
            d += 0.000005;
            if (d >= 1) {
                if (negative) {
                    if (buf != null) {
                        buf.append((byte)'-');
                        buf.append((byte)'1');
                        return null;
                    } else {
                        return "-1";
                    }
                } else {
                    if (buf != null) {
                        buf.append((byte)'1');
                        return null;
                    } else {
                        return "1";
                    }
                }
            }
            if (buf != null) {
                final int v = (int) (d * 100000);

                if (negative) {
					buf.append((byte)'-');
				}
                buf.append((byte)'0');
                buf.append((byte)'.');

                buf.append( (byte)(v / 10000 + ZERO) );
                if (v % 10000 != 0) {
                    buf.append( (byte)(v / 1000 % 10 + ZERO) );
                    if (v % 1000 != 0) {
                        buf.append( (byte)(v / 100 % 10 + ZERO) );
                        if (v % 100 != 0) {
                            buf.append((byte)(v / 10 % 10 + ZERO) );
                            if (v % 10 != 0) {
                                buf.append((byte)(v % 10 + ZERO) );
                            }
                        }
                    }
                }
                return null;
            } else {
                int x = 100000;
                final int v = (int) (d * x);

                final StringBuffer res = new StringBuffer();
                if (negative) {
					res.append('-');
				}
                res.append("0.");

                while( v < x/10 ) {
                    res.append('0');
                    x /= 10;
                }
                res.append(v);
                int cut = res.length() - 1;
                while (res.charAt(cut) == '0') {
                    --cut;
                }
                res.setLength(cut + 1);
                return res.toString();
            }
        } else if (d <= 32767) {
            d += 0.005;
            final int v = (int) (d * 100);

            if (v < byteCacheSize && byteCache[v] != null) {
                if (buf != null) {
                    if (negative) {
						buf.append((byte)'-');
					}
                    buf.append(byteCache[v]);
                    return null;
                } else {
                    String tmp = PdfEncodings.convertToString(byteCache[v], null);
                    if (negative) {
						tmp = "-" + tmp;
					}
                    return tmp;
                }
            }
            if (buf != null) {
                if (v < byteCacheSize) {
                    //create the cachebyte[]
                    byte[] cache;
                    int size = 0;
                    if (v >= 1000000) {
                        //the original number is >=10000, we need 5 more bytes
                        size += 5;
                    } else if (v >= 100000) {
                        //the original number is >=1000, we need 4 more bytes
                        size += 4;
                    } else if (v >= 10000) {
                        //the original number is >=100, we need 3 more bytes
                        size += 3;
                    } else if (v >= 1000) {
                        //the original number is >=10, we need 2 more bytes
                        size += 2;
                    } else if (v >= 100) {
                        //the original number is >=1, we need 1 more bytes
                        size += 1;
                    }

                    //now we must check if we have a decimal number
                    if (v % 100 != 0) {
                        //yes, do not forget the "."
                        size += 2;
                    }
                    if (v % 10 != 0) {
                        size++;
                    }
                    cache = new byte[size];
                    int add = 0;
                    if (v >= 1000000) {
                        cache[add++] = bytes[v / 1000000];
                    }
                    if (v >= 100000) {
                        cache[add++] = bytes[v / 100000 % 10];
                    }
                    if (v >= 10000) {
                        cache[add++] = bytes[v / 10000 % 10];
                    }
                    if (v >= 1000) {
                        cache[add++] = bytes[v / 1000 % 10];
                    }
                    if (v >= 100) {
                        cache[add++] = bytes[v / 100 % 10];
                    }

                    if (v % 100 != 0) {
                        cache[add++] = (byte)'.';
                        cache[add++] = bytes[v / 10 % 10];
                        if (v % 10 != 0) {
                            cache[add++] = bytes[v % 10];
                        }
                    }
                    byteCache[v] = cache;
                }

                if (negative) {
					buf.append((byte)'-');
				}
                if (v >= 1000000) {
                    buf.append( bytes[v / 1000000] );
                }
                if (v >= 100000) {
                    buf.append( bytes[v / 100000 % 10] );
                }
                if (v >= 10000) {
                    buf.append( bytes[v / 10000 % 10] );
                }
                if (v >= 1000) {
                    buf.append( bytes[v / 1000 % 10] );
                }
                if (v >= 100) {
                    buf.append( bytes[v / 100 % 10] );
                }

                if (v % 100 != 0) {
                    buf.append((byte)'.');
                    buf.append( bytes[v / 10 % 10] );
                    if (v % 10 != 0) {
                        buf.append( bytes[v % 10] );
                    }
                }
                return null;
            } else {
                final StringBuffer res = new StringBuffer();
                if (negative) {
					res.append('-');
				}
                if (v >= 1000000) {
                    res.append( chars[v / 1000000] );
                }
                if (v >= 100000) {
                    res.append( chars[v / 100000 % 10] );
                }
                if (v >= 10000) {
                    res.append( chars[v / 10000 % 10] );
                }
                if (v >= 1000) {
                    res.append( chars[v / 1000 % 10] );
                }
                if (v >= 100) {
                    res.append( chars[v / 100 % 10] );
                }

                if (v % 100 != 0) {
                    res.append('.');
                    res.append( chars[v / 10 % 10] );
                    if (v % 10 != 0) {
                        res.append( chars[v % 10] );
                    }
                }
                return res.toString();
            }
        } else {
            final StringBuffer res = new StringBuffer();
            if (negative) {
				res.append('-');
			}
            d += 0.5;
            final long v = (long) d;
            return res.append(v).toString();
        }
    }

    /**
     * Sets the size to zero.
     */
    void reset() {
        this.count = 0;
    }

    /**
     * Creates a newly allocated byte array. Its size is the current
     * size of this output stream and the valid contents of the buffer
     * have been copied into it.
     *
     * @return  the current contents of this output stream, as a byte array.
     */
    public byte[] toByteArray() {
        final byte newbuf[] = new byte[this.count];
        System.arraycopy(this.buf, 0, newbuf, 0, this.count);
        return newbuf;
    }

    /**
     * Returns the current size of the buffer.
     *
     * @return the value of the count field, which is the number of valid bytes in this byte buffer.
     */
    int size() {
        return this.count;
    }

    public void setSize(final int size) {
        if (size > this.count || size < 0) {
			throw new IndexOutOfBoundsException("The new size must be positive and <= of the current size");
		}
        this.count = size;
    }

    /**
     * Converts the buffer's contents into a string, translating bytes into
     * characters according to the platform's default character encoding.
     *
     * @return String translated from the buffer's contents.
     */
    @Override
	public String toString() {
        return new String(this.buf, 0, this.count);
    }



    /**
     * Writes the complete contents of this byte buffer output to
     * the specified output stream argument, as if by calling the output
     * stream's write method using out.write(buf, 0, count).
     *
     * @param      out   the output stream to which to write the data.
     * @exception  IOException  if an I/O error occurs.
     */
    void writeTo(final OutputStream out) throws IOException {
        out.write(this.buf, 0, this.count);
    }

    @Override
	public void write(final int b) throws IOException {
        append((byte)b);
    }

    @Override
	public void write(final byte[] b, final int off, final int len) {
        append(b, off, len);
    }

    public byte[] getBuffer() {
        return this.buf;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy