forked from Qortal/qortal
Improved metadata trimming, to better handle multibyte UTF-8 characters.
This commit is contained in:
parent
46e2e1043d
commit
45bc2e46d6
@ -7,6 +7,7 @@ import org.qortal.arbitrary.misc.Category;
|
|||||||
import org.qortal.repository.DataException;
|
import org.qortal.repository.DataException;
|
||||||
import org.qortal.utils.Base58;
|
import org.qortal.utils.Base58;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -217,6 +218,25 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
|||||||
|
|
||||||
// Static helper methods
|
// Static helper methods
|
||||||
|
|
||||||
|
public static String trimUTF8String(String string, int maxLength) {
|
||||||
|
byte[] inputBytes = string.getBytes(StandardCharsets.UTF_8);
|
||||||
|
int length = Math.min(inputBytes.length, maxLength);
|
||||||
|
byte[] outputBytes = new byte[length];
|
||||||
|
|
||||||
|
System.arraycopy(inputBytes, 0, outputBytes, 0, length);
|
||||||
|
String result = new String(outputBytes, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
// check if last character is truncated
|
||||||
|
int lastIndex = result.length() - 1;
|
||||||
|
|
||||||
|
if (lastIndex > 0 && result.charAt(lastIndex) != string.charAt(lastIndex)) {
|
||||||
|
// last character is truncated so remove the last character
|
||||||
|
return result.substring(0, lastIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static String limitTitle(String title) {
|
public static String limitTitle(String title) {
|
||||||
if (title == null) {
|
if (title == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -225,7 +245,7 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return title.substring(0, Math.min(title.length(), MAX_TITLE_LENGTH));
|
return trimUTF8String(title, MAX_TITLE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String limitDescription(String description) {
|
public static String limitDescription(String description) {
|
||||||
@ -236,7 +256,7 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return description.substring(0, Math.min(description.length(), MAX_DESCRIPTION_LENGTH));
|
return trimUTF8String(description, MAX_DESCRIPTION_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> limitTags(List<String> tags) {
|
public static List<String> limitTags(List<String> tags) {
|
||||||
|
@ -248,6 +248,47 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUTF8Metadata() throws DataException, IOException, MissingDataException {
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
|
||||||
|
String publicKey58 = Base58.encode(alice.getPublicKey());
|
||||||
|
String name = "TEST"; // Can be anything for this test
|
||||||
|
String identifier = null; // Not used for this test
|
||||||
|
Service service = Service.ARBITRARY_DATA;
|
||||||
|
int chunkSize = 100;
|
||||||
|
int dataLength = 900; // Actual data length will be longer due to encryption
|
||||||
|
|
||||||
|
// Example (modified) strings from real world content
|
||||||
|
String title = "Доля юаня в трансграничных Доля юаня в трансграничных";
|
||||||
|
String description = "Когда рыночек порешал";
|
||||||
|
List<String> tags = Arrays.asList("Доля", "юаня", "трансграничных");
|
||||||
|
Category category = Category.OTHER;
|
||||||
|
|
||||||
|
// Register the name to Alice
|
||||||
|
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "");
|
||||||
|
transactionData.setFee(new RegisterNameTransaction(null, null).getUnitFee(transactionData.getTimestamp()));
|
||||||
|
TransactionUtils.signAndMint(repository, transactionData, alice);
|
||||||
|
|
||||||
|
// Create PUT transaction
|
||||||
|
Path path1 = ArbitraryUtils.generateRandomDataPath(dataLength);
|
||||||
|
ArbitraryDataFile arbitraryDataFile = ArbitraryUtils.createAndMintTxn(repository, publicKey58, path1, name,
|
||||||
|
identifier, ArbitraryTransactionData.Method.PUT, service, alice, chunkSize, 0L, true,
|
||||||
|
title, description, tags, category);
|
||||||
|
|
||||||
|
// Check the chunk count is correct
|
||||||
|
assertEquals(10, arbitraryDataFile.chunkCount());
|
||||||
|
|
||||||
|
// Check the metadata is correct
|
||||||
|
String expectedTrimmedTitle = "Доля юаня в трансграничных Доля юаня в тран";
|
||||||
|
assertEquals(expectedTrimmedTitle, arbitraryDataFile.getMetadata().getTitle());
|
||||||
|
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
||||||
|
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
||||||
|
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
||||||
|
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMetadataLengths() throws DataException, IOException, MissingDataException {
|
public void testMetadataLengths() throws DataException, IOException, MissingDataException {
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user