org.ttzero.excel.entity.e3.Context Maven / Gradle / Ivy
/*
* Copyright (c) 2019-2020, [email protected] All Rights Reserved.
*
* Licensed 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.ttzero.excel.entity.e3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ttzero.excel.entity.e3.enums.ByteOrder;
import org.ttzero.excel.manager.ExcelType;
import org.ttzero.excel.reader.ExcelReadException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Path;
import java.util.Arrays;
/**
* Compound Document Header
*
* The header is always located at the beginning of
* the file, and its size is exactly {@code 512} bytes.
* This implies that the first sector (with SecID 0)
* always starts at file offset {@code 512}.
*
* @author guanquan.wang at 2019-01-29 13:31
*/
public final class Context {
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
/**
* The tmp split directory path
*/
public Path root;
/**
* The excel file channel
*/
public SeekableByteChannel channel;
/**
* Type of file, enum value of {@link ExcelType}
*/
public ExcelType excelType;
/**
* Revision number of the file format
*/
public short mv;
/**
* Version number of the file format
*/
public short v;
/**
* Byte order identifier
*
*
* - FE FF: Little-Endian
* - FF FE: Big-Endian
*
*/
public ByteOrder byteOrder;
/**
* Size of a sector in the compound document file
* in power-of-two (ssz), real sector size is sec_size = 2ssz bytes
* (minimum value is 7 which means 128 bytes, most used
* value is 9 which means 512 bytes)
*/
public int ssz;
/**
* Size of a short-sector in the short-stream container
* stream in power-of-two (sssz), real short-sector
* size is short_sec_size = 2sssz bytes
* (maximum value is sector size ssz, see above, most used
* value is 6 which means 64 bytes)
*/
public int sssz;
/**
* Total number of sectors used for the sector allocation table
*/
public int count_sat;
/**
* SecID of first sector of the directory stream
*/
public int dir_sid;
/**
* Minimum size of a standard stream (in bytes, minimum allowed
* and most used size is {@code 4096} bytes), streams with an
* actual size smaller than (and not equal to) this value are
* stored as short-streams
*/
public int standard_size;
/**
* SecID of first sector of the short-sector allocation table,
* or –2 (End Of Chain SecID) if not extant
*/
public int first_ssat_sid;
/**
* Total number of sectors used for the short-sector allocation table
*/
public int count_ssat;
/**
* SecID of first sector of the master sector allocation
* table, or –2 (End Of Chain SecID) if no additional
* sectors used
*/
public int first_msat_sid;
/**
* Total number of sectors used for the master sector allocation table
*/
public int count_msat;
/**
* First part of the master sector allocation table
*/
public int[] msat;
/**
* The short-sector allocation table
*/
public int[] ssat;
/**
* The split size.
* Default size is 5, so the default block size is 16KB
*/
public int split;
/**
* The sector size
*/
public int sectorSize;
/**
* The first short-sector SecID
*/
public int first_short_sector;
/**
* The shared string block size
*/
public int cacheSize;
/**
* The shared string hot block size
*/
public int hotSize;
/**
* The Sector Identifiers Table
*/
public SectorAllocationTable sectorTable;
public Context() {
this.sectorTable = new SectorAllocationTable.SmallSectorTable();
}
/**
* Read specify sector data
*
* @param sid the sector id
* @param buffer dest byte buffer
* @return byte buffer
*/
public ByteBuffer read(int sid, ByteBuffer buffer) {
/*
Read 5 blocks of data at a time, so position is multiple of 0, 5, 10 ...
and plus a fixed 512 bytes in header
*/
long position = (((long) sid) >> split << (ssz + split)) + 512;
buffer.clear();
try {
if (channel.position() != position) {
LOGGER.debug("Sector id: {}, Position: {}, Channel position: {}", sid, position, channel.position());
channel.position(position);
}
channel.read(buffer);
} catch (IOException e) {
throw new ExcelReadException(e);
}
buffer.flip();
return buffer;
}
/**
* Test the short-sector-block is adjacent
*
* @param sid the RootStorage sector id
* @return bool
*/
public boolean isAdjacentShortBlock(int sid) {
return first_short_sector == SectorAllocationTable.EOC || ssat.length == 0 || sid >= ssat.length;
}
/**
* Bound check
*
* @return false if the record size exceeds limit
*/
public boolean recordBoundCheck(int from, int size, int s_size) {
int n = size >> s_size;
if (n == 0) return true;
if ((n << s_size) < size) n++;
sectorTable.moveTo(from);
for ( ; --n > 0; ) {
int next_sid = sectorTable.nextSecID();
if (next_sid < 0) return false;
}
return true;
}
@Override
public String toString() {
return "{Root: " + root +
", Type: " + excelType +
", Revision: " + mv +
", Version: " + v +
", ByteOrder: " + byteOrder +
", ssz: " + ssz +
", sssz: " + sssz +
", count_sat: " + count_sat +
", dir_sid: " + dir_sid +
", standard_size: " + standard_size +
", first_ssat_sid: " + first_ssat_sid +
", count_ssat: " + count_ssat +
", first_msat_sid: " + first_msat_sid +
", count_msat: " + count_msat +
", msat: " + Arrays.toString(msat) +
", ssat: " + Arrays.toString(ssat) +
", first_short_sector: " + first_short_sector +
"}"
;
}
}