/*
* Copyright (C) 2006 Steve Ratcliffe
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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.
*
*
* Author: Steve Ratcliffe
* Create date: 03-Dec-2006
* Change: Thomas Lußnig <gps@suche.org>
*/
package uk.me.parabola.imgfmt.app.typ;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import uk.me.parabola.imgfmt.Utils;
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.Section;
import uk.me.parabola.imgfmt.app.SectionWriter;
import uk.me.parabola.imgfmt.app.srt.Sort;
import uk.me.parabola.imgfmt.app.srt.SortKey;
import uk.me.parabola.imgfmt.fs.ImgChannel;
import uk.me.parabola.log.Logger;
/**
* The TYP file.
*
* @author Thomas Lußnig
* @author Steve Ratcliffe
*/
public class TYPFile
extends ImgFile
{
private static final Logger log =
Logger.
getLogger(TYPFile.
class);
private final TYPHeader header =
new TYPHeader
();
private TypData data
;
private final Map<Integer,
Integer> strToType =
new TreeMap<Integer,
Integer>();
private final Map<Integer,
Integer> typeToStr =
new TreeMap<Integer,
Integer>();
public TYPFile
(ImgChannel chan
) {
setHeader
(header
);
setWriter
(new BufferedImgFileWriter
(chan
));
position
(TYPHeader.
HEADER_LEN);
}
public void write
() {
ImgFileWriter writer = getWriter
();
writer.
position(TYPHeader.
HEADER_LEN);
writeSection
(writer, header.
getPolygonData(), header.
getPolygonIndex(), data.
getPolygons());
writeSection
(writer, header.
getLineData(), header.
getLineIndex(), data.
getLines());
writeSection
(writer, header.
getPointData(), header.
getPointIndex(), data.
getPoints());
SectionWriter subWriter = header.
getShapeStacking().
makeSectionWriter(writer
);
data.
getStacking().
write(subWriter
);
Utils.
closeFile(subWriter
);
writeSection
(writer, header.
getIconData(), header.
getIconIndex(), data.
getIcons());
writeLabels
(writer
);
writeStrIndex
(writer
);
writerTypeIndex
(writer
);
zapZero
(header.
getShapeStacking(), header.
getLabels(), header.
getStringIndex(), header.
getTypeIndex());
log.
debug("syncing TYP file");
position
(0);
getHeader
().
writeHeader(getWriter
());
}
private void writeLabels
(ImgFileWriter in
) {
if (data.
getIcons().
isEmpty())
return;
SectionWriter writer = header.
getLabels().
makeSectionWriter(in
);
List<SortKey<TypIconSet
>> keys =
new ArrayList<SortKey<TypIconSet
>>();
Sort sort = data.
getSort();
for (TypIconSet icon : data.
getIcons()) {
String label = icon.
getLabel();
if (label
!=
null) {
SortKey<TypIconSet
> key = sort.
createSortKey(icon, label
);
keys.
add(key
);
}
}
Collections.
sort(keys
);
// Offset 0 is reserved to mean no label.
writer.
put((byte) 0);
for (SortKey<TypIconSet
> key : keys
) {
int off = writer.
position();
TypIconSet icon = key.
getObject();
int type = icon.
getTypeForFile();
String label = icon.
getLabel();
if (label
!=
null) {
CharBuffer cb =
CharBuffer.
wrap(label
);
CharsetEncoder encoder = data.
getEncoder();
try {
ByteBuffer buffer = encoder.
encode(cb
);
writer.
put(buffer
);
// If we succeeded then note offsets for indexes
strToType.
put(off, type
);
typeToStr.
put(type, off
);
} catch (CharacterCodingException ignore
) {
String name = encoder.
charset().
name();
throw new TypLabelException
(name
);
}
writer.
put((byte) 0);
}
}
Utils.
closeFile(writer
);
}
private void writeStrIndex
(ImgFileWriter in
) {
SectionWriter writer = header.
getStringIndex().
makeSectionWriter(in
);
int psize = ptrSize
(header.
getLabels().
getSize());
header.
getStringIndex().
setItemSize((char) (3 + psize
));
for (Map.Entry<Integer,
Integer> ent : strToType.
entrySet()) {
putN
(writer, psize, ent.
getKey());
putN
(writer,
3, ent.
getValue());
}
Utils.
closeFile(writer
);
}
private void writerTypeIndex
(ImgFileWriter in
) {
SectionWriter writer = header.
getTypeIndex().
makeSectionWriter(in
);
int psize = ptrSize
(header.
getLabels().
getSize());
header.
getTypeIndex().
setItemSize((char) (3 + psize
));
for (Map.Entry<Integer,
Integer> ent : typeToStr.
entrySet()) {
putN
(writer,
3, ent.
getKey());
putN
(writer, psize, ent.
getValue());
}
Utils.
closeFile(writer
);
}
private void writeSection
(ImgFileWriter writer, Section dataSection, Section indexSection,
List<? extends TypElement
> elementData
)
{
Collections.
sort(elementData
);
SectionWriter subWriter = dataSection.
makeSectionWriter(writer
);
CharsetEncoder encoder = data.
getEncoder();
for (TypElement elem : elementData
)
elem.
write(subWriter, encoder
);
Utils.
closeFile(subWriter
);
int size = dataSection.
getSize();
int typeSize = indexSection.
getItemSize();
int psize = ptrSize
(size
);
indexSection.
setItemSize((char) (typeSize + psize
));
subWriter = indexSection.
makeSectionWriter(writer
);
for (TypElement elem : elementData
) {
int offset = elem.
getOffset();
int type = elem.
getTypeForFile();
putN
(subWriter, typeSize, type
);
putN
(subWriter, psize, offset
);
}
Utils.
closeFile(subWriter
);
zapZero
(dataSection, indexSection
);
}
private void zapZero
(Section...
sect) {
for (Section s : sect
) {
if (s.
getSize() ==
0) {
s.
setPosition(0);
s.
setItemSize((char) 0);
}
}
}
private int ptrSize
(int size
) {
int psize =
1;
if (size
> 0xffffff
)
psize =
4;
else if (size
> 0xffff
)
psize =
3;
else if (size
> 0xff
)
psize =
2;
return psize
;
}
protected void putN
(ImgFileWriter writer,
int n,
int value
) {
switch (n
) {
case 1:
writer.
put((byte) value
);
break;
case 2:
writer.
putChar((char) value
);
break;
case 3:
writer.
put3(value
);
break;
case 4:
writer.
putInt(value
);
break;
default:
// Don't write anything.
assert false;
break;
}
}
public void setData
(TypData data
) {
this.
data = data
;
TypParam param = data.
getParam();
header.
setCodePage((char) param.
getCodePage());
header.
setFamilyId((char) param.
getFamilyId());
header.
setProductId((char) param.
getProductId());
}
}