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 }