/protocols/smpp/src/main/java/org/mobicents/protocols/smpp/gsm/ems/CompressedData.java

http://mobicents.googlecode.com/ · Java · 180 lines · 135 code · 13 blank · 32 comment · 30 complexity · 7862aa4744c7d1ca3ef9e87f849defed MD5 · raw file

  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.mobicents.protocols.smpp.gsm.ems;
  23. import java.nio.ByteBuffer;
  24. import java.util.ArrayList;
  25. import java.util.List;
  26. import org.mobicents.protocols.smpp.gsm.AbstractHeaderElement;
  27. /**
  28. * Header element that represents one or more compressed extended
  29. * objects.
  30. * @version $Id: CompressedData.java 484 2010-02-08 16:08:50Z orank $
  31. */
  32. public class CompressedData extends AbstractHeaderElement {
  33. private List<ExtendedObject> objects = new ArrayList<ExtendedObject>();
  34. private byte[] compressedData;
  35. private int ptr;
  36. public void add(ExtendedObject object) {
  37. objects.add(object);
  38. }
  39. public byte[] compress() {
  40. int length = 0;
  41. for (ExtendedObject obj : objects) {
  42. length += obj.getLength();
  43. }
  44. length += objects.size();
  45. // Create the uncompressed buffer.
  46. ByteBuffer buffer = ByteBuffer.allocate(length);
  47. for (ExtendedObject obj : objects) {
  48. buffer.put((byte) 0x14);
  49. buffer.put(obj.getData());
  50. }
  51. byte[] uncompressed = buffer.array();
  52. ByteBuffer compressed = ByteBuffer.allocate(length);
  53. ByteBuffer literal = ByteBuffer.allocate(length);
  54. literal.put(uncompressed, 0, 2);
  55. int readPos = 2;
  56. while (readPos < length) {
  57. boolean sliceFound = false;
  58. // Can't find a slice size larger than the number of bytes we
  59. // have available behind or in front of the current read position.
  60. int sliceSize =
  61. Math.min(Math.min(63, readPos), uncompressed.length - readPos);
  62. int slicePos = -1;
  63. for (; sliceSize > 2; sliceSize--) {
  64. slicePos = findSlice(uncompressed, readPos, sliceSize);
  65. if (slicePos >= 0) {
  66. sliceFound = true;
  67. break;
  68. }
  69. }
  70. if (!sliceFound) {
  71. // Add the current byte to the literal buffer
  72. literal.put((byte) uncompressed[readPos]);
  73. readPos++;
  74. } else {
  75. // Output the current literal buffer.
  76. outputLiterals(compressed, literal);
  77. // Output a slice descriptor
  78. slicePos = readPos - slicePos;
  79. int descriptor = ((sliceSize & 0x2f) << 9) | (slicePos & 0x1ff);
  80. compressed.putShort((short) descriptor);
  81. readPos += sliceSize;
  82. }
  83. }
  84. compressed.flip();
  85. compressedData = new byte[compressed.remaining()];
  86. compressed.get(compressedData, 0, compressed.remaining());
  87. return compressedData;
  88. }
  89. @Override
  90. public void reset() {
  91. super.reset();
  92. objects.clear();
  93. compressedData = null;
  94. ptr = 0;
  95. }
  96. public int getLength() {
  97. if (compressedData == null) {
  98. throw new IllegalStateException("Must compress the data first.");
  99. }
  100. return compressedData.length + 3;
  101. }
  102. @Override
  103. public boolean isComplete() {
  104. if (compressedData == null) {
  105. throw new IllegalStateException("Must compress the data first.");
  106. }
  107. return ptr == compressedData.length;
  108. }
  109. @Override
  110. public boolean write(int segmentNum, ByteBuffer buffer) {
  111. if (compressedData == null) {
  112. throw new IllegalStateException("Must compress the data first.");
  113. }
  114. boolean writeHeader = ptr == 0;
  115. if (writeHeader && buffer.remaining() < 5) {
  116. return false;
  117. } else if (!writeHeader && buffer.remaining() < 3) {
  118. return false;
  119. }
  120. int headerSize;
  121. int dataSize;
  122. if (writeHeader) {
  123. headerSize = 3;
  124. dataSize = Math.min(buffer.remaining() - 5, compressedData.length - ptr);
  125. } else {
  126. headerSize = 0;
  127. dataSize = Math.min(buffer.remaining() - 2, compressedData.length - ptr);
  128. }
  129. buffer.put((byte) 0x16);
  130. buffer.put((byte) (headerSize + dataSize));
  131. if (writeHeader) {
  132. buffer.put((byte) 0);
  133. buffer.putShort((short) compressedData.length);
  134. }
  135. buffer.put(compressedData, ptr, dataSize);
  136. ptr += dataSize;
  137. return true;
  138. }
  139. private int findSlice(byte[] data, int readPos, int sliceSize) {
  140. int pos = readPos - sliceSize;
  141. int endPos = Math.max(readPos - 511, 0);
  142. for (; pos >= endPos; pos--) {
  143. boolean matched = true;
  144. for (int i = 0; i < sliceSize; i++) {
  145. if (data[readPos + i] != data[pos + i]) {
  146. matched = false;
  147. break;
  148. }
  149. }
  150. if (matched) {
  151. return pos;
  152. }
  153. }
  154. return -1;
  155. }
  156. private void outputLiterals(ByteBuffer compressed, ByteBuffer literal) {
  157. literal.flip();
  158. while (literal.remaining() > 0) {
  159. int size = Math.min(127, literal.remaining());
  160. compressed.put((byte) (0x80 | size));
  161. for (int i = 0; i < size; i++) {
  162. compressed.put(literal.get());
  163. }
  164. }
  165. literal.clear();
  166. }
  167. }