net.sf.jasperreports.engine.virtualization.StringSerializer Maven / Gradle / Ivy
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see .
*/
package net.sf.jasperreports.engine.virtualization;
import java.io.IOException;
import net.sf.jasperreports.engine.JRRuntimeException;
/**
* @author Lucian Chirita ([email protected])
*/
public class StringSerializer implements ObjectSerializer
{
public static final String EXCEPTION_MESSAGE_KEY_CHUNK_UNEXPECTED_LENGTH = "virtualization.chunk.unexpected.length";
public static final String EXCEPTION_MESSAGE_KEY_CHUNK_UNEXPECTED_LENGTH_REMAINING = "virtualization.chunk.unexpected.length.remaining";
// smaller than 65535/3, see writeUTF
private static final int CHUNK_SIZE = 20000;
@Override
public int typeValue()
{
return SerializationConstants.OBJECT_TYPE_STRING;
}
@Override
public ReferenceType defaultReferenceType()
{
return ReferenceType.OBJECT;
}
@Override
public boolean defaultStoreReference()
{
return true;
}
@Override
public void write(String value, VirtualizationOutput out) throws IOException
{
int length = value.length();
if (length < CHUNK_SIZE)
{
out.writeUTF(value);
}
else
{
out.writeUTF(value.substring(0, CHUNK_SIZE));
// writing the length so that we know when to stop in read()
out.writeInt(length);
for (int index = CHUNK_SIZE; index < length; index += CHUNK_SIZE)
{
out.writeUTF(value.substring(index, Math.min(length, index + CHUNK_SIZE)));
}
}
}
@Override
public String read(VirtualizationInput in) throws IOException
{
//TODO write some unit tests
String chunk = in.readUTF();
int chunkLength = chunk.length();
if (chunkLength < CHUNK_SIZE)
{
// single chunk
return chunk;
}
// should be of exact max chunk size
if (chunkLength != CHUNK_SIZE)
{
throw
new JRRuntimeException(
EXCEPTION_MESSAGE_KEY_CHUNK_UNEXPECTED_LENGTH,
new Object[]{chunkLength});
}
// we have several chunks, read the length
int length = in.readInt();
if (length < CHUNK_SIZE)
{
throw
new JRRuntimeException(
EXCEPTION_MESSAGE_KEY_CHUNK_UNEXPECTED_LENGTH,
new Object[]{length});
}
//FIXME check against an upper limit to prevent memory being allocated when the data is corrupted?
char[] chars = new char[length];
chunk.getChars(0, chunkLength, chars, 0);
int remaining = length - chunkLength;
while (remaining > 0)
{
chunk = in.readUTF();
chunkLength = chunk.length();
if (chunkLength < CHUNK_SIZE)
{
// we should be on the last chunk
if (chunkLength != remaining)
{
throw
new JRRuntimeException(
EXCEPTION_MESSAGE_KEY_CHUNK_UNEXPECTED_LENGTH_REMAINING,
new Object[]{chunkLength, remaining});
}
}
else if (chunkLength != CHUNK_SIZE)
{
// should be of exact max chunk size
throw
new JRRuntimeException(
EXCEPTION_MESSAGE_KEY_CHUNK_UNEXPECTED_LENGTH,
new Object[]{chunkLength});
}
chunk.getChars(0, chunkLength, chars, length - remaining);
remaining -= chunkLength;
}
return new String(chars);
}
}