protected int writeString(String str)
   throws IOException {
    int strlen = str.length();
    int utflen = 0;
    char[] charr = new char[strlen];
    int c, count = 0;

    str.getChars(0, strlen, charr, 0);

    // check the length of the UTF-encoded string
    for (int i = 0; i < strlen; i++) {
      c = charr[i];
      if ((c >= 0x0001) && (c <= 0x007F)) {
        utflen++;
      } else if (c > 0x07FF) {
        utflen += 3;
      } else {
        utflen += 2;
      }
    }

    /**
     * if utf-encoded String is < 64K, use the "String" data type, with a
     * two-byte prefix specifying string length; otherwise use the "Long String"
     * data type, withBUG#298 a four-byte prefix
     */
    byte[] bytearr;
    if (utflen <= 65535) {
      outputStream.writeByte(AMF0Body.DATA_TYPE_STRING);
      bytearr = new byte[utflen+2];
    } else {
      outputStream.writeByte(AMF0Body.DATA_TYPE_LONG_STRING);
      bytearr = new byte[utflen+4];
      bytearr[count++] = (byte) ((utflen >>> 24) & 0xFF);
      bytearr[count++] = (byte) ((utflen >>> 16) & 0xFF);
    }

    bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
    bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
    for (int i = 0; i < strlen; i++) {
      c = charr[i];
      if ((c >= 0x0001) && (c <= 0x007F)) {
        bytearr[count++] = (byte) c;
      } else if (c > 0x07FF) {
        bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
        bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));
        bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
      } else {
        bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
        bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
      }
    }

    outputStream.write(bytearr);
    return utflen + 2;
  }