/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter Unisharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

package com.pullenti.unitext.internal.word;

public class ReaderUtils {

    public static final int headerDIFATSectorsCount = 109;

    public static final int directoryEntrySize = 128;

    public static final int headerSize = 512;

    public static CFHeader readHeader(com.pullenti.unisharp.Stream s) throws Exception, java.io.IOException {
        s.setPosition(0L);
        byte[] headerBytes = new byte[headerSize];
        int headerRead = s.read(headerBytes, 0, headerSize);
        if (headerRead != headerSize) 
            throw new Exception("Invalid header: eof of file");
        CFHeader header = new CFHeader();
        header.signature1 = java.nio.ByteBuffer.wrap(headerBytes, 0, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.signature2 = java.nio.ByteBuffer.wrap(headerBytes, 4, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.minorVersion = java.nio.ByteBuffer.wrap(headerBytes, 24, 2).order(java.nio.ByteOrder.LITTLE_ENDIAN).getShort();
        header.majorVersion = java.nio.ByteBuffer.wrap(headerBytes, 26, 2).order(java.nio.ByteOrder.LITTLE_ENDIAN).getShort();
        header.byteOrder = java.nio.ByteBuffer.wrap(headerBytes, 28, 2).order(java.nio.ByteOrder.LITTLE_ENDIAN).getShort();
        header.sectorShift = java.nio.ByteBuffer.wrap(headerBytes, 30, 2).order(java.nio.ByteOrder.LITTLE_ENDIAN).getShort();
        header.miniSectorShift = java.nio.ByteBuffer.wrap(headerBytes, 32, 2).order(java.nio.ByteOrder.LITTLE_ENDIAN).getShort();
        header.reserved = getByteArrayPortion(headerBytes, 34, 6);
        header.directorySectorsCount = java.nio.ByteBuffer.wrap(headerBytes, 40, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.fATSectorsCount = java.nio.ByteBuffer.wrap(headerBytes, 44, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.firstDirectorySectorLocation = java.nio.ByteBuffer.wrap(headerBytes, 48, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.transactionSignatureNumber = java.nio.ByteBuffer.wrap(headerBytes, 52, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.miniStreamCutoffSize = java.nio.ByteBuffer.wrap(headerBytes, 56, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.firstMiniFATSectorLocation = java.nio.ByteBuffer.wrap(headerBytes, 60, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.miniFATSectorsCount = java.nio.ByteBuffer.wrap(headerBytes, 64, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.firstDIFATSectorLocation = java.nio.ByteBuffer.wrap(headerBytes, 68, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.dIFATSectorsCount = java.nio.ByteBuffer.wrap(headerBytes, 72, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        header.dIFAT = new int[headerDIFATSectorsCount];
        for (int i = 0; i < headerDIFATSectorsCount; i++) {
            header.dIFAT[i] = java.nio.ByteBuffer.wrap(headerBytes, 76 + (i * 4), 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        }
        return header;
    }

    public static byte[] readFragment(com.pullenti.unisharp.Stream s, int streamOffset, int length) throws Exception, java.io.IOException {
        byte[] data = new byte[length];
        s.setPosition((long)streamOffset);
        int read = s.read(data, 0, length);
        if (read <= 0) 
            throw new Exception("Unexcpected eof of file");
        return data;
    }

    public static int readUInt32(com.pullenti.unisharp.Stream s, int streamOffset) throws Exception, java.io.IOException {
        return java.nio.ByteBuffer.wrap(readFragment(s, streamOffset, 4), 0, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
    }

    public static int[] readArrayOfUInt32(com.pullenti.unisharp.Stream s, int streamOffset, int count) throws Exception, java.io.IOException {
        int[] array = new int[count];
        byte[] data = readFragment(s, streamOffset, 4 * count);
        for (int i = 0; i < count; i++) {
            array[i] = java.nio.ByteBuffer.wrap(data, 4 * i, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        }
        return array;
    }

    public static CFDirectoryEntry readDirectoryEntry(com.pullenti.unisharp.Stream s, int streamOffset, boolean isVersion3) throws Exception, java.io.IOException {
        byte[] data = readFragment(s, streamOffset, directoryEntrySize);
        CFDirectoryEntry entry = new CFDirectoryEntry();
        entry.nameLength = java.nio.ByteBuffer.wrap(data, 64, 2).order(java.nio.ByteOrder.LITTLE_ENDIAN).getShort();
        int nameLength = Math.min(32, (Short.toUnsignedInt(entry.nameLength)) / 2);
        entry.name = new char[nameLength];
        for (int i = 0; i < nameLength; i++) {
            entry.name[i] = java.nio.ByteBuffer.wrap(data, 2 * i, 2).order(java.nio.ByteOrder.LITTLE_ENDIAN).getChar();
        }
        entry.objectType = data[66];
        entry.colorFlag = data[67];
        entry.leftSiblingID = java.nio.ByteBuffer.wrap(data, 68, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        entry.rightSiblingID = java.nio.ByteBuffer.wrap(data, 72, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        entry.childID = java.nio.ByteBuffer.wrap(data, 76, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        entry.stateBits = java.nio.ByteBuffer.wrap(data, 96, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        entry.startingSectorLocation = java.nio.ByteBuffer.wrap(data, 116, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        entry.streamSize = java.nio.ByteBuffer.wrap(data, 120, 4).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
        if (isVersion3) 
            entry.streamSize &= ((int)0xFFFFFFFF);
        return entry;
    }

    public static void validateHeader(CFHeader header) throws Exception {
        if (Integer.compareUnsigned(header.signature1, CFHeader.defaultSignature1) != 0 || Integer.compareUnsigned(header.signature2, CFHeader.defaultSignature2) != 0) 
            throw new Exception("Invalid header: signature");
        if (!header.cLSID.equals(com.pullenti.unisharp.Utils.EMPTYUUID)) {
        }
        if (Integer.compareUnsigned(header.minorVersion, (short)0x3E) != 0) {
        }
        if (Integer.compareUnsigned(header.majorVersion, (short)3) != 0 && Integer.compareUnsigned(header.majorVersion, (short)4) != 0) 
            throw new Exception("Invalid header: Major version");
        if (Integer.compareUnsigned(header.byteOrder, (short)0xFFFE) != 0) 
            throw new Exception("Invalid header: Byte order");
        if (Integer.compareUnsigned(header.majorVersion, (short)3) == 0 && Integer.compareUnsigned(header.sectorShift, (short)0x0009) != 0) 
            throw new Exception("Invalid header: Sector shirt for v3");
        if (Integer.compareUnsigned(header.majorVersion, (short)4) == 0 && Integer.compareUnsigned(header.sectorShift, (short)0x000c) != 0) 
            throw new Exception("Invalid header: Sector shirt for v4");
        if (Integer.compareUnsigned(header.miniSectorShift, (short)0x0006) != 0) 
            throw new Exception("Invalid header: Mini sector shirt");
        if (((header.reserved[0] != ((byte)0) || header.reserved[1] != ((byte)0) || header.reserved[2] != ((byte)0)) || header.reserved[3] != ((byte)0) || header.reserved[4] != ((byte)0)) || header.reserved[5] != ((byte)0)) 
            throw new Exception("Invalid header: Reserved");
        if (Integer.compareUnsigned(header.majorVersion, (short)3) == 0 && Integer.compareUnsigned(header.directorySectorsCount, (int)0) != 0) 
            throw new Exception("Invalid header: Directory sectors for v3");
        if (Integer.compareUnsigned(header.miniStreamCutoffSize, (int)0x1000) != 0) 
            throw new Exception("Invalid header: Mini stream cutoff size");
    }

    public static void validateDirectoryEntry(CFDirectoryEntry entry) throws Exception {
        int len = Short.toUnsignedInt(entry.nameLength);
        if ((entry.name.length * 2) != len || len == 0) 
            throw new Exception("Invalid directory entry: name length");
        if (((int)entry.name[entry.name.length - 1]) != 0) 
            throw new Exception("Invalid directory entry: name null termination");
        for (char ch : entry.name) {
            if ((ch == '/' || ch == '\\' || ch == ':') || ch == '!') 
                throw new Exception("Invalid directory entry: illegal char in name");
        }
        if ((entry.objectType != DirectoryObjectTypes.unknown && entry.objectType != DirectoryObjectTypes.storage && entry.objectType != DirectoryObjectTypes.stream) && entry.objectType != DirectoryObjectTypes.rootStorage) 
            throw new Exception("Invalid directory entry: object type");
        if (entry.colorFlag != TreeColors.red && entry.colorFlag != TreeColors.black) 
            throw new Exception("Invalid directory entry: color flag");
        if (Integer.compareUnsigned(entry.leftSiblingID, DirectoryStreamIds.mAXREGSID) > 0 && Integer.compareUnsigned(entry.leftSiblingID, DirectoryStreamIds.nOSTREAM) != 0) 
            throw new Exception("Invalid directory entry: left sibling");
        if (Integer.compareUnsigned(entry.rightSiblingID, DirectoryStreamIds.mAXREGSID) > 0 && Integer.compareUnsigned(entry.rightSiblingID, DirectoryStreamIds.nOSTREAM) != 0) 
            throw new Exception("Invalid directory entry: right sibling");
        if (Integer.compareUnsigned(entry.childID, DirectoryStreamIds.mAXREGSID) > 0 && Integer.compareUnsigned(entry.childID, DirectoryStreamIds.nOSTREAM) != 0) 
            throw new Exception("Invalid directory entry: child");
    }

    private static byte[] getByteArrayPortion(byte[] source, int offset, int length) {
        byte[] bytes = new byte[length];
        for(int iii = 0; iii < (length); iii++) bytes[(0) + iii] = source[(offset) + iii];
        return bytes;
    }
    public ReaderUtils() {
    }
}
