| 17 | |
| 18 | class Rsv { |
| 19 | static byte[] encodeRsv(String[][] rows) { |
| 20 | ArrayList<byte[]> parts = new ArrayList<byte[]>(); |
| 21 | byte[] valueTerminatorByte = new byte[]{(byte)0xFF}; |
| 22 | byte[] nullValueByte = new byte[]{(byte)0xFE}; |
| 23 | byte[] rowTerminatorByte = new byte[]{(byte)0xFD}; |
| 24 | CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); |
| 25 | int resultLength = 0; |
| 26 | for (String[] row : rows) { |
| 27 | for (String value : row) { |
| 28 | if (value == null) { parts.add(nullValueByte); resultLength++; } |
| 29 | else if (value.length() > 0) { |
| 30 | byte[] valueBytes; |
| 31 | try { |
| 32 | ByteBuffer byteBuffer = encoder.encode(CharBuffer.wrap(value)); |
| 33 | valueBytes = new byte[byteBuffer.limit()]; |
| 34 | byteBuffer.get(valueBytes); |
| 35 | } catch (Exception e) { throw new RuntimeException("Invalid string value", e); } |
| 36 | parts.add(valueBytes); resultLength += valueBytes.length; |
| 37 | } |
| 38 | parts.add(valueTerminatorByte); resultLength++; |
| 39 | } |
| 40 | parts.add(rowTerminatorByte); resultLength++; |
| 41 | } |
| 42 | byte[] result = new byte[resultLength]; |
| 43 | ByteBuffer resultBuffer = ByteBuffer.wrap(result); |
| 44 | for (byte[] part : parts) { resultBuffer.put(part); } |
| 45 | return result; |
| 46 | } |
| 47 | |
| 48 | static String[][] decodeRsv(byte[] bytes) { |
| 49 | if (bytes.length > 0 && (bytes[bytes.length-1] & 0xFF) != 0xFD) { throw new RuntimeException("Incomplete RSV document"); } |