001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004     *
005     *   This file is part of the Granite Data Services Platform.
006     *
007     *   Granite Data Services is free software; you can redistribute it and/or
008     *   modify it under the terms of the GNU Lesser General Public
009     *   License as published by the Free Software Foundation; either
010     *   version 2.1 of the License, or (at your option) any later version.
011     *
012     *   Granite Data Services is distributed in the hope that it will be useful,
013     *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015     *   General Public License for more details.
016     *
017     *   You should have received a copy of the GNU Lesser General Public
018     *   License along with this library; if not, write to the Free Software
019     *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020     *   USA, or see <http://www.gnu.org/licenses/>.
021     */
022    package org.granite.messaging.jmf.codec.std.impl;
023    
024    import java.io.IOException;
025    import java.io.OutputStream;
026    
027    import org.granite.messaging.jmf.DumpContext;
028    import org.granite.messaging.jmf.InputContext;
029    import org.granite.messaging.jmf.OutputContext;
030    import org.granite.messaging.jmf.codec.std.StringCodec;
031    
032    /**
033     * @author Franck WOLFF
034     */
035    public class StringCodecImpl extends AbstractIntegerStringCodec<String> implements StringCodec {
036            
037            protected static final int UUID_FLAG = 0x10;
038            protected static final int UUID_UPPERCASE_FLAG = 0x20;
039            
040            protected static final char[] LOWER_HEX = "0123456789abcdef".toCharArray();
041            protected static final char[] UPPER_HEX = "0123456789ABCDEF".toCharArray();
042            
043            protected static final int[] HEX_INDICES = new int[256];
044            static {
045                    for (int i = 0; i < HEX_INDICES.length; i++) {
046                            if (i >= '0' && i <= '9')
047                                    HEX_INDICES[i] = i - '0';
048                            else if (i >= 'a' && i <= 'f')
049                                    HEX_INDICES[i] = i - 'a' + 10;
050                            else if (i >= 'A' && i <= 'F')
051                                    HEX_INDICES[i] = i - 'A' + 10;
052                            else
053                                    HEX_INDICES[i] = -1;
054                    }
055            }
056            
057            public int getObjectType() {
058                    return JMF_STRING;
059            }
060    
061            public Class<?> getObjectClass() {
062                    return String.class;
063            }
064    
065            public void encode(OutputContext ctx, String v) throws IOException {
066                    
067                    int uuidCaseFlag = isUUID(v);
068                    if (uuidCaseFlag != -1 && ctx.indexOfStoredStrings(v) < 0) {
069                            encodeUUID(ctx, v, uuidCaseFlag);
070                            ctx.addToStoredStrings(v);
071                    }
072                    else
073                            writeString(ctx, v, JMF_STRING_TYPE_HANDLER);
074            }
075            
076            public String decode(InputContext ctx, int parameterizedJmfType) throws IOException {
077                    int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
078                    
079                    if (jmfType != JMF_STRING)
080                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
081                    
082                    if ((parameterizedJmfType & UUID_FLAG) != 0) {
083                            String uid = decodeUUID(ctx, parameterizedJmfType);
084                            ctx.addSharedString(uid);
085                            return uid;
086                    }
087                    
088                    return readString(ctx, parameterizedJmfType, JMF_STRING_TYPE_HANDLER);
089            }
090            
091            public void dump(DumpContext ctx, int parameterizedJmfType) throws IOException {
092                    ctx.indentPrintLn(String.class.getName() + ": \"" + escape(decode(ctx, parameterizedJmfType)) + "\"");
093            }
094            
095            protected int isUUID(String v) {
096                    if (v.length() != 36 || v.charAt(8) != '-')
097                            return -1;
098                    
099                    int flag = -1;
100                    
101                    for (int i = 0; i < 36; i++) {
102                            char c = v.charAt(i);
103                            
104                            switch (i) {
105                            case 8: case 13: case 18: case 23:
106                                    if (c != '-')
107                                            return -1;
108                                    break;
109                            default:
110                                    if (!(c >= '0' && c <= '9')) {
111                                            if (c >= 'a' && c <= 'f') {
112                                                    if (flag == -1)
113                                                            flag = 0x00;
114                                                    else if (flag != 0x00)
115                                                            return -1;
116                                            }
117                                            else if (c >= 'A' && c <= 'F') {
118                                                    if (flag == -1)
119                                                            flag = UUID_UPPERCASE_FLAG;
120                                                    else if (flag != UUID_UPPERCASE_FLAG)
121                                                            return -1;
122                                            }
123                                            else
124                                                    return -1;
125                                    }
126                                    break;
127                            }
128                    }
129                    
130                    if (flag == -1)
131                            flag = 0x00;
132                    
133                    return flag;
134            }
135            
136            protected void encodeUUID(OutputContext ctx, String v, int caseFlag) throws IOException {
137                    final OutputStream os = ctx.getOutputStream();
138                    
139                    os.write(caseFlag | UUID_FLAG | JMF_STRING);
140                    
141                    byte[] bytes = new byte[16];
142    
143                    int i = 0, j = 0;
144                    while (i < 36) {
145                            char c1 = v.charAt(i++);
146                            if (c1 == '-')
147                                    c1 = v.charAt(i++);
148                            char c2 = v.charAt(i++);
149                            
150                            bytes[j++] = (byte)(HEX_INDICES[c1] << 4 | HEX_INDICES[c2]);
151                    }
152    
153                    os.write(bytes);
154            }
155            
156            protected String decodeUUID(InputContext ctx, int parameterizedJmfType) throws IOException {
157                    final char[] hex = (parameterizedJmfType & UUID_UPPERCASE_FLAG) != 0 ? UPPER_HEX : LOWER_HEX;
158                    
159                    byte[] bytes = new byte[16];
160                    ctx.safeReadFully(bytes);
161                    
162                    char[] chars = new char[36];
163                    int i = 0;
164                    for (byte b : bytes) {
165                            if (i == 8 || i == 13 || i == 18 || i == 23)
166                                    chars[i++] = '-';
167                            chars[i++] = hex[(b & 0xF0) >> 4];
168                            chars[i++] = hex[b & 0x0F];
169                    }
170                    
171                    return new String(chars);
172            }
173    }