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.IOException;
022import java.io.OutputStream;
023import java.io.UnsupportedEncodingException;
024import java.io.Writer;
025
026
027/**
028 * class to handle characters, similar to StringBuffer, but dont copy big blocks of char arrays.
029 */
030public class CharBuffer {
031
032        private final static int BLOCK_LENGTH = 1024;
033        private char 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        
039        /**
040         * default constructor
041         */
042        public CharBuffer() {
043                this(BLOCK_LENGTH);
044        }
045
046        /**
047         * constructor with size of the buffer
048         * @param size
049         */
050        public CharBuffer(int size) {
051                buffer = new char[size];
052        }
053        
054        public void append(char c) {
055                append(new char[]{c});
056        }
057        
058        /**
059        * method to appennd a charr array to the buffer
060        * @param c char array to append
061        */
062        public void append(char c[]) {
063                int maxlength=buffer.length-pos;
064                if(c.length<maxlength) {
065                        System.arraycopy(c, 0, buffer, pos, c.length);
066                        pos+=c.length;
067                }
068                else {
069                        System.arraycopy(c, 0, buffer, pos, maxlength);
070                        curr.next=new Entity(buffer);
071                        curr=curr.next;
072                        length+=buffer.length;
073                        buffer=new char[(buffer.length>c.length-maxlength)?buffer.length:c.length-maxlength];
074                        if(c.length>maxlength) {
075                                System.arraycopy(c, maxlength, buffer, 0, c.length-maxlength);
076                                pos=c.length-maxlength;
077                        }
078                        else {
079                                pos=0;
080                        }
081                }
082        }
083        
084        /**
085        * method to append a part of a char array
086        * @param c char array to get part from
087        * @param off start index on the char array
088        * @param len length of the sequenz to get from array
089        */
090        public void append(char c[], int off, int len) {
091                int restLength=buffer.length-pos;
092                if(len<restLength) {
093                        System.arraycopy(c, off, buffer, pos, len);
094                        pos+=len;
095                }
096                else {
097                        System.arraycopy(c, off, buffer, pos, restLength);
098                        curr.next=new Entity(buffer);
099                        curr=curr.next;
100                        length+=buffer.length;
101                        buffer=new char[(buffer.length>len-restLength)?buffer.length:len-restLength];
102                        
103                        System.arraycopy(c, off+restLength, buffer, 0, len-restLength);
104                        pos=len-restLength;
105                        
106                }
107        }
108        
109        /**
110        * Method to append a string to char buffer
111        * @param str String to append
112        */
113        public void append(String str) {
114                if(str==null)return;
115                int restLength=buffer.length-pos;
116                if(str.length()<restLength) {
117                        str.getChars(0,str.length(),buffer,pos);
118                        pos+=str.length();
119                }
120                else {
121                        str.getChars(0,restLength,buffer,pos);
122                        curr.next=new Entity(buffer);
123                        curr=curr.next;
124                        length+=buffer.length;
125                        buffer=new char[(buffer.length>str.length()-restLength)?buffer.length:str.length()-restLength];
126                        
127                        str.getChars(restLength,str.length(),buffer,0);
128                        pos=str.length()-restLength;
129                        
130                }
131        }
132
133        /**
134        * method to append a part of a String
135        * @param str string to get part from
136        * @param off start index on the string
137        * @param len length of the sequenz to get from string
138        */
139        public void append(String str, int off, int len) {
140                int restLength=buffer.length-pos;
141                if(len<restLength) {
142                        str.getChars(off,off+len,buffer,pos);
143                        pos+=len;
144                }
145                else {
146                        str.getChars(off,off+restLength,buffer,pos);
147                        curr.next=new Entity(buffer);
148                        curr=curr.next;
149                        length+=buffer.length;
150                        buffer=new char[(buffer.length>len-restLength)?buffer.length:len-restLength];
151                        
152                        str.getChars(off+restLength,off+len,buffer,0);
153                        pos=len-restLength;
154                        
155                }
156        }
157
158        /**
159        * method to writeout content of the char buffer in a writer,
160        * this is faster than get char array with (toCharArray()) and write this
161        in writer.
162        * @param writer writer to write inside
163        * @throws IOException
164        */
165        public void writeOut(Writer writer) throws IOException {
166                
167                Entity e=root;
168                while(e.next!=null) {
169                        e=e.next;
170                        writer.write(e.data);
171                }
172                writer.write(buffer, 0, pos);
173        }
174        public void writeOut(OutputStream os, String charset) throws IOException {
175                Entity e=root;
176                while(e.next!=null) {
177                        e=e.next;
178                        os.write(new String(e.data).getBytes(charset));
179                }
180                os.write(new String(buffer, 0, pos).getBytes(charset));
181        }
182    
183
184        /**
185        * return content of the Char Buffer as char array
186        * @return char array
187        */
188        public char[] toCharArray() {
189                Entity e=root;
190                char[] chrs=new char[size()];
191                int off=0;
192                while(e.next!=null) {
193                        e=e.next;
194                        System.arraycopy(e.data,0,chrs,off,e.data.length);
195                        off+=e.data.length;
196                }
197                System.arraycopy(buffer,0,chrs,off,pos);
198                return chrs;
199        }
200        
201        @Override
202        public String toString() {
203                return new String(toCharArray());
204        }
205
206        /**
207        * clear the content of the buffer
208        */
209        public void clear() {
210                if(size()==0)return;
211        buffer = new char[buffer.length];
212                root.next=null;
213                pos = 0;
214                length=0;
215                curr=root;
216        }
217
218        /**
219         * @return returns the size of the content of the buffer
220         */
221        public int size() {
222                return length+pos;
223        }
224        
225        
226        private class Entity {
227                private char[] data;
228                private Entity next;
229                
230                private Entity(char[] data) {
231                        this.data=data;
232                }
233        }
234
235
236    public byte[] getBytes(String characterEncoding) throws UnsupportedEncodingException {
237        
238        
239        return toString().getBytes(characterEncoding);
240        
241    }
242
243        
244        /*public static void main(String[] args) {
245                CharBuffer cb=new CharBuffer(3);
246                cb.append("12");
247                cb.append("34");
248                cb.append("5");
249                cb.append("6");
250                cb.append("7");
251                cb.append("890-");
252                cb.append("1234567890-1234567890-");
253                
254                cb=new CharBuffer(3);
255                cb.append("12",0,2);
256                cb.append("34",0,2);
257                cb.append("5",0,1);
258                cb.append("xxx6ggg",3,1);
259                cb.append("7zzz",0,1);
260                cb.append("890-",0,4);
261                cb.append("1234567890-1234567890-",0,22);
262                //System.out.println(cb+"->"+cb.size());
263                
264                
265                cb=new CharBuffer(3);
266                cb.append(new char[]{'1','2'});
267                cb.append(new char[]{'3','4'});
268                cb.append(new char[]{'5'});
269                cb.append(new char[]{'6'});
270                cb.append(new char[]{'7'});
271                cb.append(new char[]{'8','9','0','-'});
272                cb.append(new char[]{'1','2','3','4','5','6','7','8','9','0','-','1','2','3','4','5','6','7','8','9','0','-'});
273                System.out.println(cb+"->"+cb.size());
274
275                
276                
277                cb=new CharBuffer(3);
278                cb.append(new char[]{'X','1','2','X'},1,2);
279                cb.append(new char[]{'3','4'},0,2);
280                cb.append(new char[]{'5'},0,1);
281                cb.append(new char[]{'6'},0,1);
282                cb.append(new char[]{'7'},0,1);
283                cb.append(new char[]{'8','9','0','-'},0,4);
284                cb.append(new char[]{'1','2','3','4','5','6','7','8','9','0','-','1','2','3','4','5','6','7','8','9','0','-'},0,22);
285                System.out.println(cb+"->"+cb.size());
286                
287                
288        }*/
289}