001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.commons.lang;
020
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.OutputStream;
024import java.io.UnsupportedEncodingException;
025
026
027/**
028 * class to handle characters, similar to StringBuffer, but dont copy big blocks of char arrays.
029 */
030public class ByteBuffer {
031
032        private final static int BLOCK_LENGTH = 1024;
033        private byte buffer[];
034        private int pos=0;
035        private int length=0;
036        private final Entity root=new Entity(null);
037        private Entity curr=root;
038        private final String charset;
039        
040        /**
041         * default constructor
042         */
043        public ByteBuffer(String charset) {
044                this(charset,BLOCK_LENGTH);
045        }
046
047        /**
048         * constructor with size of the buffer
049         * @param size
050         */
051        public ByteBuffer(String charset,int size) {
052                buffer = new byte[size];
053                this.charset=charset;
054        }
055        
056        public void append(char c) throws IOException {
057                append(new String(new char[]{c}));
058        }
059        
060        /**
061        * method to appennd a charr array to the buffer
062        * @param c char array to append
063         * @throws IOException 
064        */
065        public void append(char c[]) throws IOException {
066                append(new String(c));
067        }
068        
069        public void append(byte c[]) {
070                int maxlength=buffer.length-pos;
071                if(c.length<maxlength) {
072                        System.arraycopy(c, 0, buffer, pos, c.length);
073                        pos+=c.length;
074                }
075                else {
076                        System.arraycopy(c, 0, buffer, pos, maxlength);
077                        curr.next=new Entity(buffer);
078                        curr=curr.next;
079                        length+=buffer.length;
080                        buffer=new byte[(buffer.length>c.length-maxlength)?buffer.length:c.length-maxlength];
081                        if(c.length>maxlength) {
082                                System.arraycopy(c, maxlength, buffer, 0, c.length-maxlength);
083                                pos=c.length-maxlength;
084                        }
085                        else {
086                                pos=0;
087                        }
088                }
089        }
090        
091        /**
092        * method to append a part of a char array
093        * @param c char array to get part from
094        * @param off start index on the char array
095        * @param len length of the sequenz to get from array
096         * @throws IOException 
097        */
098        public void append(char c[], int off, int len) throws IOException {
099                append(new String(c,off,len));
100        }
101        
102        /**
103        * Method to append a string to char buffer
104        * @param str String to append
105         * @throws IOException 
106        */
107        public void append(String str) throws IOException {
108                append(str.getBytes(charset));
109        }
110
111        /**
112        * method to append a part of a String
113        * @param str string to get part from
114        * @param off start index on the string
115        * @param len length of the sequenz to get from string
116         * @throws IOException 
117        */
118        public void append(String str, int off, int len) throws IOException {
119                append(str.substring(off, off+len));
120        }
121
122        /**
123        * method to writeout content of the char buffer in a writer,
124        * this is faster than get char array with (toCharArray()) and write this
125        in writer.
126        * @param writer writer to write inside
127        * @throws IOException
128        */
129        public void writeOut(OutputStream os) throws IOException {
130                Entity e=root;
131                while(e.next!=null) {
132                        e=e.next;
133                        os.write(e.data);
134                }
135                os.write(buffer,0,pos);
136        }
137        
138        @Override
139        public String toString() {
140                try {
141                        return new String(getBytes(),charset);
142                } catch (UnsupportedEncodingException e) {
143                        return new String(getBytes());
144                }
145        }
146
147        /**
148        * clear the content of the buffer
149        */
150        public void clear() {
151                if(size()==0)return;
152        buffer = new byte[buffer.length];
153                root.next=null;
154                pos = 0;
155                length=0;
156                curr=root;
157        }
158
159        /**
160         * @return returns the size of the content of the buffer
161         */
162        public int size() {
163                return length+pos;
164        }
165        
166        
167        private class Entity {
168                private byte[] data;
169                private Entity next;
170                
171                private Entity(byte[] data) {
172                        this.data=data;
173                }
174        }
175
176
177    public byte[] getBytes() {
178        ByteArrayOutputStream baos=new ByteArrayOutputStream();
179                try {
180                        writeOut(baos);
181                } 
182                catch (IOException e) {}
183        return baos.toByteArray();
184    }
185}