mirror of https://github.com/apache/poi.git
Remove unnecessary cast and reformat some code a bit
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1771247 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f656e74c4b
commit
f2975b1e5f
|
@ -32,7 +32,7 @@ public class WorkingWithRichText {
|
||||||
XSSFWorkbook wb = new XSSFWorkbook(); //or new HSSFWorkbook();
|
XSSFWorkbook wb = new XSSFWorkbook(); //or new HSSFWorkbook();
|
||||||
try {
|
try {
|
||||||
XSSFSheet sheet = wb.createSheet();
|
XSSFSheet sheet = wb.createSheet();
|
||||||
XSSFRow row = sheet.createRow((short) 2);
|
XSSFRow row = sheet.createRow(2);
|
||||||
|
|
||||||
XSSFCell cell = row.createCell(1);
|
XSSFCell cell = row.createCell(1);
|
||||||
XSSFRichTextString rt = new XSSFRichTextString("The quick brown fox");
|
XSSFRichTextString rt = new XSSFRichTextString("The quick brown fox");
|
||||||
|
@ -53,7 +53,7 @@ public class WorkingWithRichText {
|
||||||
rt.append(" Jumped over the lazy dog", font3);
|
rt.append(" Jumped over the lazy dog", font3);
|
||||||
|
|
||||||
cell.setCellValue(rt);
|
cell.setCellValue(rt);
|
||||||
|
|
||||||
// Write the output to a file
|
// Write the output to a file
|
||||||
OutputStream fileOut = new FileOutputStream("xssf-richtext.xlsx");
|
OutputStream fileOut = new FileOutputStream("xssf-richtext.xlsx");
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -28,78 +28,68 @@ import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
public final class ComplexFileTable
|
public final class ComplexFileTable {
|
||||||
{
|
private static final byte GRPPRL_TYPE = 1;
|
||||||
|
private static final byte TEXT_PIECE_TABLE_TYPE = 2;
|
||||||
|
|
||||||
private static final byte GRPPRL_TYPE = 1;
|
protected TextPieceTable _tpt;
|
||||||
private static final byte TEXT_PIECE_TABLE_TYPE = 2;
|
|
||||||
|
|
||||||
protected TextPieceTable _tpt;
|
private SprmBuffer[] _grpprls;
|
||||||
|
|
||||||
private SprmBuffer[] _grpprls;
|
public ComplexFileTable() {
|
||||||
|
_tpt = new TextPieceTable();
|
||||||
public ComplexFileTable()
|
}
|
||||||
{
|
|
||||||
_tpt = new TextPieceTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ComplexFileTable(byte[] documentStream, byte[] tableStream, int offset, int fcMin) throws IOException
|
public ComplexFileTable(byte[] documentStream, byte[] tableStream, int offset, int fcMin) throws IOException {
|
||||||
{
|
//skips through the prms before we reach the piece table. These contain data
|
||||||
//skips through the prms before we reach the piece table. These contain data
|
//for actual fast saved files
|
||||||
//for actual fast saved files
|
|
||||||
List<SprmBuffer> sprmBuffers = new LinkedList<SprmBuffer>();
|
List<SprmBuffer> sprmBuffers = new LinkedList<SprmBuffer>();
|
||||||
while ( tableStream[offset] == GRPPRL_TYPE )
|
while (tableStream[offset] == GRPPRL_TYPE) {
|
||||||
{
|
|
||||||
offset++;
|
offset++;
|
||||||
int size = LittleEndian.getShort( tableStream, offset );
|
int size = LittleEndian.getShort(tableStream, offset);
|
||||||
offset += LittleEndian.SHORT_SIZE;
|
offset += LittleEndian.SHORT_SIZE;
|
||||||
byte[] bs = LittleEndian.getByteArray( tableStream, offset, size );
|
byte[] bs = LittleEndian.getByteArray(tableStream, offset, size);
|
||||||
offset += size;
|
offset += size;
|
||||||
|
|
||||||
SprmBuffer sprmBuffer = new SprmBuffer( bs, false, 0 );
|
SprmBuffer sprmBuffer = new SprmBuffer(bs, false, 0);
|
||||||
sprmBuffers.add( sprmBuffer );
|
sprmBuffers.add(sprmBuffer);
|
||||||
}
|
}
|
||||||
this._grpprls = sprmBuffers.toArray( new SprmBuffer[sprmBuffers.size()] );
|
this._grpprls = sprmBuffers.toArray(new SprmBuffer[sprmBuffers.size()]);
|
||||||
|
|
||||||
if(tableStream[offset] != TEXT_PIECE_TABLE_TYPE)
|
if (tableStream[offset] != TEXT_PIECE_TABLE_TYPE) {
|
||||||
{
|
throw new IOException("The text piece table is corrupted");
|
||||||
throw new IOException("The text piece table is corrupted");
|
}
|
||||||
|
int pieceTableSize = LittleEndian.getInt(tableStream, ++offset);
|
||||||
|
offset += LittleEndian.INT_SIZE;
|
||||||
|
_tpt = new TextPieceTable(documentStream, tableStream, offset, pieceTableSize, fcMin);
|
||||||
}
|
}
|
||||||
int pieceTableSize = LittleEndian.getInt(tableStream, ++offset);
|
|
||||||
offset += LittleEndian.INT_SIZE;
|
|
||||||
_tpt = new TextPieceTable(documentStream, tableStream, offset, pieceTableSize, fcMin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextPieceTable getTextPieceTable()
|
public TextPieceTable getTextPieceTable() {
|
||||||
{
|
return _tpt;
|
||||||
return _tpt;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public SprmBuffer[] getGrpprls()
|
public SprmBuffer[] getGrpprls() {
|
||||||
{
|
|
||||||
return _grpprls;
|
return _grpprls;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void writeTo( HWPFFileSystem sys ) throws IOException
|
public void writeTo(HWPFFileSystem sys) throws IOException {
|
||||||
{
|
HWPFOutputStream docStream = sys.getStream("WordDocument");
|
||||||
HWPFOutputStream docStream = sys.getStream( "WordDocument" );
|
HWPFOutputStream tableStream = sys.getStream("1Table");
|
||||||
HWPFOutputStream tableStream = sys.getStream( "1Table" );
|
|
||||||
|
|
||||||
writeTo( docStream, tableStream );
|
writeTo(docStream, tableStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo( HWPFOutputStream wordDocumentStream,
|
public void writeTo(HWPFOutputStream wordDocumentStream,
|
||||||
HWPFOutputStream tableStream ) throws IOException
|
HWPFOutputStream tableStream) throws IOException {
|
||||||
{
|
tableStream.write(TEXT_PIECE_TABLE_TYPE);
|
||||||
tableStream.write( TEXT_PIECE_TABLE_TYPE );
|
|
||||||
|
|
||||||
byte[] table = _tpt.writeTo( wordDocumentStream );
|
byte[] table = _tpt.writeTo(wordDocumentStream);
|
||||||
|
|
||||||
byte[] numHolder = new byte[LittleEndian.INT_SIZE];
|
byte[] numHolder = new byte[LittleEndian.INT_SIZE];
|
||||||
LittleEndian.putInt( numHolder, 0, table.length );
|
LittleEndian.putInt(numHolder, 0, table.length);
|
||||||
tableStream.write( numHolder );
|
tableStream.write(numHolder);
|
||||||
tableStream.write( table );
|
tableStream.write(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,27 +41,23 @@ import org.apache.poi.util.LittleEndian;
|
||||||
* @author Ryan Ackley
|
* @author Ryan Ackley
|
||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public abstract class FormattedDiskPage
|
public abstract class FormattedDiskPage {
|
||||||
{
|
|
||||||
protected byte[] _fkp;
|
protected byte[] _fkp;
|
||||||
protected int _crun;
|
protected int _crun;
|
||||||
protected int _offset;
|
protected int _offset;
|
||||||
|
|
||||||
|
public FormattedDiskPage() {
|
||||||
public FormattedDiskPage()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses a 512-byte array to create a FKP
|
* Uses a 512-byte array to create a FKP
|
||||||
*/
|
*/
|
||||||
public FormattedDiskPage(byte[] documentStream, int offset)
|
public FormattedDiskPage(byte[] documentStream, int offset) {
|
||||||
{
|
|
||||||
_crun = LittleEndian.getUByte(documentStream, offset + 511);
|
_crun = LittleEndian.getUByte(documentStream, offset + 511);
|
||||||
_fkp = documentStream;
|
_fkp = documentStream;
|
||||||
_offset = offset;
|
_offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to get a text offset corresponding to a grpprl in this fkp.
|
* Used to get a text offset corresponding to a grpprl in this fkp.
|
||||||
* @param index The index of the property in this FKP
|
* @param index The index of the property in this FKP
|
||||||
|
@ -71,6 +67,7 @@ public abstract class FormattedDiskPage
|
||||||
{
|
{
|
||||||
return LittleEndian.getInt(_fkp, _offset + (index * 4));
|
return LittleEndian.getInt(_fkp, _offset + (index * 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to get the end of the text corresponding to a grpprl in this fkp.
|
* Used to get the end of the text corresponding to a grpprl in this fkp.
|
||||||
* @param index The index of the property in this fkp.
|
* @param index The index of the property in this fkp.
|
||||||
|
@ -80,6 +77,7 @@ public abstract class FormattedDiskPage
|
||||||
{
|
{
|
||||||
return LittleEndian.getInt(_fkp, _offset + ((index + 1) * 4));
|
return LittleEndian.getInt(_fkp, _offset + ((index + 1) * 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to get the total number of grrprl's stored int this FKP
|
* Used to get the total number of grrprl's stored int this FKP
|
||||||
* @return The number of grpprls in this FKP
|
* @return The number of grpprls in this FKP
|
||||||
|
|
|
@ -25,178 +25,148 @@ import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plex of CPs stored in File (PLCF)
|
* Plex of CPs stored in File (PLCF)
|
||||||
*
|
* <p>
|
||||||
* common data structure in a Word file. Contains an array of 4 byte ints in the
|
* common data structure in a Word file. Contains an array of 4 byte ints in the
|
||||||
* front that relate to an array of arbitrary data structures in the back.
|
* front that relate to an array of arbitrary data structures in the back.
|
||||||
*
|
* <p>
|
||||||
* See page 184 of official documentation for details
|
* See page 184 of official documentation for details
|
||||||
*
|
*
|
||||||
* @author Ryan Ackley
|
* @author Ryan Ackley
|
||||||
*/
|
*/
|
||||||
public final class PlexOfCps
|
public final class PlexOfCps {
|
||||||
{
|
|
||||||
private int _iMac;
|
private int _iMac;
|
||||||
private int _offset;
|
private int _offset;
|
||||||
private int _cbStruct;
|
private int _cbStruct;
|
||||||
private List<GenericPropertyNode> _props;
|
private List<GenericPropertyNode> _props;
|
||||||
|
|
||||||
public PlexOfCps( int sizeOfStruct )
|
public PlexOfCps(int sizeOfStruct) {
|
||||||
{
|
|
||||||
_props = new ArrayList<GenericPropertyNode>();
|
_props = new ArrayList<GenericPropertyNode>();
|
||||||
_cbStruct = sizeOfStruct;
|
_cbStruct = sizeOfStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param cb
|
* @param cb The size of PLCF in bytes
|
||||||
* The size of PLCF in bytes
|
* @param cbStruct The size of the data structure type stored in this PlexOfCps.
|
||||||
* @param cbStruct
|
|
||||||
* The size of the data structure type stored in this PlexOfCps.
|
|
||||||
*/
|
*/
|
||||||
public PlexOfCps( byte[] buf, int start, int cb, int cbStruct )
|
public PlexOfCps(byte[] buf, int start, int cb, int cbStruct) {
|
||||||
{
|
|
||||||
// Figure out the number we hold
|
// Figure out the number we hold
|
||||||
_iMac = ( cb - 4 ) / ( 4 + cbStruct );
|
_iMac = (cb - 4) / (4 + cbStruct);
|
||||||
|
|
||||||
_cbStruct = cbStruct;
|
_cbStruct = cbStruct;
|
||||||
_props = new ArrayList<GenericPropertyNode>( _iMac );
|
_props = new ArrayList<GenericPropertyNode>(_iMac);
|
||||||
|
|
||||||
for ( int x = 0; x < _iMac; x++ )
|
for (int x = 0; x < _iMac; x++) {
|
||||||
{
|
_props.add(getProperty(x, buf, start));
|
||||||
_props.add( getProperty( x, buf, start ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
void adjust( int startCp, int shift )
|
void adjust(int startCp, int shift) {
|
||||||
{
|
for (GenericPropertyNode node : _props) {
|
||||||
for ( GenericPropertyNode node : _props )
|
if (node.getStart() > startCp) {
|
||||||
{
|
if (node.getStart() + shift < startCp) {
|
||||||
if ( node.getStart() > startCp )
|
node.setStart(startCp);
|
||||||
{
|
} else {
|
||||||
if ( node.getStart() + shift < startCp )
|
node.setStart(node.getStart() + shift);
|
||||||
{
|
|
||||||
node.setStart( startCp );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node.setStart( node.getStart() + shift );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( node.getEnd() >= startCp )
|
if (node.getEnd() >= startCp) {
|
||||||
{
|
if (node.getEnd() + shift < startCp) {
|
||||||
if ( node.getEnd() + shift < startCp )
|
node.setEnd(startCp);
|
||||||
{
|
} else {
|
||||||
node.setEnd( startCp );
|
node.setEnd(node.getEnd() + shift);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node.setEnd( node.getEnd() + shift );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GenericPropertyNode getProperty( int index )
|
public GenericPropertyNode getProperty(int index) {
|
||||||
{
|
return _props.get(index);
|
||||||
return _props.get( index );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addProperty( GenericPropertyNode node )
|
public void addProperty(GenericPropertyNode node) {
|
||||||
{
|
_props.add(node);
|
||||||
_props.add( node );
|
|
||||||
_iMac++;
|
_iMac++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove( int index )
|
void remove(int index) {
|
||||||
{
|
_props.remove(index);
|
||||||
_props.remove( index );
|
|
||||||
_iMac--;
|
_iMac--;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toByteArray()
|
public byte[] toByteArray() {
|
||||||
{
|
|
||||||
int size = _props.size();
|
int size = _props.size();
|
||||||
int cpBufSize = ( ( size + 1 ) * LittleEndian.INT_SIZE );
|
int cpBufSize = ((size + 1) * LittleEndian.INT_SIZE);
|
||||||
int structBufSize = +( _cbStruct * size );
|
int structBufSize = +(_cbStruct * size);
|
||||||
int bufSize = cpBufSize + structBufSize;
|
int bufSize = cpBufSize + structBufSize;
|
||||||
|
|
||||||
byte[] buf = new byte[bufSize];
|
byte[] buf = new byte[bufSize];
|
||||||
|
|
||||||
GenericPropertyNode node = null;
|
GenericPropertyNode node = null;
|
||||||
for ( int x = 0; x < size; x++ )
|
for (int x = 0; x < size; x++) {
|
||||||
{
|
node = _props.get(x);
|
||||||
node = _props.get( x );
|
|
||||||
|
|
||||||
// put the starting offset of the property into the plcf.
|
// put the starting offset of the property into the plcf.
|
||||||
LittleEndian.putInt( buf, ( LittleEndian.INT_SIZE * x ),
|
LittleEndian.putInt(buf, (LittleEndian.INT_SIZE * x),
|
||||||
node.getStart() );
|
node.getStart());
|
||||||
|
|
||||||
// put the struct into the plcf
|
// put the struct into the plcf
|
||||||
System.arraycopy( node.getBytes(), 0, buf, cpBufSize
|
System.arraycopy(node.getBytes(), 0, buf, cpBufSize
|
||||||
+ ( x * _cbStruct ), _cbStruct );
|
+ (x * _cbStruct), _cbStruct);
|
||||||
}
|
}
|
||||||
// put the ending offset of the last property into the plcf.
|
// put the ending offset of the last property into the plcf.
|
||||||
LittleEndian.putInt( buf, LittleEndian.INT_SIZE * size, node.getEnd() );
|
LittleEndian.putInt(buf, LittleEndian.INT_SIZE * size, node.getEnd());
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private GenericPropertyNode getProperty( int index, byte[] buf, int offset )
|
private GenericPropertyNode getProperty(int index, byte[] buf, int offset) {
|
||||||
{
|
int start = LittleEndian.getInt(buf, offset + getIntOffset(index));
|
||||||
int start = LittleEndian.getInt( buf, offset + getIntOffset( index ) );
|
int end = LittleEndian.getInt(buf, offset + getIntOffset(index + 1));
|
||||||
int end = LittleEndian.getInt( buf, offset + getIntOffset( index + 1 ) );
|
|
||||||
|
|
||||||
byte[] struct = new byte[_cbStruct];
|
byte[] struct = new byte[_cbStruct];
|
||||||
System.arraycopy( buf, offset + getStructOffset( index ), struct, 0,
|
System.arraycopy(buf, offset + getStructOffset(index), struct, 0,
|
||||||
_cbStruct );
|
_cbStruct);
|
||||||
|
|
||||||
return new GenericPropertyNode( start, end, struct );
|
return new GenericPropertyNode(start, end, struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getIntOffset( int index )
|
private int getIntOffset(int index) {
|
||||||
{
|
|
||||||
return index * 4;
|
return index * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the number of data structures in this PlexofCps.
|
* returns the number of data structures in this PlexofCps.
|
||||||
*
|
*
|
||||||
* @return The number of data structures in this PlexofCps
|
* @return The number of data structures in this PlexofCps
|
||||||
*/
|
*/
|
||||||
public int length()
|
public int length() {
|
||||||
{
|
|
||||||
return _iMac;
|
return _iMac;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset, in bytes, from the beginning if this PlexOfCps to the
|
* Returns the offset, in bytes, from the beginning if this PlexOfCps to the
|
||||||
* data structure at index.
|
* data structure at index.
|
||||||
*
|
*
|
||||||
* @param index
|
* @param index The index of the data structure.
|
||||||
* The index of the data structure.
|
|
||||||
*
|
|
||||||
* @return The offset, in bytes, from the beginning if this PlexOfCps to the
|
* @return The offset, in bytes, from the beginning if this PlexOfCps to the
|
||||||
* data structure at index.
|
* data structure at index.
|
||||||
*/
|
*/
|
||||||
private int getStructOffset( int index )
|
private int getStructOffset(int index) {
|
||||||
{
|
return (4 * (_iMac + 1)) + (_cbStruct * index);
|
||||||
return ( 4 * ( _iMac + 1 ) ) + ( _cbStruct * index );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericPropertyNode[] toPropertiesArray()
|
GenericPropertyNode[] toPropertiesArray() {
|
||||||
{
|
if (_props == null || _props.isEmpty())
|
||||||
if ( _props == null || _props.isEmpty() )
|
|
||||||
return new GenericPropertyNode[0];
|
return new GenericPropertyNode[0];
|
||||||
|
|
||||||
return _props.toArray( new GenericPropertyNode[_props.size()] );
|
return _props.toArray(new GenericPropertyNode[_props.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString() {
|
||||||
{
|
|
||||||
return "PLCF (cbStruct: " + _cbStruct + "; iMac: " + _iMac + ")";
|
return "PLCF (cbStruct: " + _cbStruct + "; iMac: " + _iMac + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,180 +26,161 @@ import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a lightweight node in the Trees used to store content
|
* Represents a lightweight node in the Trees used to store content
|
||||||
* properties.
|
* properties.
|
||||||
* This only ever works in characters. For the few odd cases when
|
* This only ever works in characters. For the few odd cases when
|
||||||
* the start and end aren't in characters (eg PAPX and CHPX), use
|
* the start and end aren't in characters (eg PAPX and CHPX), use
|
||||||
* {@link BytePropertyNode} between you and this.
|
* {@link BytePropertyNode} between you and this.
|
||||||
*
|
*
|
||||||
* @author Ryan Ackley
|
* @author Ryan Ackley
|
||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public abstract class PropertyNode<T extends PropertyNode<T>> implements Comparable<T>, Cloneable
|
public abstract class PropertyNode<T extends PropertyNode<T>> implements Comparable<T>, Cloneable {
|
||||||
{
|
|
||||||
|
|
||||||
public static final class EndComparator implements
|
public static final class EndComparator implements
|
||||||
Comparator<PropertyNode<?>>
|
Comparator<PropertyNode<?>> {
|
||||||
{
|
|
||||||
public static final EndComparator instance = new EndComparator();
|
public static final EndComparator instance = new EndComparator();
|
||||||
|
|
||||||
public int compare( PropertyNode<?> o1, PropertyNode<?> o2 )
|
public int compare(PropertyNode<?> o1, PropertyNode<?> o2) {
|
||||||
{
|
|
||||||
int thisVal = o1.getEnd();
|
int thisVal = o1.getEnd();
|
||||||
int anotherVal = o2.getEnd();
|
int anotherVal = o2.getEnd();
|
||||||
return ( thisVal < anotherVal ? -1 : ( thisVal == anotherVal ? 0
|
return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0
|
||||||
: 1 ) );
|
: 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class StartComparator implements
|
public static final class StartComparator implements
|
||||||
Comparator<PropertyNode<?>>
|
Comparator<PropertyNode<?>> {
|
||||||
{
|
|
||||||
public static final StartComparator instance = new StartComparator();
|
public static final StartComparator instance = new StartComparator();
|
||||||
|
|
||||||
public int compare( PropertyNode<?> o1, PropertyNode<?> o2 )
|
public int compare(PropertyNode<?> o1, PropertyNode<?> o2) {
|
||||||
{
|
|
||||||
int thisVal = o1.getStart();
|
int thisVal = o1.getStart();
|
||||||
int anotherVal = o2.getStart();
|
int anotherVal = o2.getStart();
|
||||||
return ( thisVal < anotherVal ? -1 : ( thisVal == anotherVal ? 0
|
return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0
|
||||||
: 1 ) );
|
: 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static POILogger _logger = POILogFactory.getLogger(PropertyNode.class);
|
private final static POILogger _logger = POILogFactory.getLogger(PropertyNode.class);
|
||||||
protected Object _buf;
|
protected Object _buf;
|
||||||
/** The start, in characters */
|
/**
|
||||||
private int _cpStart;
|
* The start, in characters
|
||||||
/** The end, in characters */
|
*/
|
||||||
private int _cpEnd;
|
private int _cpStart;
|
||||||
|
/**
|
||||||
|
* The end, in characters
|
||||||
|
*/
|
||||||
|
private int _cpEnd;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param fcStart The start of the text for this property, in characters.
|
* @param fcStart The start of the text for this property, in characters.
|
||||||
* @param fcEnd The end of the text for this property, in characters.
|
* @param fcEnd The end of the text for this property, in characters.
|
||||||
* @param buf FIXME: Old documentation is: "grpprl The property description in compressed form."
|
* @param buf FIXME: Old documentation is: "grpprl The property description in compressed form."
|
||||||
*/
|
*/
|
||||||
protected PropertyNode(int fcStart, int fcEnd, Object buf)
|
protected PropertyNode(int fcStart, int fcEnd, Object buf) {
|
||||||
{
|
_cpStart = fcStart;
|
||||||
_cpStart = fcStart;
|
_cpEnd = fcEnd;
|
||||||
_cpEnd = fcEnd;
|
_buf = buf;
|
||||||
_buf = buf;
|
|
||||||
|
|
||||||
if(_cpStart < 0) {
|
if (_cpStart < 0) {
|
||||||
_logger.log(POILogger.WARN, "A property claimed to start before zero, at " + _cpStart + "! Resetting it to zero, and hoping for the best");
|
_logger.log(POILogger.WARN, "A property claimed to start before zero, at " + _cpStart + "! Resetting it to zero, and hoping for the best");
|
||||||
_cpStart = 0;
|
_cpStart = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _cpEnd < _cpStart )
|
if (_cpEnd < _cpStart) {
|
||||||
{
|
_logger.log(POILogger.WARN, "A property claimed to end (" + _cpEnd
|
||||||
_logger.log( POILogger.WARN, "A property claimed to end (" + _cpEnd
|
|
||||||
+ ") before start! "
|
+ ") before start! "
|
||||||
+ "Resetting end to start, and hoping for the best" );
|
+ "Resetting end to start, and hoping for the best");
|
||||||
_cpEnd = _cpStart;
|
_cpEnd = _cpStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The start offset of this property's text.
|
* @return The start offset of this property's text.
|
||||||
*/
|
*/
|
||||||
public int getStart()
|
public int getStart() {
|
||||||
{
|
return _cpStart;
|
||||||
return _cpStart;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void setStart(int start)
|
public void setStart(int start) {
|
||||||
{
|
_cpStart = start;
|
||||||
_cpStart = start;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The offset of the end of this property's text.
|
* @return The offset of the end of this property's text.
|
||||||
*/
|
*/
|
||||||
public int getEnd()
|
public int getEnd() {
|
||||||
{
|
return _cpEnd;
|
||||||
return _cpEnd;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnd(int end)
|
public void setEnd(int end) {
|
||||||
{
|
_cpEnd = end;
|
||||||
_cpEnd = end;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust for a deletion that can span multiple PropertyNodes.
|
* Adjust for a deletion that can span multiple PropertyNodes.
|
||||||
* @param start
|
*
|
||||||
* @param length
|
* @param start
|
||||||
*/
|
* @param length
|
||||||
public void adjustForDelete(int start, int length)
|
*/
|
||||||
{
|
public void adjustForDelete(int start, int length) {
|
||||||
int end = start + length;
|
int end = start + length;
|
||||||
|
|
||||||
if (_cpEnd > start) {
|
if (_cpEnd > start) {
|
||||||
// The start of the change is before we end
|
// The start of the change is before we end
|
||||||
|
|
||||||
if (_cpStart < end) {
|
if (_cpStart < end) {
|
||||||
// The delete was somewhere in the middle of us
|
// The delete was somewhere in the middle of us
|
||||||
_cpEnd = end >= _cpEnd ? start : _cpEnd - length;
|
_cpEnd = end >= _cpEnd ? start : _cpEnd - length;
|
||||||
_cpStart = Math.min(start, _cpStart);
|
_cpStart = Math.min(start, _cpStart);
|
||||||
} else {
|
} else {
|
||||||
// The delete was before us
|
// The delete was before us
|
||||||
_cpEnd -= length;
|
_cpEnd -= length;
|
||||||
_cpStart -= length;
|
_cpStart -= length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean limitsAreEqual(Object o)
|
protected boolean limitsAreEqual(Object o) {
|
||||||
{
|
return ((PropertyNode<?>) o).getStart() == _cpStart &&
|
||||||
return ((PropertyNode<?>)o).getStart() == _cpStart &&
|
((PropertyNode<?>) o).getEnd() == _cpEnd;
|
||||||
((PropertyNode<?>)o).getEnd() == _cpEnd;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode() {
|
||||||
{
|
|
||||||
return this._cpStart * 31 + this._buf.hashCode();
|
return this._cpStart * 31 + this._buf.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o)
|
public boolean equals(Object o) {
|
||||||
{
|
if (!(o instanceof PropertyNode)) return false;
|
||||||
if (!(o instanceof PropertyNode)) return false;
|
|
||||||
|
|
||||||
if (limitsAreEqual(o))
|
if (limitsAreEqual(o)) {
|
||||||
{
|
Object testBuf = ((PropertyNode<?>) o)._buf;
|
||||||
Object testBuf = ((PropertyNode<?>)o)._buf;
|
if (testBuf instanceof byte[] && _buf instanceof byte[]) {
|
||||||
if (testBuf instanceof byte[] && _buf instanceof byte[])
|
return Arrays.equals((byte[]) testBuf, (byte[]) _buf);
|
||||||
{
|
}
|
||||||
return Arrays.equals((byte[])testBuf, (byte[])_buf);
|
return _buf.equals(testBuf);
|
||||||
}
|
}
|
||||||
return _buf.equals(testBuf);
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public T clone() throws CloneNotSupportedException
|
public T clone() throws CloneNotSupportedException {
|
||||||
{
|
return (T) super.clone();
|
||||||
return (T) super.clone();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for sorting in collections.
|
* Used for sorting in collections.
|
||||||
*/
|
*/
|
||||||
public int compareTo(T o)
|
public int compareTo(T o) {
|
||||||
{
|
int cpEnd = o.getEnd();
|
||||||
int cpEnd = o.getEnd();
|
if (_cpEnd == cpEnd) {
|
||||||
if(_cpEnd == cpEnd)
|
return 0;
|
||||||
{
|
} else if (_cpEnd < cpEnd) {
|
||||||
return 0;
|
return -1;
|
||||||
}
|
} else {
|
||||||
else if(_cpEnd < cpEnd)
|
return 1;
|
||||||
{
|
}
|
||||||
return -1;
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,203 +25,185 @@ import org.apache.poi.util.Internal;
|
||||||
/**
|
/**
|
||||||
* Lightweight representation of a text piece.
|
* Lightweight representation of a text piece.
|
||||||
* Works in the character domain, not the byte domain, so you
|
* Works in the character domain, not the byte domain, so you
|
||||||
* need to have turned byte references into character
|
* need to have turned byte references into character
|
||||||
* references before getting here.
|
* references before getting here.
|
||||||
*
|
*
|
||||||
* @author Ryan Ackley
|
* @author Ryan Ackley
|
||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public class TextPiece extends PropertyNode<TextPiece>
|
public class TextPiece extends PropertyNode<TextPiece> {
|
||||||
{
|
private boolean _usesUnicode;
|
||||||
private boolean _usesUnicode;
|
|
||||||
|
|
||||||
private PieceDescriptor _pd;
|
private PieceDescriptor _pd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param start
|
* @param start Beginning offset in main document stream, in characters.
|
||||||
* Beginning offset in main document stream, in characters.
|
* @param end Ending offset in main document stream, in characters.
|
||||||
* @param end
|
* @param text The raw bytes of our text
|
||||||
* Ending offset in main document stream, in characters.
|
* @deprecated Use {@link #TextPiece(int, int, byte[], PieceDescriptor)}
|
||||||
* @param text
|
* instead
|
||||||
* The raw bytes of our text
|
|
||||||
* @deprecated Use {@link #TextPiece(int,int,byte[],PieceDescriptor)}
|
|
||||||
* instead
|
|
||||||
*/
|
*/
|
||||||
public TextPiece( int start, int end, byte[] text, PieceDescriptor pd,
|
public TextPiece(int start, int end, byte[] text, PieceDescriptor pd,
|
||||||
int cpStart )
|
int cpStart) {
|
||||||
{
|
this(start, end, text, pd);
|
||||||
this( start, end, text, pd );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param start
|
* @param start Beginning offset in main document stream, in characters.
|
||||||
* Beginning offset in main document stream, in characters.
|
* @param end Ending offset in main document stream, in characters.
|
||||||
* @param end
|
* @param text The raw bytes of our text
|
||||||
* Ending offset in main document stream, in characters.
|
|
||||||
* @param text
|
|
||||||
* The raw bytes of our text
|
|
||||||
*/
|
*/
|
||||||
public TextPiece( int start, int end, byte[] text, PieceDescriptor pd )
|
public TextPiece(int start, int end, byte[] text, PieceDescriptor pd) {
|
||||||
{
|
super(start, end, buildInitSB(text, pd));
|
||||||
super(start, end, buildInitSB(text, pd));
|
_usesUnicode = pd.isUnicode();
|
||||||
_usesUnicode = pd.isUnicode();
|
_pd = pd;
|
||||||
_pd = pd;
|
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
int textLength = ((CharSequence)_buf).length();
|
int textLength = ((CharSequence) _buf).length();
|
||||||
if(end-start != textLength) {
|
if (end - start != textLength) {
|
||||||
throw new IllegalStateException("Told we're for characters " + start + " -> " + end + ", but actually covers " + textLength + " characters!");
|
throw new IllegalStateException("Told we're for characters " + start + " -> " + end + ", but actually covers " + textLength + " characters!");
|
||||||
}
|
}
|
||||||
if(end < start) {
|
if (end < start) {
|
||||||
throw new IllegalStateException("Told we're of negative size! start="+start + " end="+end);
|
throw new IllegalStateException("Told we're of negative size! start=" + start + " end=" + end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the StringBuilder from the text and unicode flag
|
* Create the StringBuilder from the text and unicode flag
|
||||||
*/
|
*/
|
||||||
private static StringBuilder buildInitSB(byte[] text, PieceDescriptor pd) {
|
private static StringBuilder buildInitSB(byte[] text, PieceDescriptor pd) {
|
||||||
String str = new String(text, Charset.forName(pd.isUnicode() ? "UTF-16LE" : "Cp1252"));
|
String str = new String(text, Charset.forName(pd.isUnicode() ? "UTF-16LE" : "Cp1252"));
|
||||||
|
|
||||||
return new StringBuilder(str);
|
return new StringBuilder(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return If this text piece is unicode
|
* @return If this text piece is unicode
|
||||||
*/
|
*/
|
||||||
public boolean isUnicode()
|
public boolean isUnicode() {
|
||||||
{
|
return _usesUnicode;
|
||||||
return _usesUnicode;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public PieceDescriptor getPieceDescriptor()
|
public PieceDescriptor getPieceDescriptor() {
|
||||||
{
|
return _pd;
|
||||||
return _pd;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public StringBuffer getStringBuffer()
|
public StringBuffer getStringBuffer() {
|
||||||
{
|
return new StringBuffer(getStringBuilder());
|
||||||
return new StringBuffer(getStringBuilder());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public StringBuilder getStringBuilder()
|
public StringBuilder getStringBuilder() {
|
||||||
{
|
return (StringBuilder) _buf;
|
||||||
return (StringBuilder)_buf;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getRawBytes()
|
public byte[] getRawBytes() {
|
||||||
{
|
return ((CharSequence) _buf).toString().getBytes(
|
||||||
return ((CharSequence)_buf).toString().getBytes(
|
Charset.forName(_usesUnicode ? "UTF-16LE" : "Cp1252")
|
||||||
Charset.forName(_usesUnicode ? "UTF-16LE" : "Cp1252")
|
);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns part of the string.
|
* Returns part of the string.
|
||||||
* Works only in characters, not in bytes!
|
* Works only in characters, not in bytes!
|
||||||
* @param start Local start position, in characters
|
*
|
||||||
* @param end Local end position, in characters
|
* @param start Local start position, in characters
|
||||||
*/
|
* @param end Local end position, in characters
|
||||||
@Deprecated
|
*/
|
||||||
public String substring(int start, int end)
|
@Deprecated
|
||||||
{
|
public String substring(int start, int end) {
|
||||||
StringBuilder buf = (StringBuilder)_buf;
|
StringBuilder buf = (StringBuilder) _buf;
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if(start < 0) {
|
if (start < 0) {
|
||||||
throw new StringIndexOutOfBoundsException("Can't request a substring before 0 - asked for " + start);
|
throw new StringIndexOutOfBoundsException("Can't request a substring before 0 - asked for " + start);
|
||||||
}
|
}
|
||||||
if(end > buf.length()) {
|
if (end > buf.length()) {
|
||||||
throw new StringIndexOutOfBoundsException("Index " + end + " out of range 0 -> " + buf.length());
|
throw new StringIndexOutOfBoundsException("Index " + end + " out of range 0 -> " + buf.length());
|
||||||
}
|
}
|
||||||
if(end < start) {
|
if (end < start) {
|
||||||
throw new StringIndexOutOfBoundsException("Asked for text from " + start + " to " + end + ", which has an end before the start!");
|
throw new StringIndexOutOfBoundsException("Asked for text from " + start + " to " + end + ", which has an end before the start!");
|
||||||
}
|
}
|
||||||
return buf.substring(start, end);
|
return buf.substring(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts the internal string for deletinging
|
* Adjusts the internal string for deletinging
|
||||||
* some characters within this.
|
* some characters within this.
|
||||||
* @param start The start position for the delete, in characters
|
*
|
||||||
* @param length The number of characters to delete
|
* @param start The start position for the delete, in characters
|
||||||
*/
|
* @param length The number of characters to delete
|
||||||
@Deprecated
|
*/
|
||||||
public void adjustForDelete(int start, int length) {
|
@Deprecated
|
||||||
int numChars = length;
|
public void adjustForDelete(int start, int length) {
|
||||||
|
int myStart = getStart();
|
||||||
int myStart = getStart();
|
int myEnd = getEnd();
|
||||||
int myEnd = getEnd();
|
int end = start + length;
|
||||||
int end = start + numChars;
|
|
||||||
|
|
||||||
/* do we have to delete from this text piece? */
|
/* do we have to delete from this text piece? */
|
||||||
if (start <= myEnd && end >= myStart) {
|
if (start <= myEnd && end >= myStart) {
|
||||||
|
|
||||||
/* find where the deleted area overlaps with this text piece */
|
/* find where the deleted area overlaps with this text piece */
|
||||||
int overlapStart = Math.max(myStart, start);
|
int overlapStart = Math.max(myStart, start);
|
||||||
int overlapEnd = Math.min(myEnd, end);
|
int overlapEnd = Math.min(myEnd, end);
|
||||||
|
|
||||||
int bufStart = overlapStart - myStart;
|
int bufStart = overlapStart - myStart;
|
||||||
int bufEnd = overlapEnd - myStart;
|
int bufEnd = overlapEnd - myStart;
|
||||||
((StringBuilder)_buf).delete(bufStart, bufEnd);
|
((StringBuilder) _buf).delete(bufStart, bufEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to invoke this even if text from this piece is not being
|
// We need to invoke this even if text from this piece is not being
|
||||||
// deleted because the adjustment must propagate to all subsequent
|
// deleted because the adjustment must propagate to all subsequent
|
||||||
// text pieces i.e., if text from tp[n] is being deleted, then
|
// text pieces i.e., if text from tp[n] is being deleted, then
|
||||||
// tp[n + 1], tp[n + 2], etc. will need to be adjusted.
|
// tp[n + 1], tp[n + 2], etc. will need to be adjusted.
|
||||||
// The superclass is expected to use a separate sentry for this.
|
// The superclass is expected to use a separate sentry for this.
|
||||||
super.adjustForDelete(start, length);
|
super.adjustForDelete(start, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the length, in characters
|
* Returns the length, in characters
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public int characterLength()
|
public int characterLength() {
|
||||||
{
|
return (getEnd() - getStart());
|
||||||
return (getEnd() - getStart());
|
}
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns the length, in bytes
|
|
||||||
*/
|
|
||||||
public int bytesLength() {
|
|
||||||
return (getEnd() - getStart()) * (_usesUnicode ? 2 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean equals(Object o)
|
* Returns the length, in bytes
|
||||||
{
|
*/
|
||||||
if (!(o instanceof TextPiece)) return false;
|
public int bytesLength() {
|
||||||
TextPiece tp = (TextPiece)o;
|
return (getEnd() - getStart()) * (_usesUnicode ? 2 : 1);
|
||||||
assert(_buf != null && tp._buf != null && _pd != null && tp._pd != null);
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
limitsAreEqual(o)
|
|
||||||
&& tp._usesUnicode == this._usesUnicode
|
|
||||||
&& tp._buf.toString().equals(this._buf.toString())
|
|
||||||
&& tp._pd.equals(this._pd)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public boolean equals(Object o) {
|
||||||
assert false : "hashCode not designed";
|
if (!(o instanceof TextPiece)) return false;
|
||||||
return 42; // any arbitrary constant will do
|
TextPiece tp = (TextPiece) o;
|
||||||
}
|
assert (_buf != null && tp._buf != null && _pd != null && tp._pd != null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
limitsAreEqual(o)
|
||||||
|
&& tp._usesUnicode == this._usesUnicode
|
||||||
|
&& tp._buf.toString().equals(this._buf.toString())
|
||||||
|
&& tp._pd.equals(this._pd)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
assert false : "hashCode not designed";
|
||||||
|
return 42; // any arbitrary constant will do
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the character position we start at.
|
* Returns the character position we start at.
|
||||||
*/
|
*/
|
||||||
public int getCP()
|
public int getCP() {
|
||||||
{
|
return getStart();
|
||||||
return getStart();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
public String toString() {
|
||||||
{
|
|
||||||
return "TextPiece from " + getStart() + " to " + getEnd() + " ("
|
return "TextPiece from " + getStart() + " to " + getEnd() + " ("
|
||||||
+ getPieceDescriptor() + ")";
|
+ getPieceDescriptor() + ")";
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,36 +22,30 @@ import java.io.ByteArrayOutputStream;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
public final class HWPFOutputStream extends ByteArrayOutputStream
|
public final class HWPFOutputStream extends ByteArrayOutputStream {
|
||||||
{
|
|
||||||
|
|
||||||
int _offset;
|
int _offset;
|
||||||
|
|
||||||
public HWPFOutputStream()
|
public HWPFOutputStream() {
|
||||||
{
|
super();
|
||||||
super();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int getOffset()
|
public int getOffset() {
|
||||||
{
|
return _offset;
|
||||||
return _offset;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void reset()
|
public synchronized void reset() {
|
||||||
{
|
super.reset();
|
||||||
super.reset();
|
_offset = 0;
|
||||||
_offset = 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void write(byte[] buf, int off, int len)
|
public synchronized void write(byte[] buf, int off, int len) {
|
||||||
{
|
super.write(buf, off, len);
|
||||||
super.write(buf, off, len);
|
_offset += len;
|
||||||
_offset += len;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void write(int b)
|
public synchronized void write(int b) {
|
||||||
{
|
super.write(b);
|
||||||
super.write(b);
|
_offset++;
|
||||||
_offset++;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue