Rev 3408 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2012.
*
* 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.mdr;
import java.nio.charset.Charset;
import java.text.Collator;
import java.util.ArrayList;
import java.util.List;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
import uk.me.parabola.imgfmt.app.srt.Sort;
/**
* Holds an index of name prefixes to record numbers.
*
* Extends MdrSection, although is sometimes a subsection, not an actual section.
*
* @author Steve Ratcliffe
*/
public class PrefixIndex
extends MdrSection
{
private final int prefixLength
;
private int maxIndex
;
// We use mdr8record for all similar indexes.
private final List<Mdr8Record
> index =
new ArrayList<>();
/**
* Sets the config and the prefix length for this index.
*
* Prefix length may differ depending on the amount of data, so will have
* to deal with that when it happens.
*
* @param config Configuration for sorting methods.
* @param prefixLength The prefix length for this index.
*/
public PrefixIndex
(MdrConfig config,
int prefixLength
) {
setConfig
(config
);
this.
prefixLength = prefixLength
;
}
/**
* We can create an index for any type that has a name.
* @param list A list of items that have a name.
*/
public void createFromList
(List<? extends NamedRecord
> list,
boolean grouped
) {
maxIndex = list.
size();
// Prefixes are equal based on the primary unaccented character, so
// we need to use the collator to test for equality and not equals().
Sort sort = getConfig
().
getSort();
Collator collator = sort.
getCollator();
collator.
setStrength(Collator.
PRIMARY);
String lastCountryName =
null;
String lastPrefix =
"";
int inRecord =
0; // record number of the input list
int outRecord =
0; // record number of the index
for (NamedRecord r : list
) {
inRecord++
;
String prefix = getPrefix
(r.
getName());
if (collator.
compare(prefix, lastPrefix
) !=
0) {
outRecord++
;
Mdr8Record ind =
new Mdr8Record
();
ind.
setPrefix(prefix
);
ind.
setRecordNumber(inRecord
);
index.
add(ind
);
lastPrefix = prefix
;
if (grouped
) {
// Peek into the real type to support the mdr17 feature of indexes sorted on country.
Mdr5Record city =
((Mdr7Record
) r
).
getCity();
if (city
!=
null) {
String countryName = city.
getCountryName();
if (!countryName.
equals(lastCountryName
)) {
city.
getMdrCountry().
getMdr29().
setMdr17(outRecord
);
lastCountryName = countryName
;
}
}
}
}
}
}
public void createFromList
(List<? extends NamedRecord
> list
) {
createFromList
(list,
false);
}
/**
* Write the section or subsection.
*/
public void writeSectData
(ImgFileWriter writer
) {
int size = numberToPointerSize
(maxIndex
);
Charset charset = getConfig
().
getSort().
getCharset();
for (Mdr8Record s : index
) {
writer.
put(s.
getPrefix().
getBytes(charset
),
0, prefixLength
);
putN
(writer, size, s.
getRecordNumber());
}
}
public int getItemSize
() {
return prefixLength + numberToPointerSize
(maxIndex
);
}
protected int numberOfItems
() {
return index.
size();
}
/**
* Get the prefix of the name at the given record.
* If the name is shorter than the prefix length, then it padded with nul characters.
* So it can be longer than the input string.
*
* @param in The name to truncate.
* @return A string prefixLength characters long, consisting of the initial
* prefix of name and padded with nulls if necessary to make up the length.
*/
private String getPrefix
(String in
) {
StringBuilder sb =
new StringBuilder();
char[] chars = in.
toCharArray();
int ci =
0;
for (int i =
0; i
< prefixLength
; i++
) {
char c =
0;
while (ci
< chars.
length) {
// TODO: simplify when initial spaces are removed
c = chars
[ci++
];
if (ci ==
1 && c== 0x20
)
continue;
if (c
>= 0x20
)
break;
}
sb.
append(c
);
}
return sb.
toString();
}
public int getPrefixLength
() {
return prefixLength
;
}
}