1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.codec.delimited.ints;
21
22 import java.nio.BufferUnderflowException;
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25
26 import org.apache.mina.codec.IoBuffer;
27 import org.apache.mina.codec.delimited.ByteBufferEncoder;
28 import org.apache.mina.codec.delimited.IoBufferDecoder;
29
30 /**
31 *
32 * Class providing raw/canonical representation of integers.
33 *
34 *
35 * <style type="text/css"> pre-fw { color: rgb(0, 0, 0); display: block;
36 * font-family:courier, "courier new", monospace; font-size: 13px; white-space:
37 * pre; } </style>
38 *
39 * <h2>RawInt32 encoder and decoder</h2>
40 * <p>
41 * This pair provides a mechanism called canonical form serialization.
42 *
43 * In this representations all 32-bits integer are encoded over 4 bytes.
44 *
45 *
46 * This library provides two variants <i>big-endian</i> and <i>small-endian</i>.
47 *
48 *
49 * In both cases, the inner bits of each byte are ordered from the most to the
50 * least significant bit.
51 *
52 * The difference between the two variants is the ordering of the four bytes.
53 *
54 * <ul>
55 * <li>Big-endian: <i>The bytes are ordered from the most to the least
56 * significant one</i></li>
57 * <li>Little-endian: <i>The bytes are ordered from the least to the most
58 * significant one</i></li>
59 * </ul>
60 *
61 * <p>
62 * This representation is often used since it is used internally in CPUs,
63 * therefore programmers using a low level languages (assembly, C, ...)
64 * appreciate using it (for ease of use or performance reasons). When integers
65 * are directly copied from memory, it is required to ensure this serializer
66 * uses the appropriate endianness on both ends.
67 * <ul>
68 * <li>Big-endian: 68k, MIPS, Alpha, SPARC</li>
69 * <li>Little-endian: x86, x86-64, ARM</li>
70 * <li><i>Bi-</i>endian (depends of the operating system): PowerPC, Itanium</li>
71 * </ul>
72 * </p>
73 *
74 * <p>
75 * More details availabile on the Wikipedia
76 * "<a href="http://en.wikipedia.org/wiki/Endianness">Endianness page</a>".
77 * </p>
78 *
79 * <h2>On-wire representation</h2>
80 * <p>
81 * Encoding of the value 67305985
82 * </p>
83 * <i>Big-Endian variant:</i>
84 *
85 * <pre-fw>
86 * 0000 0100 0000 0011 0000 0010 0000 0001
87 * ‾‾‾‾↓‾‾‾‾ ‾‾‾‾↓‾‾‾‾ ‾‾‾‾↓‾‾‾‾ ‾‾‾‾↓‾‾‾‾
88 * 4 3 2 1 // 4·2<sup>24</sup> + 3·2<sup>16</sup> + 2·2<sup>8</sup> + 1·2<sup>0</sup> = 67305985
89 *
90 * </pre-fw>
91 *
92 * <i>Little-Endian variant:</i>
93 *
94 * <pre-fw>
95 * 0000 0001 0000 0010 0000 0011 0000 0100
96 * ‾‾‾‾↓‾‾‾‾ ‾‾‾‾↓‾‾‾‾ ‾‾‾‾↓‾‾‾‾ ‾‾‾‾↓‾‾‾‾
97 * 1 2 3 4 // 1·2<sup>0</sup> + 2·2<sup>8</sup> + 3·2<sup>16</sup> + 4·2<sup>24</sup> = 67305985
98 * </pre-fw>
99 *
100 * </p>
101 *
102 * <p>
103 * n.b. This class doesn't have any dependency against Apache Thrift or any
104 * other library in order to provide this convenient integer serialization
105 * module to any software using FramedMINA.
106 * </p>
107 *
108 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
109 */
110 /*
111 * About the suppression of warnings:
112 * This class contains a lot of bit-shifting, logical and/or operations order to handle
113 * VarInt conversions. The code contains a lot of hard-coded integer that tools like
114 * Sonar classify as "magic numbers". Using final static variables for all of them
115 * would have resulted in a code less readable.
116 * The "all" scope is too generic, but Sonar doesn't not handle properly others scopes
117 * like "MagicNumber" (Sonar 3.6 - 03July2013)
118 */
119 @SuppressWarnings("all")
120 public final class RawInt32 implements IntTranscoder {
121 private final ByteOrder bo;
122
123 public RawInt32(ByteOrder bo) {
124 super();
125 this.bo = bo == null ? ByteOrder.BIG_ENDIAN : bo;
126 }
127
128 @Override
129 public IoBufferDecoder<Integer> getDecoder() {
130 return new Decoder();
131 }
132
133 @Override
134 public ByteBufferEncoder<Integer> getEncoder() {
135 return new Encoder();
136 }
137
138 private static final int BYTE_MASK = 0xff;
139
140 /**
141 * Documentation available in the {@link RawInt32} enclosing class.
142 *
143 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
144 *
145 */
146 private class Decoder extends IoBufferDecoder<Integer> {
147
148 @Override
149 public Integer decode(IoBuffer input) {
150 if (input.remaining() < 4) {
151 return null;
152 }
153
154 int out = 0;
155 for (int i = 0; i < 32; i += 8) {
156 out |= (input.get() & 0xff) << (bo == ByteOrder.BIG_ENDIAN ? 24 - i : i);
157 }
158 return out;
159 }
160 }
161
162 /**
163 * Documentation available in the {@link RawInt32} enclosing class.
164 *
165 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
166 *
167 */
168 private class Encoder extends ByteBufferEncoder<Integer> {
169
170 @Override
171 public void writeTo(Integer message, ByteBuffer buffer) {
172
173 if (buffer.remaining() < 4) {
174 throw new BufferUnderflowException();
175 }
176 for (int i = 0; i < 32; i += 8) {
177 buffer.put((byte) (message >> (bo == ByteOrder.BIG_ENDIAN ? 24 - i : i)));
178 }
179 }
180
181 @Override
182 public int getEncodedSize(Integer message) {
183 return 4;
184 }
185
186 }
187 }