SquirrelJME/SquirrelJME

View on GitHub
tools/pcf-to-sqf/src/main/java/net/multiphasicapps/pcftosqf/pcf/PCFBitmap.java

Summary

Maintainability
A
0 mins
Test Coverage
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// SquirrelJME
//     Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------

package net.multiphasicapps.pcftosqf.pcf;

import cc.squirreljme.runtime.cldc.util.SortedTreeSet;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * This represents the bitmap from within a PCF file.
 *
 * @since 2018/11/28
 */
public final class PCFBitmap
{
    /** The format. */
    public final int format;
    
    /** The number of glyphs. */
    public final int numglyphs;
    
    /** The glyph map. */
    public final Map<Integer, PCFGlyphMap> glyphmaps;
    
    /**
     * Initializes the bitmap data.
     *
     * @param __format The format used.
     * @param __numglyphs The glyphs used.
     * @param __offsets The offsets.
     * @param __data The data.
     * @throws NullPointerException On null arguments.
     * @since 2018/11/28
     */
    public PCFBitmap(int __format, int __numglyphs, int[] __offsets,
        byte[] __data)
        throws NullPointerException
    {
        if (__offsets == null || __data == null)
            throw new NullPointerException("NARG");
        
        this.format = __format;
        this.numglyphs = __numglyphs;
        
        // This class is used to sort all of the offsets but still keep the
        // original indexes
        final class __Index__
            implements Comparable<__Index__>
        {
            /** The offset. */
            public final int offset;
            
            /** The index. */
            public final int index;
            
            /**
             * Initializes the index.
             *
             * @param __o The offset.
             * @param __i The index.
             * @since 2018/11/29
             */
            __Index__(int __o, int __i)
            {
                this.offset = __o;
                this.index = __i;
            }
            
            /**
             * {@inheritDoc}
             * @since 2018/11/29
             */
            @Override
            public int compareTo(__Index__ __o)
            {
                // Sort by the offset first, but it is possible that some
                // glyphs might share the same offset, so do not lose them!
                int rv = this.offset - __o.offset;
                if (rv != 0)
                    return rv;
                return this.index - __o.index;
            }
        }
        
        // Go through all the offsets and determine all of the bounds
        Set<__Index__> index = new SortedTreeSet<>();
        for (int i = 0; i < this.numglyphs; i++)
            index.add(new __Index__(__offsets[i], i));
        
        // Need to determine the bounds for every glyph to extract the data
        // for it, so mark when an index ends and such. So go through
        // and mark where a new glyph starts.
        int datalen = __data.length;
        boolean[] boops = new boolean[datalen];
        for (__Index__ i : index)
            boops[i.offset] = true;
        
        // Build the bitmaps for each map of glyphs so they can be converted
        // accordingly
        Map<Integer, PCFGlyphMap> glyphmaps = new HashMap<>();
        for (__Index__ i : index)
        {
            // Start with a dynamic set of copied byte data
            List<Byte> bm = new ArrayList<>();
            
            // Add all the bits that make up the glyph data there
            for (int o = i.offset; o < datalen;)
            {
                // Add this byte always
                bm.add(__data[o++]);
                
                // Since we are at the next index check for the end or if
                // it signaled a new glyph here
                if (o >= datalen || boops[o])
                    break;
            }
            
            // Store the glyph data
            glyphmaps.put(i.index, new PCFGlyphMap(bm));
        }
        
        this.glyphmaps = glyphmaps;
    }
    
    /**
     * Reads the bitmap data.
     *
     * @param __dis The input stream.
     * @return The resulting bitmap.
     * @throws IOException On read errors.
     * @throws NullPointerException On null arguments.
     * @since 2018/11/28
     */
    public static final PCFBitmap read(DataInputStream __dis)
        throws IOException, NullPointerException
    {
        if (__dis == null)
            throw new NullPointerException("NARG");
        
        // Format
        int format = Integer.reverseBytes(__dis.readInt());
        
        // Read the glyph offsets
        int numglyphs = __dis.readInt();
        int[] offsets = new int[numglyphs];
        for (int i = 0; i < numglyphs; i++)
            offsets[i] = __dis.readInt();
        
        // Read all four bitmap sizes
        int[] bitmapsizes = new int[4];
        for (int i = 0; i < 4; i++)
            bitmapsizes[i] = __dis.readInt();
        
        // The bytes depends on the format
        byte[] data = new byte[bitmapsizes[format & 3]];
        __dis.readFully(data);
        
        // Build bitmap
        return new PCFBitmap(format, numglyphs, offsets, data);
    }
}