rewrite Sttb utils to handle complex cases
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1177643 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b814328848
commit
ef2876e71f
@ -21,12 +21,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.util.POILogFactory;
|
|
||||||
|
|
||||||
import org.apache.poi.util.POILogger;
|
|
||||||
|
|
||||||
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
|
import org.apache.poi.util.POILogFactory;
|
||||||
|
import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
public class BookmarksTables
|
public class BookmarksTables
|
||||||
@ -120,8 +118,8 @@ public class BookmarksTables
|
|||||||
int namesLength = fib.getLcbSttbfbkmk();
|
int namesLength = fib.getLcbSttbfbkmk();
|
||||||
|
|
||||||
if ( namesStart != 0 && namesLength != 0 )
|
if ( namesStart != 0 && namesLength != 0 )
|
||||||
this.names = new ArrayList<String>( Arrays.asList( SttbfUtils.read(
|
this.names = new ArrayList<String>( Arrays.asList( SttbUtils
|
||||||
tableStream, namesStart ) ) );
|
.readSttbfBkmk( tableStream, namesStart ) ) );
|
||||||
|
|
||||||
int firstDescriptorsStart = fib.getFcPlcfbkf();
|
int firstDescriptorsStart = fib.getFcPlcfbkf();
|
||||||
int firstDescriptorsLength = fib.getLcbPlcfbkf();
|
int firstDescriptorsLength = fib.getLcbPlcfbkf();
|
||||||
@ -196,8 +194,8 @@ public class BookmarksTables
|
|||||||
}
|
}
|
||||||
|
|
||||||
int start = tableStream.getOffset();
|
int start = tableStream.getOffset();
|
||||||
SttbfUtils
|
SttbUtils.writeSttbfBkmk( names.toArray( new String[names.size()] ),
|
||||||
.write( tableStream, names.toArray( new String[names.size()] ) );
|
tableStream );
|
||||||
int end = tableStream.getOffset();
|
int end = tableStream.getOffset();
|
||||||
|
|
||||||
fib.setFcSttbfbkmk( start );
|
fib.setFcSttbfbkmk( start );
|
||||||
|
@ -24,8 +24,6 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.util.LittleEndian;
|
|
||||||
import org.apache.poi.util.StringUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String table containing the names of authors of revision marks, e-mails and
|
* String table containing the names of authors of revision marks, e-mails and
|
||||||
@ -35,21 +33,6 @@ import org.apache.poi.util.StringUtil;
|
|||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public final class RevisionMarkAuthorTable {
|
public final class RevisionMarkAuthorTable {
|
||||||
/**
|
|
||||||
* must be 0xFFFF
|
|
||||||
*/
|
|
||||||
private short fExtend = (short) 0xFFFF;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the number of entries in the table
|
|
||||||
*/
|
|
||||||
private short cData = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* must be 0
|
|
||||||
*/
|
|
||||||
private short cbExtra = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of entries.
|
* Array of entries.
|
||||||
*/
|
*/
|
||||||
@ -62,36 +45,11 @@ public final class RevisionMarkAuthorTable {
|
|||||||
* @param offset the offset into the byte array.
|
* @param offset the offset into the byte array.
|
||||||
* @param size the size of the table in the byte array.
|
* @param size the size of the table in the byte array.
|
||||||
*/
|
*/
|
||||||
public RevisionMarkAuthorTable(byte[] tableStream, int offset, int size) throws IOException {
|
public RevisionMarkAuthorTable( byte[] tableStream, int offset, int size )
|
||||||
// Read fExtend - it isn't used
|
throws IOException
|
||||||
fExtend = LittleEndian.getShort(tableStream, offset);
|
{
|
||||||
if(fExtend != 0xFFFF) {
|
entries = SttbUtils.readSttbfRMark( tableStream, offset );
|
||||||
//TODO: throw an exception here?
|
}
|
||||||
}
|
|
||||||
offset += 2;
|
|
||||||
|
|
||||||
// Read the number of entries
|
|
||||||
cData = LittleEndian.getShort(tableStream, offset);
|
|
||||||
offset += 2;
|
|
||||||
|
|
||||||
// Read cbExtra - it isn't used
|
|
||||||
cbExtra = LittleEndian.getShort(tableStream, offset);
|
|
||||||
if(cbExtra != 0) {
|
|
||||||
//TODO: throw an exception here?
|
|
||||||
}
|
|
||||||
offset += 2;
|
|
||||||
|
|
||||||
entries = new String[cData];
|
|
||||||
for (int i = 0; i < cData; i++) {
|
|
||||||
int len = LittleEndian.getShort(tableStream, offset);
|
|
||||||
offset += 2;
|
|
||||||
|
|
||||||
String name = StringUtil.getFromUnicodeLE(tableStream, offset, len);
|
|
||||||
offset += len * 2;
|
|
||||||
|
|
||||||
entries[i] = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entries. The returned list cannot be modified.
|
* Gets the entries. The returned list cannot be modified.
|
||||||
@ -121,7 +79,7 @@ public final class RevisionMarkAuthorTable {
|
|||||||
* @return the number of entries.
|
* @return the number of entries.
|
||||||
*/
|
*/
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return cData;
|
return entries.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,19 +88,9 @@ public final class RevisionMarkAuthorTable {
|
|||||||
* @param tableStream the table stream to write to.
|
* @param tableStream the table stream to write to.
|
||||||
* @throws IOException if an error occurs while writing.
|
* @throws IOException if an error occurs while writing.
|
||||||
*/
|
*/
|
||||||
public void writeTo(HWPFOutputStream tableStream) throws IOException {
|
public void writeTo( HWPFOutputStream tableStream ) throws IOException
|
||||||
byte[] header = new byte[6];
|
{
|
||||||
LittleEndian.putShort(header, 0, fExtend);
|
SttbUtils.writeSttbfRMark( entries, tableStream );
|
||||||
LittleEndian.putShort(header, 2, cData);
|
}
|
||||||
LittleEndian.putShort(header, 4, cbExtra);
|
|
||||||
tableStream.write(header);
|
|
||||||
|
|
||||||
for (String name : entries) {
|
|
||||||
byte[] buf = new byte[name.length() * 2 + 2];
|
|
||||||
LittleEndian.putShort(buf, 0, (short) name.length());
|
|
||||||
StringUtil.putUnicodeLE(name, buf, 2);
|
|
||||||
tableStream.write(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hwpf.model;
|
package org.apache.poi.hwpf.model;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -26,55 +25,32 @@ import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
|||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String table containing the history of the last few revisions ("saves") of the document.
|
* String table containing the history of the last few revisions ("saves") of
|
||||||
* Read-only for the time being.
|
* the document. Read-only for the time being.
|
||||||
*
|
*
|
||||||
* @author Daniel Noll
|
* @author Daniel Noll
|
||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public final class SavedByTable
|
public final class SavedByTable
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Array of entries.
|
||||||
|
*/
|
||||||
|
private SavedByEntry[] entries;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of entries.
|
* Constructor to read the table from the table stream.
|
||||||
*/
|
*
|
||||||
private SavedByEntry[] entries;
|
* @param tableStream
|
||||||
|
* the table stream.
|
||||||
/**
|
* @param offset
|
||||||
* Constructor to read the table from the table stream.
|
* the offset into the byte array.
|
||||||
*
|
* @param size
|
||||||
* @param tableStream the table stream.
|
* the size of the table in the byte array.
|
||||||
* @param offset the offset into the byte array.
|
*/
|
||||||
* @param size the size of the table in the byte array.
|
public SavedByTable( byte[] tableStream, int offset, int size )
|
||||||
*/
|
{
|
||||||
public SavedByTable(byte[] tableStream, int offset, int size)
|
String[] strings = SttbUtils.readSttbSavedBy( tableStream, offset );
|
||||||
{
|
|
||||||
// // Read the value that I don't know what it does. :-)
|
|
||||||
// unknownValue = LittleEndian.getShort(tableStream, offset);
|
|
||||||
// offset += 2;
|
|
||||||
//
|
|
||||||
// // The stored int is the number of strings, and there are two strings per entry.
|
|
||||||
// int numEntries = LittleEndian.getInt(tableStream, offset) / 2;
|
|
||||||
// offset += 4;
|
|
||||||
//
|
|
||||||
// entries = new SavedByEntry[numEntries];
|
|
||||||
// for (int i = 0; i < numEntries; i++)
|
|
||||||
// {
|
|
||||||
// int len = LittleEndian.getShort(tableStream, offset);
|
|
||||||
// offset += 2;
|
|
||||||
// String userName = StringUtil.getFromUnicodeLE(tableStream, offset, len);
|
|
||||||
// offset += len * 2;
|
|
||||||
// len = LittleEndian.getShort(tableStream, offset);
|
|
||||||
// offset += 2;
|
|
||||||
// String saveLocation = StringUtil.getFromUnicodeLE(tableStream, offset, len);
|
|
||||||
// offset += len * 2;
|
|
||||||
//
|
|
||||||
// entries[i] = new SavedByEntry(userName, saveLocation);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// first value is mark for extended STTBF ;) -- sergey
|
|
||||||
String[] strings = SttbfUtils.read( tableStream, offset );
|
|
||||||
|
|
||||||
int numEntries = strings.length / 2;
|
int numEntries = strings.length / 2;
|
||||||
entries = new SavedByEntry[numEntries];
|
entries = new SavedByEntry[numEntries];
|
||||||
for ( int i = 0; i < numEntries; i++ )
|
for ( int i = 0; i < numEntries; i++ )
|
||||||
@ -83,15 +59,15 @@ public final class SavedByTable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entries. The returned list cannot be modified.
|
* Gets the entries. The returned list cannot be modified.
|
||||||
*
|
*
|
||||||
* @return the list of entries.
|
* @return the list of entries.
|
||||||
*/
|
*/
|
||||||
public List<SavedByEntry> getEntries()
|
public List<SavedByEntry> getEntries()
|
||||||
{
|
{
|
||||||
return Collections.unmodifiableList(Arrays.asList(entries));
|
return Collections.unmodifiableList( Arrays.asList( entries ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes this table to the table stream.
|
* Writes this table to the table stream.
|
||||||
@ -110,7 +86,7 @@ public final class SavedByTable
|
|||||||
toSave[counter++] = entry.getUserName();
|
toSave[counter++] = entry.getUserName();
|
||||||
toSave[counter++] = entry.getSaveLocation();
|
toSave[counter++] = entry.getSaveLocation();
|
||||||
}
|
}
|
||||||
SttbfUtils.write( tableStream, toSave );
|
SttbUtils.writeSttbSavedBy( toSave, tableStream );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
211
src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java
Normal file
211
src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
package org.apache.poi.hwpf.model;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
||||||
|
import org.apache.poi.util.Internal;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utils class for storing and reading "STring TaBle stored in File"
|
||||||
|
*
|
||||||
|
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
|
||||||
|
*/
|
||||||
|
@Internal
|
||||||
|
class SttbUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
static class Sttb
|
||||||
|
{
|
||||||
|
public int cbExtra;
|
||||||
|
|
||||||
|
public int cDataLength;
|
||||||
|
|
||||||
|
public String[] data;
|
||||||
|
|
||||||
|
public byte[][] extraData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int CBEXTRA_STTB_SAVED_BY = 0; // bytes
|
||||||
|
|
||||||
|
private static final int CBEXTRA_STTBF_BKMK = 0; // bytes
|
||||||
|
|
||||||
|
private static final int CBEXTRA_STTBF_R_MARK = 0; // bytes
|
||||||
|
|
||||||
|
private static final int CDATA_SIZE_STTB_SAVED_BY = 2; // bytes
|
||||||
|
|
||||||
|
private static final int CDATA_SIZE_STTBF_BKMK = 2; // bytes
|
||||||
|
|
||||||
|
private static final int CDATA_SIZE_STTBF_R_MARK = 2; // bytes
|
||||||
|
|
||||||
|
static Sttb read( int cDataLength, byte[] buffer, int startOffset )
|
||||||
|
{
|
||||||
|
short ffff = LittleEndian.getShort( buffer, startOffset );
|
||||||
|
int offset = startOffset + 2;
|
||||||
|
|
||||||
|
if ( ffff != (short) 0xffff )
|
||||||
|
{
|
||||||
|
// Non-extended character Pascal strings
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Non-extended character Pascal strings are not supported right now. "
|
||||||
|
+ "Please, contact POI developers for update." );
|
||||||
|
}
|
||||||
|
// strings are extended character strings
|
||||||
|
|
||||||
|
int cData = cDataLength == 2 ? LittleEndian.getUShort( buffer, offset )
|
||||||
|
: LittleEndian.getInt( buffer, offset );
|
||||||
|
offset += cDataLength;
|
||||||
|
|
||||||
|
Sttb sttb = new Sttb();
|
||||||
|
sttb.cDataLength = cDataLength;
|
||||||
|
sttb.cbExtra = LittleEndian.getUShort( buffer, offset );
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
sttb.data = new String[cData];
|
||||||
|
sttb.extraData = new byte[cData][];
|
||||||
|
|
||||||
|
for ( int i = 0; i < cData; i++ )
|
||||||
|
{
|
||||||
|
int cchData = LittleEndian.getShort( buffer, offset );
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
if ( cchData < 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sttb.data[i] = StringUtil
|
||||||
|
.getFromUnicodeLE( buffer, offset, cchData );
|
||||||
|
offset += cchData * 2;
|
||||||
|
|
||||||
|
sttb.extraData[i] = LittleEndian.getByteArray( buffer, offset,
|
||||||
|
sttb.cbExtra );
|
||||||
|
offset += sttb.cbExtra;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sttb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String[] readSttbfBkmk( byte[] buffer, int startOffset )
|
||||||
|
{
|
||||||
|
return read( CDATA_SIZE_STTBF_BKMK, buffer, startOffset ).data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String[] readSttbfRMark( byte[] buffer, int startOffset )
|
||||||
|
{
|
||||||
|
return read( CDATA_SIZE_STTBF_R_MARK, buffer, startOffset ).data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String[] readSttbSavedBy( byte[] buffer, int startOffset )
|
||||||
|
{
|
||||||
|
return read( CDATA_SIZE_STTB_SAVED_BY, buffer, startOffset ).data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write( Sttb sttb, HWPFOutputStream tableStream )
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
final int headerSize = sttb.cDataLength == 2 ? 6 : 8;
|
||||||
|
|
||||||
|
byte[] header = new byte[headerSize];
|
||||||
|
LittleEndian.putShort( header, 0, (short) 0xffff );
|
||||||
|
|
||||||
|
if ( sttb.data == null || sttb.data.length == 0 )
|
||||||
|
{
|
||||||
|
if ( sttb.cDataLength == 4 )
|
||||||
|
{
|
||||||
|
LittleEndian.putInt( header, 2, 0 );
|
||||||
|
LittleEndian.putUShort( header, 6, sttb.cbExtra );
|
||||||
|
tableStream.write( header );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LittleEndian.putUShort( header, 2, 0 );
|
||||||
|
LittleEndian.putUShort( header, 4, sttb.cbExtra );
|
||||||
|
tableStream.write( header );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( sttb.cDataLength == 4 )
|
||||||
|
{
|
||||||
|
LittleEndian.putInt( header, 2, sttb.data.length );
|
||||||
|
LittleEndian.putUShort( header, 6, sttb.cbExtra );
|
||||||
|
tableStream.write( header );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LittleEndian.putUShort( header, 2, sttb.data.length );
|
||||||
|
LittleEndian.putUShort( header, 4, sttb.cbExtra );
|
||||||
|
tableStream.write( header );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < sttb.data.length; i++ )
|
||||||
|
{
|
||||||
|
String entry = sttb.data[i];
|
||||||
|
if ( entry == null )
|
||||||
|
{
|
||||||
|
// is it correct?
|
||||||
|
tableStream.write( new byte[] { -1, 0 } );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buf = new byte[entry.length() * 2 + sttb.cbExtra + 2];
|
||||||
|
|
||||||
|
LittleEndian.putShort( buf, 0, (short) entry.length() );
|
||||||
|
StringUtil.putUnicodeLE( entry, buf, 2 );
|
||||||
|
|
||||||
|
if ( sttb.extraData != null && i < sttb.extraData.length
|
||||||
|
&& sttb.extraData[i] != null )
|
||||||
|
System.arraycopy( sttb.extraData[i], 0, buf,
|
||||||
|
entry.length() * 2,
|
||||||
|
Math.min( sttb.extraData[i].length, sttb.cbExtra ) );
|
||||||
|
|
||||||
|
tableStream.write( buf );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeSttbfBkmk( String[] data, HWPFOutputStream tableStream )
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
Sttb sttb = new Sttb();
|
||||||
|
sttb.cDataLength = CDATA_SIZE_STTBF_BKMK;
|
||||||
|
sttb.data = data;
|
||||||
|
sttb.cbExtra = CBEXTRA_STTBF_BKMK;
|
||||||
|
write( sttb, tableStream );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeSttbfRMark( String[] data, HWPFOutputStream tableStream )
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
Sttb sttb = new Sttb();
|
||||||
|
sttb.cDataLength = CDATA_SIZE_STTBF_R_MARK;
|
||||||
|
sttb.data = data;
|
||||||
|
sttb.cbExtra = CBEXTRA_STTBF_R_MARK;
|
||||||
|
write( sttb, tableStream );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeSttbSavedBy( String[] data, HWPFOutputStream tableStream )
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
Sttb sttb = new Sttb();
|
||||||
|
sttb.cDataLength = CDATA_SIZE_STTB_SAVED_BY;
|
||||||
|
sttb.data = data;
|
||||||
|
sttb.cbExtra = CBEXTRA_STTB_SAVED_BY;
|
||||||
|
write( sttb, tableStream );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,92 +0,0 @@
|
|||||||
/* ====================================================================
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
|
||||||
this work for additional information regarding copyright ownership.
|
|
||||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
(the "License"); you may not use this file except in compliance with
|
|
||||||
the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
==================================================================== */
|
|
||||||
package org.apache.poi.hwpf.model;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
|
||||||
import org.apache.poi.util.Internal;
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
|
||||||
import org.apache.poi.util.StringUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utils for storing and reading "STring TaBle stored in File"
|
|
||||||
*
|
|
||||||
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
|
|
||||||
*/
|
|
||||||
@Internal
|
|
||||||
class SttbfUtils
|
|
||||||
{
|
|
||||||
public static String[] read( byte[] data, int startOffset )
|
|
||||||
{
|
|
||||||
short ffff = LittleEndian.getShort( data, startOffset );
|
|
||||||
|
|
||||||
if ( ffff != (short) 0xffff )
|
|
||||||
{
|
|
||||||
// Non-extended character Pascal strings
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"Non-extended character Pascal strings are not supported right now. "
|
|
||||||
+ "Please, contact POI developers for update." );
|
|
||||||
}
|
|
||||||
|
|
||||||
// strings are extended character strings
|
|
||||||
int offset = startOffset + 2;
|
|
||||||
int numEntries = LittleEndian.getInt( data, offset );
|
|
||||||
offset += 4;
|
|
||||||
|
|
||||||
String[] entries = new String[numEntries];
|
|
||||||
for ( int i = 0; i < numEntries; i++ )
|
|
||||||
{
|
|
||||||
int len = LittleEndian.getShort( data, offset );
|
|
||||||
offset += 2;
|
|
||||||
String value = StringUtil.getFromUnicodeLE( data, offset, len );
|
|
||||||
offset += len * 2;
|
|
||||||
entries[i] = value;
|
|
||||||
}
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int write( HWPFOutputStream tableStream, String[] entries )
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
byte[] header = new byte[6];
|
|
||||||
LittleEndian.putShort( header, 0, (short) 0xffff );
|
|
||||||
|
|
||||||
if ( entries == null || entries.length == 0 )
|
|
||||||
{
|
|
||||||
LittleEndian.putInt( header, 2, 0 );
|
|
||||||
tableStream.write( header );
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
LittleEndian.putInt( header, 2, entries.length );
|
|
||||||
tableStream.write( header );
|
|
||||||
int size = 6;
|
|
||||||
|
|
||||||
for ( String entry : entries )
|
|
||||||
{
|
|
||||||
byte[] buf = new byte[entry.length() * 2 + 2];
|
|
||||||
LittleEndian.putShort( buf, 0, (short) entry.length() );
|
|
||||||
StringUtil.putUnicodeLE( entry, buf, 2 );
|
|
||||||
tableStream.write( buf );
|
|
||||||
size += buf.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user