// Check if DatagramChannel.send while connected can include // address without throwing private static void test1() throws Exception { DatagramChannel sndChannel = DatagramChannel.open(); sndChannel.socket().bind(null); InetSocketAddress sender = new InetSocketAddress(InetAddress.getLocalHost(), sndChannel.socket().getLocalPort()); DatagramChannel rcvChannel = DatagramChannel.open(); rcvChannel.socket().bind(null); InetSocketAddress receiver = new InetSocketAddress(InetAddress.getLocalHost(), rcvChannel.socket().getLocalPort()); rcvChannel.connect(sender); sndChannel.connect(receiver); ByteBuffer bb = ByteBuffer.allocate(256); bb.put("hello".getBytes()); bb.flip(); int sent = sndChannel.send(bb, receiver); bb.clear(); rcvChannel.receive(bb); bb.flip(); CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb); if (!cb.toString().startsWith("h")) throw new RuntimeException("Test failed"); rcvChannel.close(); sndChannel.close(); }
// Check if the datagramsocket adaptor can send with a packet // that has not been initialized with an address; the legacy // datagram socket will send in this case private static void test2() throws Exception { DatagramChannel sndChannel = DatagramChannel.open(); sndChannel.socket().bind(null); InetSocketAddress sender = new InetSocketAddress(InetAddress.getLocalHost(), sndChannel.socket().getLocalPort()); DatagramChannel rcvChannel = DatagramChannel.open(); rcvChannel.socket().bind(null); InetSocketAddress receiver = new InetSocketAddress(InetAddress.getLocalHost(), rcvChannel.socket().getLocalPort()); rcvChannel.connect(sender); sndChannel.connect(receiver); byte b[] = "hello".getBytes("UTF-8"); DatagramPacket pkt = new DatagramPacket(b, b.length); sndChannel.socket().send(pkt); ByteBuffer bb = ByteBuffer.allocate(256); rcvChannel.receive(bb); bb.flip(); CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb); if (!cb.toString().startsWith("h")) throw new RuntimeException("Test failed"); // Check that the pkt got set with the target address; // This is legacy behavior if (!pkt.getSocketAddress().equals(receiver)) throw new RuntimeException("Test failed"); rcvChannel.close(); sndChannel.close(); }
public static void main(String[] arguments) { try { // read byte data into a byte buffer String data = "friends.dat"; FileInputStream inData = new FileInputStream(data); FileChannel inChannel = inData.getChannel(); long inSize = inChannel.size(); ByteBuffer source = ByteBuffer.allocate((int) inSize); inChannel.read(source, 0); source.position(0); System.out.println("Original byte data:"); for (int i = 0; source.remaining() > 0; i++) { System.out.print(source.get() + " "); } // convert byte data into character data source.position(0); Charset ascii = Charset.forName("US-ASCII"); CharsetDecoder toAscii = ascii.newDecoder(); CharBuffer destination = toAscii.decode(source); destination.position(0); System.out.println("\n\nNew character data:"); for (int i = 0; destination.remaining() > 0; i++) { System.out.print(destination.get()); } System.out.println(); } catch (FileNotFoundException fne) { System.out.println(fne.getMessage()); } catch (IOException ioe) { System.out.println(ioe.getMessage()); } }
static boolean check(CharsetDecoder dec, byte[] bytes, boolean direct, int[] flow) { int inPos = flow[0]; int inLen = flow[1]; int outPos = flow[2]; int outLen = flow[3]; int expedInPos = flow[4]; int expedOutPos = flow[5]; CoderResult expedCR = (flow[6] == 0) ? CoderResult.UNDERFLOW : CoderResult.OVERFLOW; ByteBuffer bbf; CharBuffer cbf; if (direct) { bbf = ByteBuffer.allocateDirect(inPos + bytes.length); cbf = ByteBuffer.allocateDirect((outPos + outLen) * 2).asCharBuffer(); } else { bbf = ByteBuffer.allocate(inPos + bytes.length); cbf = CharBuffer.allocate(outPos + outLen); } bbf.position(inPos); bbf.put(bytes).flip().position(inPos).limit(inPos + inLen); cbf.position(outPos); dec.reset(); CoderResult cr = dec.decode(bbf, cbf, false); if (cr != expedCR || bbf.position() != expedInPos || cbf.position() != expedOutPos) { System.out.printf("Expected(direct=%5b): [", direct); for (int i : flow) System.out.print(" " + i); System.out.println( "] CR=" + cr + ", inPos=" + bbf.position() + ", outPos=" + cbf.position()); return false; } return true; }
static byte[] encode(char[] cc, Charset cs, boolean testDirect, Time t) throws Exception { ByteBuffer bbf; CharBuffer cbf; CharsetEncoder enc = cs.newEncoder(); String csn = cs.name(); if (testDirect) { bbf = ByteBuffer.allocateDirect(cc.length * 4); cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); cbf.put(cc).flip(); } else { bbf = ByteBuffer.allocate(cc.length * 4); cbf = CharBuffer.wrap(cc); } CoderResult cr = null; long t1 = System.nanoTime() / 1000; for (int i = 0; i < iteration; i++) { cbf.rewind(); bbf.clear(); enc.reset(); cr = enc.encode(cbf, bbf, true); } long t2 = System.nanoTime() / 1000; t.t = (t2 - t1) / iteration; if (cr != CoderResult.UNDERFLOW) { System.out.println("ENC-----------------"); int pos = cbf.position(); System.out.printf(" cr=%s, cbf.pos=%d, cc[pos]=%x%n", cr.toString(), pos, cc[pos] & 0xffff); throw new RuntimeException("Encoding err: " + csn); } byte[] bb = new byte[bbf.position()]; bbf.flip(); bbf.get(bb); return bb; }
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { int mark = src.position(); if (needsMark) { if (dst.remaining() < 2) return CoderResult.OVERFLOW; put(BYTE_ORDER_MARK, dst); needsMark = false; } try { while (src.hasRemaining()) { char c = src.get(); if (!Surrogate.is(c)) { if (dst.remaining() < 2) return CoderResult.OVERFLOW; mark++; put(c, dst); continue; } int d = sgp.parse(c, src); if (d < 0) return sgp.error(); if (dst.remaining() < 4) return CoderResult.OVERFLOW; mark += 2; put(Surrogate.high(d), dst); put(Surrogate.low(d), dst); } return CoderResult.UNDERFLOW; } finally { src.position(mark); } }
/** * Creates a string in a specfied character set. * * @param value String constant, must not be null * @param charsetName Name of the character set, may be null * @param collation Collation, may be null * @throws IllegalCharsetNameException If the given charset name is illegal * @throws UnsupportedCharsetException If no support for the named charset is available in this * instance of the Java virtual machine * @throws RuntimeException If the given value cannot be represented in the given charset */ public NlsString(String value, String charsetName, SqlCollation collation) { assert value != null; if (null != charsetName) { charsetName = charsetName.toUpperCase(); this.charsetName = charsetName; String javaCharsetName = SqlUtil.translateCharacterSetName(charsetName); if (javaCharsetName == null) { throw new UnsupportedCharsetException(charsetName); } this.charset = Charset.forName(javaCharsetName); CharsetEncoder encoder = charset.newEncoder(); // dry run to see if encoding hits any problems try { encoder.encode(CharBuffer.wrap(value)); } catch (CharacterCodingException ex) { throw RESOURCE.charsetEncoding(value, javaCharsetName).ex(); } } else { this.charsetName = null; this.charset = null; } this.collation = collation; this.value = value; }
public static void main(String args[]) throws Exception { String s = "abc\uD800\uDC00qrst"; // Valid surrogate char[] c = s.toCharArray(); CharsetEncoder enc = Charset.forName("ISO8859_1").newEncoder().onUnmappableCharacter(CodingErrorAction.REPLACE); /* Process the first 4 characters, including the high surrogate which should be stored */ ByteBuffer bb = ByteBuffer.allocate(10); CharBuffer cb = CharBuffer.wrap(c); cb.limit(4); enc.encode(cb, bb, false); cb.limit(7); enc.encode(cb, bb, true); byte[] first = bb.array(); for (int i = 0; i < 7; i++) System.err.printf("[%d]=%d was %d\n", i, (int) first[i] & 0xffff, (int) c[i] & 0xffff); }
public static void main(String[] args) throws Exception { // 创建简体中文对应的Charset Charset cn = Charset.forName("GBK"); // 获取cn对象对应的编码器和解码器 CharsetEncoder cnEncoder = cn.newEncoder(); CharsetDecoder cnDecoder = cn.newDecoder(); // 创建一个CharBuffer对象 CharBuffer cbuff = CharBuffer.allocate(8); cbuff.put('孙'); cbuff.put('悟'); cbuff.put('空'); cbuff.flip(); // 将CharBuffer中的字符序列转换成字节序列 ByteBuffer bbuff = cnEncoder.encode(cbuff); // 循环访问ByteBuffer中的每个字节 for (int i = 0; i < bbuff.capacity(); i++) { System.out.print(bbuff.get(i) + " "); } // 将ByteBuffer的数据解码成字符序列 System.out.println("\n" + cnDecoder.decode(bbuff)); }
static CoderResult decodeCR(byte[] bb, Charset cs, boolean testDirect) throws Exception { CharsetDecoder dec = cs.newDecoder(); ByteBuffer bbf; CharBuffer cbf; if (testDirect) { bbf = ByteBuffer.allocateDirect(bb.length); cbf = ByteBuffer.allocateDirect(bb.length * 2).asCharBuffer(); bbf.put(bb).flip(); } else { bbf = ByteBuffer.wrap(bb); cbf = CharBuffer.allocate(bb.length); } CoderResult cr = null; for (int i = 0; i < iteration; i++) { bbf.rewind(); cbf.clear(); dec.reset(); cr = dec.decode(bbf, cbf, true); } return cr; }
static CoderResult encodeCR(char[] cc, Charset cs, boolean testDirect) throws Exception { ByteBuffer bbf; CharBuffer cbf; CharsetEncoder enc = cs.newEncoder(); if (testDirect) { bbf = ByteBuffer.allocateDirect(cc.length * 4); cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); cbf.put(cc).flip(); } else { bbf = ByteBuffer.allocate(cc.length * 4); cbf = CharBuffer.wrap(cc); } CoderResult cr = null; for (int i = 0; i < iteration; i++) { cbf.rewind(); bbf.clear(); enc.reset(); cr = enc.encode(cbf, bbf, true); } return cr; }
@Override int read(final TextInput ti) throws IOException { int c = -1; while (++c < 4) { final int ch = ti.readByte(); if (ch < 0) break; cache[c] = (byte) ch; outc.position(0); inc.position(0); inc.limit(c + 1); csd.reset(); final CoderResult cr = csd.decode(inc, outc, true); if (cr.isMalformed()) continue; // return character int i = 0; final int os = outc.position(); for (int o = 0; o < os; ++o) i |= outc.get(o) << (o << 3); return i; } return c == 0 ? -1 : invalid(); }
/** * Writes any remaining output to the output buffer and resets the converter to its initial state. * * @param output char array to receive flushed output. * @param outStart start writing to output array at this offset. * @param outEnd stop writing to output array at this offset (exclusive). * @exception MalformedInputException if the output to be flushed contained a partial or invalid * multibyte character sequence. flush will write what it can to the output buffer and reset * the converter before throwing this exception. An additional call to flush is not required. * @exception ConversionBufferFullException if output array is filled before all the output can be * flushed. flush will write what it can to the output buffer and remember its state. An * additional call to flush with a new output buffer will conclude the operation. */ public int flush(char[] output, int outStart, int outEnd) throws MalformedInputException, ConversionBufferFullException { byteOff = charOff = 0; if (outStart >= outEnd || outStart >= output.length) throw new ConversionBufferFullException(); if (dst != null && dst.array() == output) dst.position(outStart).limit(outEnd); else dst = CharBuffer.wrap(output, outStart, outEnd - outStart); CoderResult cr = null; try { if (src != null) cr = decoder.decode((ByteBuffer) src.clear(), dst, true); assert !cr.isUnmappable(); if (cr.isMalformed()) { badInputLength = cr.length(); reset(); throw new MalformedInputException(); } } catch (IllegalStateException ise) { if (src != null) cr = decoder.reset().decode(src, dst, true); } try { cr = decoder.flush(dst); } catch (Exception e) { assert false; } finally { byteOff = 0; charOff = dst.position(); src = null; } if (cr.isOverflow()) throw new ConversionBufferFullException(); // Return the length written to the output buffer if (cr.isUnderflow()) { int written = charOff - outStart; reset(); return written; } assert false; return -1; // should be never reached }
/** * Converts an array of bytes containing characters in an external encoding into an array of * Unicode characters. This method allows a buffer by buffer conversion of a data stream. The * state of the conversion is saved between calls to convert. Among other things, this means * multibyte input sequences can be split between calls. If a call to convert results in an * exception, the conversion may be continued by calling convert again with suitably modified * parameters. All conversions should be finished with a call to the flush method. * * @return the number of bytes written to output. * @param input byte array containing text to be converted. * @param inStart begin conversion at this offset in input array. * @param inEnd stop conversion at this offset in input array (exclusive). * @param output character array to receive conversion result. * @param outStart start writing to output array at this offset. * @param outEnd stop writing to output array at this offset (exclusive). * @exception MalformedInputException if the input buffer contains any sequence of bytes that is * illegal for the input character set. * @exception UnknownCharacterException for any character that that cannot be converted to * Unicode. Thrown only when converter is not in substitution mode. * @exception ConversionBufferFullException if output array is filled prior to converting all the * input. */ public int convert(byte[] input, int inStart, int inEnd, char[] output, int outStart, int outEnd) throws UnknownCharacterException, MalformedInputException, ConversionBufferFullException { byteOff = inStart; charOff = outStart; // throw exceptions compatible to legacy ByteToCharXxx converters if (inStart >= inEnd) return 0; if (inStart >= input.length) throw new ArrayIndexOutOfBoundsException(inStart); if (outStart >= outEnd || outStart >= output.length) throw new ConversionBufferFullException(); if (src != null && src.array() == input) src.position(inStart).limit(inEnd); else src = ByteBuffer.wrap(input, inStart, inEnd - inStart); if (dst != null && dst.array() == output) dst.position(outStart).limit(outEnd); else dst = CharBuffer.wrap(output, outStart, outEnd - outStart); CoderResult cr; try { cr = decoder.decode(src, dst, false); } catch (IllegalStateException ise) { cr = decoder.reset().decode(src, dst, false); } finally { byteOff = src.position(); charOff = dst.position(); } if (cr.isUnmappable()) { badInputLength = cr.length(); throw new UnknownCharacterException(); } if (cr.isMalformed()) { badInputLength = cr.length(); throw new MalformedInputException(); } if (cr.isOverflow()) throw new ConversionBufferFullException(); // Return the length written to the output buffer if (cr.isUnderflow()) return charOff - outStart; return -1; // should be never reached }
/** * Check if the first X characters of a byte stream match a String. * * @param data The byte array to process * @param pattern The String to match * @return True if the pattern was found, false otherwise */ private static boolean bytesEqualsString(byte[] data, String pattern) { byte[] bytes = new byte[pattern.length()]; Charset csets = Charset.forName("US-ASCII"); boolean fin = false; int currChar = 0; // remove any CR and/or LF characters at the beginning of the article // data while (!fin) { if (currChar >= data.length) break; byte in = data[currChar]; ByteBuffer bb = ByteBuffer.wrap(new byte[] {(byte) in}); CharBuffer cb = csets.decode(bb); char c = cb.charAt(0); if (data.length > 0 && (c == '\n' || c == '\r')) currChar++; else fin = true; if (data.length == 0) fin = true; } // extract bytes (chars) to check from article data for (int i = 0; i < bytes.length && i < data.length; i++, currChar++) { byte in = data[currChar]; bytes[i] = (byte) in; } // decode byte data to characters ByteBuffer bb = ByteBuffer.wrap(bytes); CharBuffer cb = csets.decode(bb); // compare these characters to the pattern String for (int i = 0; i < pattern.length(); i++) if (cb.charAt(i) != pattern.charAt(i)) return false; return true; }
static void testMixed(Charset cs) throws Throwable { CharsetDecoder dec = cs.newDecoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); CharsetEncoder enc = cs.newEncoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); List<Integer> cps = new ArrayList<>(0x10000); int off = 0; int cp = 0; while (cp < 0x10000) { if (enc.canEncode((char) cp)) { cps.add(cp); } cp++; } Collections.shuffle(cps); char[] bmpCA = new char[cps.size()]; for (int i = 0; i < cps.size(); i++) bmpCA[i] = (char) (int) cps.get(i); String bmpStr = new String(bmpCA); // getBytes(csn); byte[] bmpBA = bmpStr.getBytes(cs.name()); ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(bmpCA)); byte[] baNIO = new byte[bf.limit()]; bf.get(baNIO, 0, baNIO.length); if (!Arrays.equals(bmpBA, baNIO)) { throw new RuntimeException("getBytes(csn) failed -> " + cs.name()); } // getBytes(cs); bmpBA = bmpStr.getBytes(cs); if (!Arrays.equals(bmpBA, baNIO)) throw new RuntimeException("getBytes(cs) failed -> " + cs.name()); // new String(csn); String strSC = new String(bmpBA, cs.name()); String strNIO = dec.reset().decode(ByteBuffer.wrap(bmpBA)).toString(); if (!strNIO.equals(strSC)) { throw new RuntimeException("new String(csn) failed -> " + cs.name()); } // new String(cs); strSC = new String(bmpBA, cs); if (!strNIO.equals(strSC)) throw new RuntimeException("new String(cs) failed -> " + cs.name()); }
/** Generic Decoder. */ private static final class Generic extends TextDecoder { /** Input cache. */ private final byte[] cache = new byte[4]; /** Input buffer. */ private final ByteBuffer inc = ByteBuffer.wrap(cache); /** Output buffer. */ private final CharBuffer outc = CharBuffer.wrap(new char[4]); /** Charset decoder. */ private final CharsetDecoder csd; /** * Constructor. * * @param enc encoding * @throws IOException I/O exception */ private Generic(final String enc) throws IOException { try { csd = Charset.forName(enc).newDecoder(); } catch (final Exception ex) { throw new EncodingException(ex); } } @Override int read(final TextInput ti) throws IOException { int c = -1; while (++c < 4) { final int ch = ti.readByte(); if (ch < 0) break; cache[c] = (byte) ch; outc.position(0); inc.position(0); inc.limit(c + 1); csd.reset(); final CoderResult cr = csd.decode(inc, outc, true); if (cr.isMalformed()) continue; // return character int i = 0; final int os = outc.position(); for (int o = 0; o < os; ++o) i |= outc.get(o) << (o << 3); return i; } return c == 0 ? -1 : invalid(); } }
static char[] decode(byte[] bb, Charset cs, boolean testDirect, Time t) throws Exception { String csn = cs.name(); CharsetDecoder dec = cs.newDecoder(); ByteBuffer bbf; CharBuffer cbf; if (testDirect) { bbf = ByteBuffer.allocateDirect(bb.length); cbf = ByteBuffer.allocateDirect(bb.length * 2).asCharBuffer(); bbf.put(bb); } else { bbf = ByteBuffer.wrap(bb); cbf = CharBuffer.allocate(bb.length); } CoderResult cr = null; long t1 = System.nanoTime() / 1000; for (int i = 0; i < iteration; i++) { bbf.rewind(); cbf.clear(); dec.reset(); cr = dec.decode(bbf, cbf, true); } long t2 = System.nanoTime() / 1000; t.t = (t2 - t1) / iteration; if (cr != CoderResult.UNDERFLOW) { System.out.println("DEC-----------------"); int pos = bbf.position(); System.out.printf( " cr=%s, bbf.pos=%d, bb[pos]=%x,%x,%x,%x%n", cr.toString(), pos, bb[pos++] & 0xff, bb[pos++] & 0xff, bb[pos++] & 0xff, bb[pos++] & 0xff); throw new RuntimeException("Decoding err: " + csn); } char[] cc = new char[cbf.position()]; cbf.flip(); cbf.get(cc); return cc; }
/** * Serializes a <code>DBObject</code> into a string that can be sent to the database. * * <p>There is a pool of available encoders. Create a new one as follows: * * <blockquote> * * </pre> * * ByteEncoder encoder = ByteEncoder.get(); // try forever until an encoder is available </pre> * * </blockquote> * * <p>Each key/value pair in the <code>DBObject</code> is encoded in the following format: * * <blockquote> * * <i><type (</i><code>byte</code><i>)><name (</i><code>String</code></i>)><0 (</i> * <code>byte</code><i>)><data (serialized data)></i> * * </blockquote> * * For example: * * <blockquote> * * <<code>NUMBER</code>><name>0<double> <code>// NUMBER = 1</code><br> * <<code>STRING</code>><name>0<len><string>0 <code>// STRING = 2</code> * * </blockquote> */ public class ByteEncoder extends Bytes { static final boolean DEBUG = Boolean.getBoolean("DEBUG.BE"); // things that won't get sent in the scope static final Set<String> BAD_GLOBALS = new HashSet<String>(); static { BAD_GLOBALS.add("db"); BAD_GLOBALS.add("local"); BAD_GLOBALS.add("core"); BAD_GLOBALS.add("args"); // TODO: should we get rid of this BAD_GLOBALS.add("obj"); // TODO: get rid of this } /** * Whether a given field is generated by the db for use by the db * * @param o an object to check * @return whether the object is a db field */ public static boolean dbOnlyField(Object o) { if (o == null) return false; if (o instanceof String) return dbOnlyField(o.toString()); return false; } /** * Whether a given field is generated by the db for use by the db * * @param s a string to check * @return whether the string is a db field */ public static boolean dbOnlyField(String s) { return s.equals("_ns") || s.equals("_save") || s.equals("_update"); } /** * Fetches a new <code>ByteEncoder</code> from the pool of available <code>ByteEncoder</code>s. * * @return a new <code>ByteEncoder</code> */ public static ByteEncoder get() { return _pool.get(); } /** * Get the current position of this ByteEncoder * * @return */ public long getPosition() { return _buf.position(); } /** * Get the remaining capacity of this ByteEncoder * * @return */ public long getRemaining() { return _buf.remaining(); } /** Resets and returns this encoder to the pool. */ protected void done() { reset(); _pool.done(this); } static final SimplePool<ByteEncoder> _pool = new SimplePool<ByteEncoder>("ByteEncoders", NUM_ENCODERS, NUM_ENCODERS * 2) { protected ByteEncoder createNew() { if (D) System.out.println("creating new ByteEncoder"); return new ByteEncoder(); } protected long memSize(ByteEncoder d) { return d._buf.capacity() + (2 * MAX_STRING) + 1024; } }; // ---- private ByteEncoder() { _buf = ByteBuffer.allocateDirect(MAX_OBJECT_SIZE + 2048); _buf.order(Bytes.ORDER); } /** * Returns the bytes in the bytebuffer. Attempts to leave the bytebuffer in the same state. Note * that mark, if set, is lost. * * @return array of bytes */ public byte[] getBytes() { int pos = _buf.position(); int limit = _buf.limit(); flip(); byte[] arr = new byte[_buf.limit()]; _buf.get(arr); flip(); _buf.position(pos); _buf.limit(limit); return arr; } /** Returns encoder to its starting state, ready to encode an object. */ protected void reset() { _buf.position(0); _buf.limit(_buf.capacity()); _flipped = false; _dontRef.clear(); } /** Switches the encoder from being write-only to being read-only. */ protected void flip() { _buf.flip(); _flipped = true; } /** * Encodes a <code>DBObject</code>. This is for the higher level api calls * * <p>If encoding an object fails, the buffer will be reset to the position prior to this put call * and a BufferOverflowException will be thrown * * @param o the object to encode * @return the number of characters in the encoding */ public int putObject(DBObject o) { _buf.mark(); try { return putObject(null, o); } catch (BufferOverflowException bof) { // reset to marked offset and wipe any written data _buf.reset(); _buf.put(new byte[_buf.remaining()]); _buf.reset(); throw new BufferOverflowException(); } } /** this is really for embedded objects */ private int putObject(String name, DBObject o) { if (o == null) throw new NullPointerException("can't save a null object"); if (DEBUG) System.out.println( "putObject : " + name + " [" + o.getClass() + "]" + " # keys " + o.keySet().size()); if (_flipped) throw new IllegalStateException("already flipped"); final int start = _buf.position(); byte myType = OBJECT; if (o instanceof List) myType = ARRAY; if (_handleSpecialObjects(name, o)) return _buf.position() - start; if (name != null) { _put(myType, name); } final int sizePos = _buf.position(); _buf.putInt(0); // leaving space for this. set it at the end List transientFields = null; if (myType == OBJECT) { if (o.containsField("_id")) _putObjectField("_id", o.get("_id")); { Object temp = o.get("_transientFields"); if (temp instanceof List) transientFields = (List) temp; } } for (String s : o.keySet()) { if (s.equals("_id")) continue; if (transientFields != null && transientFields.contains(s)) continue; Object val = o.get(s); _putObjectField(s, val); } _buf.put(EOO); _buf.putInt(sizePos, _buf.position() - sizePos); return _buf.position() - start; } private void _putObjectField(String name, Object val) { if (dbOnlyField(name) || name.equals("_transientFields")) return; if (DEBUG) System.out.println("\t put thing : " + name); if (name.equals("$where") && val instanceof String) { _put(CODE, name); _putValueString(val.toString()); return; } val = Bytes.applyEncodingHooks(val); if (val == null) putNull(name); else if (val instanceof Date) putDate(name, (Date) val); else if (val instanceof Number) putNumber(name, (Number) val); else if (val instanceof String) putString(name, val.toString()); else if (val instanceof ObjectId) putObjectId(name, (ObjectId) val); else if (val instanceof DBObject) putObject(name, (DBObject) val); else if (val instanceof Boolean) putBoolean(name, (Boolean) val); else if (val instanceof Pattern) putPattern(name, (Pattern) val); else if (val instanceof DBRegex) { putDBRegex(name, (DBRegex) val); } else if (val instanceof Map) putMap(name, (Map) val); else if (val instanceof List) putList(name, (List) val); else if (val instanceof byte[]) putBinary(name, (byte[]) val); else if (val instanceof DBBinary) putBinary(name, (DBBinary) val); else if (val.getClass().isArray()) putList(name, Arrays.asList((Object[]) val)); else if (val instanceof DBPointer) { // temporary - there's the notion of "special object" , but for simple level 0... DBPointer r = (DBPointer) val; putDBPointer(name, r._ns, (ObjectId) r._id); } else if (val instanceof DBRefBase) { putDBRef(name, (DBRefBase) val); } else if (val instanceof DBSymbol) { putSymbol(name, (DBSymbol) val); } else if (val instanceof DBUndefined) { putUndefined(name); } else if (val instanceof DBTimestamp) { putTimestamp(name, (DBTimestamp) val); } else throw new IllegalArgumentException("can't serialize " + val.getClass()); } private void putList(String name, List l) { _put(ARRAY, name); final int sizePos = _buf.position(); _buf.putInt(0); for (int i = 0; i < l.size(); i++) _putObjectField(String.valueOf(i), l.get(i)); _buf.put(EOO); _buf.putInt(sizePos, _buf.position() - sizePos); } private void putMap(String name, Map m) { _put(OBJECT, name); final int sizePos = _buf.position(); _buf.putInt(0); for (Object key : m.keySet()) _putObjectField(key.toString(), m.get(key)); _buf.put(EOO); _buf.putInt(sizePos, _buf.position() - sizePos); } private boolean _handleSpecialObjects(String name, DBObject o) { if (o == null) return false; if (o instanceof DBCollection) { DBCollection c = (DBCollection) o; putDBPointer(name, c.getName(), Bytes.COLLECTION_REF_ID); return true; } if (!_dontRefContains(o) && name != null && o instanceof DBPointer) { DBPointer r = (DBPointer) o; putDBPointer(name, r._ns, (ObjectId) r._id); return true; } if (!(o instanceof List) && o.get(Bytes.NO_REF_HACK) != null) { o.removeField(Bytes.NO_REF_HACK); return false; } if (!_dontRefContains(o) && name != null && !(o instanceof List) && cameFromDB(o)) { putDBPointer(name, o.get("_ns").toString(), (ObjectId) (o.get("_id"))); return true; } return false; } protected int putNull(String name) { int start = _buf.position(); _put(NULL, name); return _buf.position() - start; } protected int putUndefined(String name) { int start = _buf.position(); _put(UNDEFINED, name); return _buf.position() - start; } protected int putTimestamp(String name, DBTimestamp ts) { int start = _buf.position(); _put(TIMESTAMP, name); _buf.putInt(ts.getTime()); _buf.putInt(ts.getInc()); return _buf.position() - start; } protected int putBoolean(String name, Boolean b) { int start = _buf.position(); _put(BOOLEAN, name); _buf.put(b ? (byte) 0x1 : (byte) 0x0); return _buf.position() - start; } protected int putDate(String name, Date d) { int start = _buf.position(); _put(DATE, name); _buf.putLong(d.getTime()); return _buf.position() - start; } protected int putNumber(String name, Number n) { int start = _buf.position(); if (n instanceof Integer) { _put(NUMBER_INT, name); _buf.putInt(n.intValue()); } else if (n instanceof Long) { _put(NUMBER_LONG, name); _buf.putLong(n.longValue()); } else { _put(NUMBER, name); _buf.putDouble(n.doubleValue()); } return _buf.position() - start; } protected void putBinary(String name, byte[] data) { _put(BINARY, name); _buf.putInt(4 + data.length); _buf.put(B_BINARY); _buf.putInt(data.length); int before = _buf.position(); _buf.put(data); int after = _buf.position(); com.mongodb.util.MyAsserts.assertEquals(after - before, data.length); } protected void putBinary(String name, DBBinary val) { _put(BINARY, name); _buf.putInt(val._data.length); _buf.put(val._type); _buf.put(val._data); } protected int putSymbol(String name, DBSymbol s) { return _putString(name, s.getSymbol(), SYMBOL); } protected int putString(String name, String s) { return _putString(name, s, STRING); } private int _putString(String name, String s, byte type) { int start = _buf.position(); _put(type, name); _putValueString(s); return _buf.position() - start; } protected int putObjectId(String name, ObjectId oid) { int start = _buf.position(); _put(OID, name); _buf.putInt(oid._time); _buf.putInt(oid._machine); _buf.putInt(oid._inc); return _buf.position() - start; } protected int putDBPointer(String name, String ns, ObjectId oid) { int start = _buf.position(); _put(REF, name); _putValueString(ns); _buf.putInt(oid._time); _buf.putInt(oid._machine); _buf.putInt(oid._inc); return _buf.position() - start; } protected void putDBRef(String name, DBRefBase ref) { _put(OBJECT, name); final int sizePos = _buf.position(); _buf.putInt(0); _putObjectField("$ref", ref.getRef()); _putObjectField("$id", ref.getId()); _buf.put(EOO); _buf.putInt(sizePos, _buf.position() - sizePos); } private int putDBRegex(String name, DBRegex regex) { int start = _buf.position(); _put(REGEX, name); _put(regex.getPattern()); String options = regex.getOptions(); TreeMap<Character, Character> sm = new TreeMap<Character, Character>(); for (int i = 0; i < options.length(); i++) { sm.put(options.charAt(i), options.charAt(i)); } StringBuffer sb = new StringBuffer(); for (char c : sm.keySet()) { sb.append(c); } _put(sb.toString()); return _buf.position() - start; } private int putPattern(String name, Pattern p) { int start = _buf.position(); _put(REGEX, name); _put(p.pattern()); _put(patternFlags(p.flags())); return _buf.position() - start; } // ---------------------------------------------- /** Encodes the type and key. */ private void _put(byte type, String name) { _buf.put(type); _put(name); } void _putValueString(String s) { int lenPos = _buf.position(); _buf.putInt(0); // making space for size int strLen = _put(s); _buf.putInt(lenPos, strLen); } int _put(String name) { _cbuf.position(0); _cbuf.limit(_cbuf.capacity()); _cbuf.append(name); _cbuf.flip(); final int start = _buf.position(); _encoder.encode(_cbuf, _buf, false); _buf.put((byte) 0); return _buf.position() - start; } boolean _dontRefContains(Object o) { if (_dontRef.size() == 0) return false; return _dontRef.peek().contains(o); } private final CharBuffer _cbuf = CharBuffer.allocate(MAX_STRING); private final CharsetEncoder _encoder = _utf8.newEncoder(); private Stack<IdentitySet> _dontRef = new Stack<IdentitySet>(); private boolean _flipped = false; final ByteBuffer _buf; }
// we assume out is large enough for this conversion // returns number of filled chars in out buffer public int convert(byte[] in, int inOffset, int inLength, char[] out) { final ByteBuffer inBuffer = ByteBuffer.wrap(in, inOffset, inLength); final CharBuffer outBuffer = CharBuffer.wrap(out, 0, out.length); myDecoder.decode(inBuffer, outBuffer, false); return outBuffer.position(); }
static void test(Charset cs, char[] bmpCA, byte[] sbBA) throws Throwable { String bmpStr = new String(bmpCA); CharsetDecoder dec = cs.newDecoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); CharsetEncoder enc = cs.newEncoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); // getBytes(csn); byte[] baSC = bmpStr.getBytes(cs.name()); ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(bmpCA)); byte[] baNIO = new byte[bf.limit()]; bf.get(baNIO, 0, baNIO.length); if (!Arrays.equals(baSC, baNIO)) throw new RuntimeException("getBytes(csn) failed -> " + cs.name()); // getBytes(cs); baSC = bmpStr.getBytes(cs); if (!Arrays.equals(baSC, baNIO)) throw new RuntimeException("getBytes(cs) failed -> " + cs.name()); // new String(csn); String strSC = new String(sbBA, cs.name()); String strNIO = dec.reset().decode(ByteBuffer.wrap(sbBA)).toString(); if (!strNIO.equals(strSC)) throw new RuntimeException("new String(csn) failed -> " + cs.name()); // new String(cs); strSC = new String(sbBA, cs); if (!strNIO.equals(strSC)) throw new RuntimeException("new String(cs) failed -> " + cs.name()); // encode unmappable surrogates if (enc instanceof sun.nio.cs.ArrayEncoder && cs.contains(Charset.forName("ASCII"))) { if (cs.name().equals("UTF-8") || // utf8 handles surrogates cs.name().equals("CESU-8")) // utf8 handles surrogates return; enc.replaceWith(new byte[] {(byte) 'A'}); sun.nio.cs.ArrayEncoder cae = (sun.nio.cs.ArrayEncoder) enc; String str = "ab\uD800\uDC00\uD800\uDC00cd"; byte[] ba = new byte[str.length() - 2]; int n = cae.encode(str.toCharArray(), 0, str.length(), ba); if (n != 6 || !"abAAcd".equals(new String(ba, cs.name()))) throw new RuntimeException("encode1(surrogates) failed -> " + cs.name()); ba = new byte[str.length()]; n = cae.encode(str.toCharArray(), 0, str.length(), ba); if (n != 6 || !"abAAcd".equals(new String(ba, 0, n, cs.name()))) throw new RuntimeException("encode2(surrogates) failed -> " + cs.name()); str = "ab\uD800B\uDC00Bcd"; ba = new byte[str.length()]; n = cae.encode(str.toCharArray(), 0, str.length(), ba); if (n != 8 || !"abABABcd".equals(new String(ba, 0, n, cs.name()))) throw new RuntimeException("encode3(surrogates) failed -> " + cs.name()); /* sun.nio.cs.ArrayDeEncoder works on the assumption that the invoker (StringCoder) allocates enough output buf, utf8 and double-byte coder does not check the output buffer limit. ba = new byte[str.length() - 1]; n = cae.encode(str.toCharArray(), 0, str.length(), ba); if (n != 7 || !"abABABc".equals(new String(ba, 0, n, cs.name()))) { throw new RuntimeException("encode4(surrogates) failed -> " + cs.name()); } */ } }