Subversion Repositories mkgmap

Rev

Rev 4377 | 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 SRTHeader header;

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

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

        public SRTFile(ImgChannel chan) {
                BufferedImgFileWriter fileWriter = new BufferedImgFileWriter(chan, "SRT");
                fileWriter.setMaxSize(Long.MAX_VALUE);
                setWriter(fileWriter);
        }

        /**
         * 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);
                // Position at the start of the writable area.
                position(header.getHeaderLength());
                SectionWriter subWriter = header.makeSectionWriter(writer);
                int header3Len = sort.getHeader3Len();
                if (header3Len == 0)
                        header3Len = sort.isMulti()? SRTHeader.HEADER3_MULTI_LEN: SRTHeader.HEADER3_LEN;
                subWriter.position(header3Len);
                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.put1u( 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.put1u(sort.getFlags(i));
                        writeWeights(writer, i);
                }
                header.endCharTable(writer.position());
        }

        private void writeWeights(ImgFileWriter writer, int i) {
                int primary = sort.getPrimary(i);
                int secondary = sort.getSecondary(i);
                int tertiary = sort.getTertiary(i);
                if (isMulti) {
                        assert primary <= 0xffff : primary;
                        assert secondary <= 0xff : secondary;
                        assert tertiary <= 0xff : tertiary;
                        writer.put2u(primary);
                        writer.put1u(secondary);
                        writer.put1u(tertiary);
                } else {
                        assert primary <= 0xff : primary;
                        assert secondary <= 0xf : secondary;
                        assert tertiary <= 0xf : tertiary;
                        writer.put1u(primary);
                        writer.put1u((tertiary << 4) | (secondary & 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.put2u(b.getPrimary());
                                writer.put1u(b.getSecondary());
                                writer.put1u(b.getTertiary());
                        } else {
                                writer.put1u(b.getPrimary());
                                writer.put1u((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.put4(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.put1u(sort.getFlags(ch));
                                        writeWeights(writer, ch);
                                        offset += 5;
                                }
                        }
                }
                header.endSrt8(writer.position());
        }

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