What Is poi-scratchpad-5.2.3.jar?

What Is poi-scratchpad-5.2.3.jar?

✍: FYIcenter.com

poi-scratchpad-5.2.3.jar is one of the JAR files for Apache POI 5.2.3, which provides an API for Microsoft document files of Word, Excel, PowerPoint, and Visio.

poi-scratchpad-5.2.3.jar provides support for older versions of Microsoft document files like Word 97, Excel 97, PowerPoint 97, etc.

poi-scratchpad-5.2.3.jar is distributed as part of the poi-bin-5.2.3-20220909.zip download file.

JAR File Size and Download Location:

JAR name: poi-scratchpad-5.2.3.jar
Target JDK version: 9

File name: poi-scratchpad.jar, poi-scratchpad-5.2.3.jar
File size: 1897121 bytes
Release date: 09-09-2022
Download: Apache POI Website

Here are Java Source Code files for poi-scratchpad-5.2.3.jar:


/* ====================================================================
   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


   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   See the License for the specific language governing permissions and
   limitations under the License.
==================================================================== */

package org.apache.poi.hslf.model.textproperties;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;

import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;

 * For a given run of characters, holds the properties (which could
 *  be paragraph properties or character properties).
 * Used to hold the number of characters affected, the list of active
 *  properties, and the indent level if required.
public class TextPropCollection implements GenericRecord, Duplicatable {
    private static final Logger LOG = LogManager.getLogger(TextPropCollection.class);

    /** All the different kinds of paragraph properties we might handle */
    private static final TextProp[] paragraphTextPropTypes = {
        // TextProp order is according to 2.9.20 TextPFException,
        // bitmask order can be different
        new ParagraphFlagsTextProp(),
        new TextProp(2, 0x80, "bullet.char"),
        new TextProp(2, 0x10, "bullet.font"),
        new TextProp(2, 0x40, "bullet.size"),
        new TextProp(4, 0x20, "bullet.color"),
        new TextAlignmentProp(),
        new TextProp(2, 0x1000, "linespacing"),
        new TextProp(2, 0x2000, "spacebefore"),
        new TextProp(2, 0x4000, "spaceafter"),
        new TextProp(2, 0x100, "text.offset"), // left margin
        // 0x200 - Undefined and MUST be ignored
        new TextProp(2, 0x400, "bullet.offset"), // indent
        new TextProp(2, 0x8000, "defaultTabSize"),
        new HSLFTabStopPropCollection(), // tabstops size is variable!
        new FontAlignmentProp(),
        new WrapFlagsTextProp(),
        new TextProp(2, 0x200000, "textDirection"),
        // 0x400000 MUST be zero and MUST be ignored
        new TextProp(0, 0x800000, "bullet.blip"), // TODO: check size
        new TextProp(0, 0x1000000, "bullet.scheme"), // TODO: check size
        new TextProp(0, 0x2000000, "hasBulletScheme"), // TODO: check size
        // 0xFC000000 MUST be zero and MUST be ignored

    /** All the different kinds of character properties we might handle */
    private static final TextProp[] characterTextPropTypes = new TextProp[] {
        new TextProp(0, 0x100000, "pp10ext"),
        new TextProp(0, 0x1000000, "newAsian.font.index"), // A bit that specifies whether the newEAFontRef field of the TextCFException10 structure that contains this CFMasks exists.
        new TextProp(0, 0x2000000, "cs.font.index"), // A bit that specifies whether the csFontRef field of the TextCFException10 structure that contains this CFMasks exists.
        new TextProp(0, 0x4000000, "pp11ext"), // A bit that specifies whether the pp11ext field of the TextCFException10 structure that contains this CFMasks exists.
        new CharFlagsTextProp(),
        new TextProp(2, 0x10000, "font.index"),
        new TextProp(2, 0x200000, "asian.font.index"),
        new TextProp(2, 0x400000, "ansi.font.index"),
        new TextProp(2, 0x800000, "symbol.font.index"),
        new TextProp(2, 0x20000, "font.size"),
        new TextProp(4, 0x40000, "font.color"),
        new TextProp(2, 0x80000, "superscript")

    public enum TextPropType {
        paragraph, character

    private int charactersCovered;

    // indentLevel is only valid for paragraph collection
    // if it's set to -1, it must be omitted - see 2.9.36 TextMasterStyleLevel
    private short indentLevel;
    private final Map<String,TextProp> textProps = new HashMap<>();
    private int maskSpecial;
    private final TextPropType textPropType;

     * Create a new collection of text properties (be they paragraph
     *  or character) which will be groked via a subsequent call to
     *  buildTextPropList().
    public TextPropCollection(int charactersCovered, TextPropType textPropType) {
        this.charactersCovered = charactersCovered;
        this.textPropType = textPropType;

    public TextPropCollection(TextPropCollection other) {
        charactersCovered = other.charactersCovered;
        indentLevel = other.indentLevel;
        maskSpecial = other.maskSpecial;
        textPropType = other.textPropType;
        other.textProps.forEach((k,v) -> textProps.put(k, v.copy()));

    public int getSpecialMask() {
        return maskSpecial;

    /** Fetch the number of characters this styling applies to */
    public int getCharactersCovered() {
        return charactersCovered;

    /** Fetch the TextProps that define this styling in the record order */
    public List<TextProp> getTextPropList() {
        List<TextProp> orderedList = new ArrayList<>();
        for (TextProp potProp : getPotentialProperties()) {
            TextProp textProp = textProps.get(potProp.getName());
            if (textProp != null) {
        return orderedList;

    /** Fetch the TextProp with this name, or null if it isn't present */
    public final <T extends TextProp> T findByName(String textPropName) {
        return (T)textProps.get(textPropName);

    public final <T extends TextProp> T removeByName(String name) {
        return (T)textProps.remove(name);

    public final TextPropType getTextPropType() {
        return textPropType;

    private TextProp[] getPotentialProperties() {
        return (textPropType == TextPropType.paragraph) ? paragraphTextPropTypes : characterTextPropTypes;

     * Checks the paragraph or character properties for the given property name.
     * Throws a HSLFException, if the name doesn't belong into this set of properties
     * @param name the property name
     * @return if found, the property template to copy from
    private <T extends TextProp> T validatePropName(final String name) {
       for (TextProp tp : getPotentialProperties()) {
            if (tp.getName().equals(name)) {
                return (T)tp;
       String errStr =
           "No TextProp with name " + name + " is defined to add from. " +
           "Character and paragraphs have their own properties/names.";
       throw new HSLFException(errStr);

    /** Add the TextProp with this name to the list */
    public final <T extends TextProp> T addWithName(final String name) {
        // Find the base TextProp to base on
        T existing = findByName(name);
        if (existing != null) return existing;

        // Add a copy of this property
        T textProp = (T)validatePropName(name).copy();
        return textProp;

     * Add the property at the correct position. Replaces an existing property with the same name.
     * @param textProp the property to be added
    public final void addProp(TextProp textProp) {
        if (textProp == null) {
            throw new HSLFException("TextProp must not be null");

        String propName = textProp.getName();

        textProps.put(propName, textProp);

     * For an existing set of text properties, build the list of
     *  properties coded for in a given run of properties.
     * @return the number of bytes that were used encoding the properties list
    public int buildTextPropList(int containsField, byte[] data, int dataOffset) {
        int bytesPassed = 0;

        // For each possible entry, see if we match the mask
        // If we do, decode that, save it, and shuffle on
        for(TextProp tp : getPotentialProperties()) {
            // Check there's still data left to read

            // Check if this property is found in the mask
            if((containsField & tp.getMask()) != 0) {
                if(dataOffset+bytesPassed >= data.length) {
                    // Out of data, can't be any more properties to go
                    // remember the mask and return
                    maskSpecial |= tp.getMask();
                    return bytesPassed;

                // Bingo, data contains this property
                TextProp prop = tp.copy();
                int val = 0;
                if (prop instanceof HSLFTabStopPropCollection) {
                    ((HSLFTabStopPropCollection)prop).parseProperty(data, dataOffset+bytesPassed);
                } else if (prop.getSize() == 2) {
                    val = LittleEndian.getShort(data,dataOffset+bytesPassed);
                } else if(prop.getSize() == 4) {
                    val = LittleEndian.getInt(data,dataOffset+bytesPassed);
                } else if (prop.getSize() == 0) {
                    //remember "special" bits.
                    maskSpecial |= tp.getMask();

                if (prop instanceof BitMaskTextProp) {
                    ((BitMaskTextProp)prop).setValueWithMask(val, containsField);
                } else if (!(prop instanceof HSLFTabStopPropCollection)) {
                bytesPassed += prop.getSize();

        // Return how many bytes were used
        return bytesPassed;

     * Clones the given text properties
    public TextPropCollection copy() {
        return new TextPropCollection(this);

     * Update the size of the text that this set of properties
     *  applies to
    public void updateTextSize(int textSize) {
        charactersCovered = textSize;

     * Writes out to disk the header, and then all the properties
    public void writeOut(OutputStream o) throws IOException {
        writeOut(o, false);

     * Writes out to disk the header, and then all the properties
    public void writeOut(OutputStream o, boolean isMasterStyle) throws IOException {
        if (!isMasterStyle) {
            // First goes the number of characters we affect
            // MasterStyles don't have this field

        // Then we have the indentLevel field if it's a paragraph collection
        if (textPropType == TextPropType.paragraph && indentLevel > -1) {
            Record.writeLittleEndian(indentLevel, o);

        // Then the mask field
        int mask = maskSpecial;
        for (TextProp textProp : textProps.values()) {
            mask |= textProp.getWriteMask();

        // Then the contents of all the properties
        for (TextProp textProp : getTextPropList()) {
            int val = textProp.getValue();
            if (textProp instanceof BitMaskTextProp && textProp.getWriteMask() == 0) {
                // don't add empty properties, as they can't be recognized while reading
            } else if (textProp.getSize() == 2) {
            } else if (textProp.getSize() == 4) {
            } else if (textProp instanceof HSLFTabStopPropCollection) {

    public short getIndentLevel(){
        return indentLevel;

    public void setIndentLevel(short indentLevel) {
        if (textPropType == TextPropType.character) {
            throw new RuntimeException("trying to set an indent on a character collection.");
        this.indentLevel = indentLevel;

    public int hashCode() {
        return Objects.hash(charactersCovered,maskSpecial,indentLevel,textProps);
     * compares most properties apart of the covered characters length
    public boolean equals(Object other) {
        if (this == other) return true;
        if (other == null) return false;
        if (getClass() != other.getClass()) return false;

        TextPropCollection o = (TextPropCollection)other;
        if (o.maskSpecial != this.maskSpecial || o.indentLevel != this.indentLevel) {
            return false;

        return textProps.equals(o.textProps);

    public String toString() {
        StringBuilder out = new StringBuilder();
        out.append("  chars covered: ").append(getCharactersCovered());
        out.append("  special mask flags: 0x").append(HexDump.toHex(getSpecialMask())).append("\n");
        if (textPropType == TextPropType.paragraph) {
            out.append("  indent level: ").append(getIndentLevel()).append("\n");
        for(TextProp p : getTextPropList()) {
            out.append("    ");
            if (p instanceof BitMaskTextProp) {
                BitMaskTextProp bm = (BitMaskTextProp)p;
                int i = 0;
                for (String s : bm.getSubPropNames()) {
                    if (bm.getSubPropMatches()[i]) {
                        out.append("          ").append(s).append(" = ").append(bm.getSubValue(i)).append("\n");

        out.append("  bytes that would be written: \n");

        try {
            UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream();
            byte[] b = baos.toByteArray();
            out.append(HexDump.dump(b, 0, 0));
        } catch (IOException e ) {
            LOG.atError().withThrowable(e).log("can't dump TextPropCollection");

        return out.toString();

    public Map<String, Supplier<?>> getGenericProperties() {
        Map<String,Supplier<?>> m = new LinkedHashMap<>();
        m.put("charactersCovered", this::getCharactersCovered);
        m.put("indentLevel", this::getIndentLevel);
        textProps.forEach((s,t) -> m.put(s, () -> t));
        m.put("maskSpecial", this::getSpecialMask);
        m.put("textPropType", this::getTextPropType);
        return Collections.unmodifiableMap(m);


Or download all of them as a single archive file:

File name: poi-scratchpad-5.2.3-src.zip
File size: 1238744 bytes
Release date: 2022-09-09


What Is poi-examples-5.2.3.jar?

What Is poi-excelant-5.2.3.jar?

Downloading and Installing Apache POI Java Library

⇑⇑ FAQ for Apache POI (Poor Obfuscation Implementation)

2017-03-22, 5841👍, 0💬