Subversion Repositories mkgmap

Rev

Rev 3408 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2010.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 or
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

package uk.me.parabola.imgfmt.app.srt;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
import uk.me.parabola.imgfmt.app.ImgFile;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
import uk.me.parabola.imgfmt.app.SectionWriter;
import uk.me.parabola.imgfmt.fs.ImgChannel;

/**
 * The SRT file. This contains a table showing the sort order of
 * the characters that is being used.
 *
 * @author Steve Ratcliffe
 */

public class SRTFile extends ImgFile {

        private final SRTHeader header;

        private Sort sort;
        private boolean isMulti;
       
        private String description;

        private final List<Integer> srt8Starts = new ArrayList<>();

        public SRTFile(ImgChannel chan) {
                header = new SRTHeader();
                setHeader(header);

                BufferedImgFileWriter fileWriter = new BufferedImgFileWriter(chan);
                fileWriter.setMaxSize(Long.MAX_VALUE);
                setWriter(fileWriter);

                // Position at the start of the writable area.
                position(header.getHeaderLength());
        }

        /**
         * Write out the file.
         * This file has an unusual layout. There are several header like structures within
         * the main body of the file, with the real header being very small.
         */

        public void write() {
                ImgFileWriter writer = getWriter();
                writeDescription(writer);

                SectionWriter subWriter = header.makeSectionWriter(writer);
                subWriter.position(sort.isMulti()? SRTHeader.HEADER3_MULTI_LEN: SRTHeader.HEADER3_LEN);
                writeSrt4Chars(subWriter);
                writeSrt5Expansions(subWriter);
                if (sort.isMulti()) {
                        for (int i = 0; i <= sort.getMaxPage(); i++)
                                srt8Starts.add(-1);
                        writeSrt8(subWriter);
                        writeSrt7(subWriter);
                }
                subWriter.close();

                // Header 2 is just after the real header
                writer.position(header.getHeaderLength());
                header.writeHeader2(writer);

                // Header 3 is after the description
                writer.position(header.getHeaderLength() + description.length() + 1 + SRTHeader.HEADER2_LEN);
                header.writeHeader3(writer);

                header.writeHeader(writer);
        }

        private void writeDescription(ImgFileWriter writer) {
                writer.position(header.getHeaderLength() + SRTHeader.HEADER2_LEN);
                writer.put(description.getBytes(Charset.forName("ascii")));
                writer.put((byte) 0);
                header.endDescription(writer.position());
        }

        /**
         * Write SRT4 the character table.
         *
         * @param writer The img file writer.
         */

        private void writeSrt4Chars(ImgFileWriter writer) {
                for (int i = 1; i < 256; i++) {
                        writer.put(sort.getFlags(i));
                        writeWeights(writer, i);
                }
                header.endCharTable(writer.position());
        }

        private void writeWeights(ImgFileWriter writer, int i) {
                if (isMulti) {
                        writer.putChar((char) sort.getPrimary(i));
                        writer.put((byte) sort.getSecondary(i));
                        writer.put((byte) sort.getTertiary(i));
                } else {
                        writer.put((byte) sort.getPrimary(i));
                        writer.put((byte) ((sort.getTertiary(i) << 4) | (sort.getSecondary(i) & 0xf)));
                }
        }

        /**
         * Write SRT5, the expansion table.
         *
         * Write out the expansion table. This is referenced from the character table, when
         * the top nibble of the type is set via the primary position value.
         */

        private void writeSrt5Expansions(ImgFileWriter writer) {

                int size = sort.getExpansionSize();
                for (int j = 1; j <= size; j++) {
                        CodePosition b = sort.getExpansion(j);
                        if (isMulti) {
                                writer.putChar(b.getPrimary());
                                writer.put(b.getSecondary());
                                writer.put(b.getTertiary());
                        } else {
                                writer.put((byte) b.getPrimary());
                                writer.put((byte) ((b.getTertiary() << 4) | (b.getSecondary() & 0xf)));
                        }
                }

                header.endTab2(writer.position());
        }

        private void writeSrt7(SectionWriter writer) {
                assert sort.isMulti();
                for (int i = 1; i <= sort.getMaxPage(); i++) {
                        writer.putInt(srt8Starts.get(i));
                }
                header.endSrt7(writer.position());
        }

        private void writeSrt8(SectionWriter writer) {
                assert sort.isMulti();

                int offset = 0;
                for (int p = 1; p <= sort.getMaxPage(); p++) {
                        if (sort.hasPage(p)) {
                                srt8Starts.set(p, offset);
                                for (int j = 0; j < 256; j++) {
                                        int ch = p * 256 + j;
                                        writer.put(sort.getFlags(ch));
                                        writeWeights(writer, ch);
                                        offset += 5;
                                }
                        }
                }
                header.endSrt8(writer.position());
        }

        public void setSort(Sort sort) {
                this.sort = sort;
                header.setSort(sort);
                description = sort.getDescription();
                isMulti = sort.isMulti();
        }
}