Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot copy long text to clipboard #1166

Open
yososs opened this issue Jan 13, 2023 · 3 comments
Open

Cannot copy long text to clipboard #1166

yososs opened this issue Jan 13, 2023 · 3 comments

Comments

@yososs
Copy link

yososs commented Jan 13, 2023

Exception thrown from writeUTF method.

@Override
public void encode(DataOutputStream os, String s) throws IOException {
os.writeUTF(s);
}
@Override
public String decode(DataInputStream is) throws IOException {
return is.readUTF();
}
};

See the following JavaDoc.

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/DataOutputStream.html#writeUTF(java.lang.String)

Throws:
UTFDataFormatException - if the modified UTF-8 encoding of str would exceed 65535 bytes in length

@Jugen
Copy link
Collaborator

Jugen commented Jan 15, 2023

Thank you for reporting, Pull Requests are welcome :-)

@yososs
Copy link
Author

yososs commented Jan 20, 2023

I propose this modified code.

This fix extends the string encoding/decoding limit of 65,535( Modified UTF-8) bytes
to the maximum number of elements in a char array in Java.

Note that this implementation is UTF-16 encoded and therefore memory inefficient.
Standard UTF-8 encoding/decoding may not pass the test due to code point changes.
Modified UTF-8 encoding may work around this, but
Modified code would not be simple.

Codec.java

	static final Codec<String> STRING_CODEC = new Codec<String>() {

		@Override
		public String getName() {
			return "string";
		}

		@Override
		public void encode(DataOutputStream os, String s) throws IOException {
//    		os.writeUTF(s);
			os.writeInt(s.length());
			os.writeChars(s);
		}

		@Override
		public String decode(DataInputStream is) throws IOException {
//            return is.readUTF();

			final int len = is.readInt();
			final char[] chars = new char[len];
			for (int i = 0; i < len; i++) {
				chars[i] = is.readChar();
			}
			return String.valueOf(chars);
		}
	};

CodecTest.java

public class CodecTest {

	@Test
	public void testStringCodec() throws IOException {

		final String[] testDatas = new String[2];
		Arrays.setAll(testDatas, i -> createTestString());

		final ByteArrayOutputStream bout = new ByteArrayOutputStream();
		try (final DataOutputStream out = new DataOutputStream(bout)) {
			for (final String str : testDatas) {
				Codec.STRING_CODEC.encode(out, str);
			}
		}
		final byte[] encoded = bout.toByteArray();

		try (final DataInputStream ins = new DataInputStream(new ByteArrayInputStream(encoded))) {
			for (final String expected : testDatas) {
				Assert.assertEquals(expected, Codec.STRING_CODEC.decode(ins));
			}
			Assert.assertTrue(ins.read() < 0);
		}

	}

	private static String createTestString() {
		final Random r = new Random();
		final StringBuilder buf = new StringBuilder();
		while (buf.length() <= 0xffff && buf.toString().getBytes(StandardCharsets.UTF_8).length <= 0xffff) {
			final int cp = r.nextInt(0x20, 0x10FFF);
			if (Character.isDefined(cp)) {
				buf.appendCodePoint(cp);
			}
		}
		return buf.toString();
	}

	@Test
	public void testStringCodec_empty() throws IOException {

		final String testData = "";

		final ByteArrayOutputStream bout = new ByteArrayOutputStream();
		try (final DataOutputStream out = new DataOutputStream(bout)) {
			Codec.STRING_CODEC.encode(out, testData);
		}
		final byte[] encoded = bout.toByteArray();

		try (final DataInputStream ins = new DataInputStream(new ByteArrayInputStream(encoded))) {
			Assert.assertEquals(testData, Codec.STRING_CODEC.decode(ins));
			Assert.assertTrue(ins.read() < 0);
		}
	}
}

@xdsswar
Copy link

xdsswar commented Feb 23, 2023

This issue happens to me long ago (not with this library) and I fixed it just by using this line
yourString.replace("\0", "");
This will replace all your NULL (0x00) values in the content. I belive this happens because the way the String is handled by the native code and the NULL termination, So looks like when you copy all content the System thinks the String ends at the first NULL (0x00> value, and that's all you get into the clip board. Try replace("\0", "") and let me know if that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants