001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.asn1.codec.stateful.examples;
021
022
023 import java.nio.ByteBuffer;
024
025 import org.apache.directory.shared.asn1.codec.DecoderException;
026 import org.apache.directory.shared.asn1.codec.stateful.AbstractStatefulDecoder;
027 import org.apache.directory.shared.i18n.I18n;
028
029
030 /**
031 * Document me.
032 *
033 * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
034 * @version $Rev: 912399 $
035 */
036 public class HexDecoder extends AbstractStatefulDecoder
037 {
038 private ByteBuffer decoded = ByteBuffer.allocate( 128 );
039
040 private byte lsn;
041
042 private byte msn;
043
044 private boolean expectingMsn = true;
045
046
047 public void decode( Object chunk ) throws DecoderException
048 {
049 ByteBuffer encoded = ( ByteBuffer ) chunk;
050
051 if ( encoded == null || !encoded.hasRemaining() )
052 {
053 return;
054 }
055
056 while ( encoded.hasRemaining() )
057 {
058 if ( !decoded.hasRemaining() )
059 {
060 decoded.flip();
061 super.decodeOccurred( decoded );
062 decoded.clear();
063 }
064
065 if ( expectingMsn )
066 {
067 msn = encoded.get();
068 expectingMsn = false;
069 }
070 else
071 {
072 lsn = encoded.get();
073 expectingMsn = true;
074 }
075
076 /*
077 * if we've hit the most significant nibble then we have two hex
078 * characters as bytes so we need to compute and add the byte to the
079 * buffer
080 */
081 if ( expectingMsn )
082 {
083 byte bite = getNibble( lsn );
084 bite |= ( getNibble( msn ) << 4 );
085 decoded.put( bite );
086 }
087 }
088
089 /*
090 * only trigger a decode callback if we have seen an even number of hex
091 * character bytes in which case we're in the expectingMsn state this
092 * will flush out what's siting in the buffer automatically
093 */
094 if ( expectingMsn )
095 {
096 decoded.flip();
097 super.decodeOccurred( decoded );
098 decoded.clear();
099 }
100 }
101
102
103 private byte getNibble( byte ch ) throws DecoderException
104 {
105 // lowercase the character if it is in upper case
106 if ( ch > 64 && ch < 91 )
107 {
108 ch -= 32;
109 }
110
111 switch ( ch )
112 {
113 case 48:
114 return 0;
115 case 49:
116 return 1;
117 case 50:
118 return 2;
119 case 51:
120 return 3;
121 case 52:
122 return 4;
123 case 53:
124 return 5;
125 case 54:
126 return 6;
127 case 55:
128 return 7;
129 case 56:
130 return 8;
131 case 57:
132 return 9;
133 case 97:
134 return 10;
135 case 98:
136 return 11;
137 case 99:
138 return 12;
139 case 100:
140 return 13;
141 case 101:
142 return 14;
143 case 102:
144 return 15;
145 default:
146 throw new DecoderException( I18n.err( I18n.ERR_00015, ch ) );
147 }
148 }
149 }