blob: 227df337c03365f0ba30aa9a000fda46fcf1c8fa [file] [log] [blame]
/* ====================================================================
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.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
import static org.apache.logging.log4j.util.Unbox.box;
@Internal
public final class FIBFieldHandler
{
// 154 == 0x009A; 158 == 0x009E
public static final int STSHFORIG = 0;
public static final int STSHF = 1;
public static final int PLCFFNDREF = 2;
public static final int PLCFFNDTXT = 3;
public static final int PLCFANDREF = 4;
public static final int PLCFANDTXT = 5;
public static final int PLCFSED = 6;
public static final int PLCFPAD = 7;
public static final int PLCFPHE = 8;
public static final int STTBGLSY = 9;
// 234 == 0x00EA; 238 == 0x00EE
public static final int PLCFGLSY = 10;
// 242 == 0200F2; 246 == 0x00F6
public static final int PLCFHDD = 11;
public static final int PLCFBTECHPX = 12;
public static final int PLCFBTEPAPX = 13;
public static final int PLCFSEA = 14;
public static final int STTBFFFN = 15;
public static final int PLCFFLDMOM = 16;
public static final int PLCFFLDHDR = 17;
// 298 == 0x12A; 302 == 0x12E
public static final int PLCFFLDFTN = 18;
// 306 == 0x132; 310 == 0x0136
public static final int PLCFFLDATN = 19;
// 314 == 0x013A; 318 == 0x013E
public static final int PLCFFLDMCR = 20;
// 322 == 0x0142; 326 == 0x0146
public static final int STTBFBKMK = 21;
// 330 == 0x014A; 334 == 0x014E
public static final int PLCFBKF = 22;
public static final int PLCFBKL = 23;
public static final int CMDS = 24;
public static final int PLCMCR = 25;
public static final int STTBFMCR = 26;
public static final int PRDRVR = 27;
public static final int PRENVPORT = 28;
public static final int PRENVLAND = 29;
public static final int WSS = 30;
// 402 == 0x0192; 406 == 0x0196
public static final int DOP = 31;
public static final int STTBFASSOC = 32;
public static final int CLX = 33;
public static final int PLCFPGDFTN = 34;
public static final int AUTOSAVESOURCE = 35;
public static final int GRPXSTATNOWNERS = 36;//validated
public static final int STTBFATNBKMK = 37;
public static final int PLCFDOAMOM = 38;
public static final int PLCDOAHDR = 39;
// 474 == 0x01DA; 478 == 0x01DE
public static final int PLCSPAMOM = 40;
// 482 == 0x01E2; 490 == 0x01E6
public static final int PLCSPAHDR = 41;
public static final int PLCFATNBKF = 42;
// 498 == 0x01F2; 502 == 0x01F6
public static final int PLCFATNBKL = 43;
// 506 == 0x01FA; 510 == 0x01FE
public static final int PMS = 44;
// 514 == 0x0202; 518 == 0x0206
public static final int FORMFLDSTTBS = 45;
public static final int PLCFENDREF = 46;
public static final int PLCFENDTXT = 47;
public static final int PLCFFLDEDN = 48;
public static final int PLCFPGDEDN = 49;
// 554 == 0x022A; 558 == 0x022E -- long
public static final int DGGINFO = 50;
public static final int STTBFRMARK = 51;
public static final int STTBCAPTION = 52;
public static final int STTBAUTOCAPTION = 53;
public static final int PLCFWKB = 54;
public static final int PLCFSPL = 55;
public static final int PLCFTXBXTXT = 56;
// 610 -- 0x0262; 614 == 0x0266
public static final int PLCFFLDTXBX = 57;// validated
public static final int PLCFHDRTXBXTXT = 58;
public static final int PLCFFLDHDRTXBX = 59;
public static final int STWUSER = 60;
public static final int STTBTTMBD = 61;
public static final int UNUSED = 62;
public static final int PGDMOTHER = 63;
public static final int BKDMOTHER = 64;
public static final int PGDFTN = 65;
public static final int BKDFTN = 66;
public static final int PGDEDN = 67;
public static final int BKDEDN = 68;
public static final int STTBFINTFLD = 69;
public static final int ROUTESLIP = 70;
public static final int STTBSAVEDBY = 71;
public static final int STTBFNM = 72;
public static final int PLFLST = 73;
@Deprecated
public static final int PLCFLST = PLFLST;
public static final int PLFLFO = 74;
public static final int PLCFTXBXBKD = 75;//validated
public static final int PLCFTXBXHDRBKD = 76;
public static final int DOCUNDO = 77;
public static final int RGBUSE = 78;
public static final int USP = 79;
public static final int USKF = 80;
public static final int PLCUPCRGBUSE = 81;
public static final int PLCUPCUSP = 82;
public static final int STTBGLSYSTYLE = 83;
public static final int PLGOSL = 84;
public static final int PLCOCX = 85;
public static final int PLCFBTELVC = 86;
public static final int MODIFIED = 87;
public static final int PLCFLVC = 88;
public static final int PLCASUMY = 89;
public static final int PLCFGRAM = 90;
public static final int STTBLISTNAMES = 91;
public static final int STTBFUSSR = 92;
private static final Logger LOGGER = LogManager.getLogger(FIBFieldHandler.class);
private static final int FIELD_SIZE = LittleEndianConsts.INT_SIZE * 2;
private Map<Integer, UnhandledDataStructure> _unknownMap = new HashMap<>();
private int[] _fields;
FIBFieldHandler(byte[] mainStream, int offset, int cbRgFcLcb, byte[] tableStream,
HashSet<Integer> offsetList, boolean areKnown)
{
_fields = new int[cbRgFcLcb * 2];
for (int x = 0; x < cbRgFcLcb; x++)
{
int fieldOffset = (x * FIELD_SIZE) + offset;
int dsOffset = LittleEndian.getInt(mainStream, fieldOffset);
fieldOffset += LittleEndianConsts.INT_SIZE;
int dsSize = LittleEndian.getInt(mainStream, fieldOffset);
if (offsetList.contains(Integer.valueOf(x)) ^ areKnown)
{
if (dsSize > 0)
{
if (dsOffset + dsSize > tableStream.length)
{
LOGGER.atWarn().log("Unhandled data structure points to outside the buffer. offset = {}, length = {}, buffer length = {}", box(dsOffset),box(dsSize),box(tableStream.length));
}
else
{
UnhandledDataStructure unhandled = new UnhandledDataStructure(
tableStream, dsOffset, dsSize);
_unknownMap.put(Integer.valueOf(x), unhandled);
}
}
}
_fields[x*2] = dsOffset;
_fields[(x*2) + 1] = dsSize;
}
}
public void clearFields()
{
Arrays.fill(_fields, 0);
}
public int getFieldOffset(int field)
{
return _fields[field*2];
}
public int getFieldSize(int field)
{
return _fields[(field*2) + 1];
}
public void setFieldOffset(int field, int offset)
{
_fields[field*2] = offset;
}
public void setFieldSize(int field, int size)
{
_fields[(field*2) + 1] = size;
}
public int sizeInBytes()
{
return (_fields.length * LittleEndianConsts.INT_SIZE);
}
public int getFieldsCount() {
return _fields.length / 2;
}
void writeTo(byte[] mainStream, int offset, ByteArrayOutputStream tableStream)
throws IOException
{
for (int x = 0; x < _fields.length/2; x++)
{
UnhandledDataStructure ds = _unknownMap.get(Integer.valueOf(x));
if (ds != null)
{
_fields[x * 2] = tableStream.size();
LittleEndian.putInt(mainStream, offset, tableStream.size());
offset += LittleEndianConsts.INT_SIZE;
byte[] buf = ds.getBuf();
tableStream.write(buf);
_fields[(x * 2) + 1] = buf.length;
LittleEndian.putInt(mainStream, offset, buf.length);
offset += LittleEndianConsts.INT_SIZE;
}
else
{
LittleEndian.putInt(mainStream, offset, _fields[x * 2]);
offset += LittleEndianConsts.INT_SIZE;
LittleEndian.putInt(mainStream, offset, _fields[(x * 2) + 1]);
offset += LittleEndianConsts.INT_SIZE;
}
}
}
private static String leftPad( String text, int value, char padChar )
{
if ( text.length() >= value )
return text;
StringBuilder result = new StringBuilder();
for ( int i = 0; i < ( value - text.length() ); i++ )
{
result.append( padChar );
}
result.append( text );
return result.toString();
}
@Override
public String toString()
{
StringBuilder result = new StringBuilder();
result.append( "[FIBFieldHandler]:\n" );
result.append( "\tFields:\n" );
result.append( "\t" );
result.append( leftPad( "Index", 8, ' ' ) );
result.append( leftPad( "FIB offset", 15, ' ' ) );
result.append( leftPad( "Offset", 8, ' ' ) );
result.append( leftPad( "Size", 8, ' ' ) );
result.append( '\n' );
for ( int x = 0; x < _fields.length / 2; x++ )
{
result.append( '\t' );
result.append( leftPad( Integer.toString( x ), 8, ' ' ) );
result.append( leftPad( Integer.toString( 154 + x * LittleEndianConsts.INT_SIZE * 2 ), 6, ' ' ) );
result.append( " 0x" );
result.append( leftPad( Integer.toHexString( 154 + x * LittleEndianConsts.INT_SIZE * 2 ), 4, '0' ) );
result.append( leftPad( Integer.toString( getFieldOffset( x ) ), 8, ' ' ) );
result.append( leftPad( Integer.toString( getFieldSize( x ) ), 8, ' ' ) );
UnhandledDataStructure structure = _unknownMap.get( Integer.valueOf( x ) );
if ( structure != null )
{
result.append( " => Unknown structure of size " );
result.append( structure.getBuf().length );
}
result.append( '\n' );
}
return result.toString();
}
}