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 */ 022package org.granite.messaging.jmf.codec.std.impl; 023 024import java.io.IOException; 025import java.io.OutputStream; 026 027import org.granite.messaging.jmf.DumpContext; 028import org.granite.messaging.jmf.InputContext; 029import org.granite.messaging.jmf.OutputContext; 030import org.granite.messaging.jmf.codec.std.StringCodec; 031 032/** 033 * @author Franck WOLFF 034 */ 035public 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}