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 }