/*
* 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();
}
}