ultimatepp/uppdev/vfk2/vfkstrm.cpp
cxl 351994a6cc Adding uppdev....
git-svn-id: svn://ultimatepp.org/upp/trunk@328 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-08-15 08:36:24 +00:00

1210 lines
31 KiB
C++

#include "vfkstrm.h"
static struct VFKLongName
{
const char *longname;
const char *shortname;
}
vfk_long_names[] =
{
{ "PARCELY", "PAR" },
{ "BUDOVY", "BUD" },
{ "CASTI_BUDOV", "CABU" },
{ "ZP_OCHRANY_NEM", "ZPOCHN" },
{ "D_POZEMKU", "DRUPOZ" },
{ "ZP_VYUZITI_POZ", "ZPVYPO" },
{ "ZDROJE_PARCEL_ZE", "ZDPAZE" },
{ "ZP_URCENI_VYMERY", "ZPURVY" },
{ "T_BUDOV", "TYPBUD" },
{ "MAPOVE_LISTY", "MAPLIS" },
{ "KATASTR_UZEMI", "KATUZE" },
{ "CASTI_OBCI", "CASOBC" },
{ "R_ZPOCHR", "RZO" },
{ "ZP_VYUZITI_BUD", "ZPVYBU" },
{ "JEDNOTKY", "JED" },
{ "T_JEDNOTEK", "TYPJED" },
{ "ZP_VYUZITI_JED", "ZPVYJE" },
{ "BONIT_DILY_PARC", "BDP" },
{ "OPRAV_SUBJEKTY", "OPSUB" },
{ "VLASTNICTVI", "VLA" },
{ "CHAR_OS", "CHAROS" },
{ "TELESA", "TEL" },
{ "JINE_PRAVNI_VZTAHY", "JPV" },
{ "T_PRAVNICH_VZTAHU", "TYPRAV" },
{ "RIZENI_KU", "RIZKU" },
{ "OBJEKTY_RIZENI", "OBJRIZ" },
{ "PREDMETY_RIZENI", "PRERIZ" },
{ "UCASTNICI", "UCAST" },
{ "ADRESY", "ADRUC" },
{ "LISTINY", "LISTIN" },
{ "DALSI_UDAJE_LISTINY", "DUL" },
{ "LISTINY_DALSI_UDAJE", "LDU" },
{ "T_LISTIN", "TYPLIS" },
{ "T_PREDMETU_R", "TYPPRE" },
{ "TYPY_RIZENI", "TYPRIZ" },
{ "TYPY_UCASTNIKU", "TYPUCA" },
{ "UCASTNICI_TYP", "UCTYP" },
{ "R_LIST", "RL" },
{ "SOURADNICE_OBRAZU", "SOBR" },
{ "SPOJENI_B_POLOH", "SBP" },
{ "SPOJENI_B_MAPY", "SBM" },
{ "KODY_CHAR_Q_BODU", "KODCHB" },
{ "T_SOURAD_SYS", "TYPSOS" },
{ "HRANICE_PARCEL", "HP" },
{ "OBRAZY_PARCEL", "OP" },
{ "OBRAZY_BUDOV", "OB" },
{ "DALSI_PRVKY_MAPY", "DPM" },
{ "OBRAZY_BODU_BP", "OBBP" },
{ "T_PRVKU_P_DAT", "TYPPPD" },
{ "HRANICE_BPEJ", "HBPEJ" },
{ "OZNACENI_BPEJ", "OBPEJ" },
{ "NAVRHY_ZMEN_KM", "NZ" },
{ "NZ_ZPMZ", "NZZP" },
{ "SOURADNICE_POLOHY", "SPOL" },
{ "REZ_PARCELNI_CISLA", "RECI" },
{ "DOTCENA_PAR_CISLA", "DOCI" },
{ "DOT_HIST_PAR_CISLA", "DOHICI" },
{ "SROVNAVACI_SESTAVENI", "SRST" },
{ 0 }
};
static bool IsPointMap(String name)
{
return name == "SPOJENI_B_MAPY"
|| name == "SOURADNICE_OBRAZU"
|| name == "DALSI_PRVKY_MAPY"
|| name == "OBRAZY_PARCEL"
|| name == "OBRAZY_BUDOV"
|| name == "OBRAZY_BODU_BP"
|| name == "SOURADNICE_POLOHY"
|| name == "PARCELY"
|| name == "BUDOVY";
}
inline bool IsIdent(char c)
{
return c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_';
}
static String GetVTypeName(int vtype)
{
switch(vtype) {
default:
case VOID_V: return "void";
case ERROR_V: return "error";
case UNKNOWN_V: return "unknown";
case VALUE_V: return "Value";
case INT_V: return "int";
case DOUBLE_V: return "double";
case INT64_V: return "int64";
case STRING_V: return "String";
case WSTRING_V: return "WString";
case DATE_V: return "Date";
case TIME_V: return "Time";
case VALUEARRAY_V: return "ValueArray";
return NFormat("unknown(%d)", vtype);
}
}
inline Time VfkReadTime(const char *p, void *endptr)
{
int fields[6];
ZeroArray(fields);
int nfld = 0;
for(;;)
if(IsDigit(*p)) {
int v = ScanInt(p, &p);
if(IsNull(v) || v < 0)
return Null;
fields[nfld++] = v;
if(nfld >= 6)
break;
}
else if(*p == ' ' || *p == ':' || *p == '.')
p++;
else
break;
if(endptr)
*(const char **)endptr = p;
if(nfld < 3)
return Null;
if(fields[0] >= 1 && fields[0] <= 31
&& fields[1] >= 1 && fields[1] <= 12
&& fields[2] >= 1900 && fields[2] <= 2900
&& fields[3] >= 0 && fields[3] <= 23
&& fields[4] >= 0 && fields[4] <= 59
&& fields[5] >= 0 && fields[5] <= 59) {
Time dt(fields[2], fields[1], fields[0], fields[3], fields[4], fields[5]);
if(dt.IsValid())
return dt;
}
return Null;
}
static String VFKParsePolvz(const char *text)
{
for(; *text; text++)
if(text[0] == 'P' && text[1] == 'O' && text[2] == 'L' && text[3] == 'V' && text[4] == 'Z' && text[5] == ':') {
text += 6;
while(*text && (byte)*text <= ' ')
text++;
const char *b = text;
bool slash = false;
while(*text && (byte)*text > ' ')
if(*text++ == '/')
slash = true;
String out;
int len = text - b;
if(slash || len <= 4)
out = String(b, text);
else {
out.Cat(b, len - 4);
out.Cat('/');
out.Cat(text - 4, 4);
}
return out;
}
return Null;
}
static String VFKParseDOPLKOD(String s)
{
const char *p = s;
while(*p && !(p[0] == '/' && p[1] == ' ' && p[2] == 'D' && p[3] == 'O'
&& p[4] == 'P' && p[5] == 'L' && p[6] == 'K' && p[7] == 'O' && p[8] == 'D'))
p++;
if(!*p)
return s;
while(p > s.Begin() && (byte)p[-1] <= ' ')
p--;
return s.Left(p - s.Begin());
}
/*
void VfkStream::Table::FlushCache()
{
scanned = scanned_sbp = scanned_sobr = false;
row_offsets.Clear();
segment_index.Clear();
point_index.Clear();
extents.Clear();
points.Clear();
sobr_map.Clear();
par_ku_map.Clear();
cobce_obec_map.Clear();
tel_ku_map.Clear();
bud_id_index.Clear();
bud_id_zdb.Clear();
bud_id_ob.Clear();
ku_index.Clear();
obec_kod_index.Clear();
}
*/
int VfkStream::Table::SizeOfInstance() const
{
return columns.GetCount() * 100
/*
+ row_offsets.GetCount() * sizeof(int)
+ segment_index.GetCount() * sizeof(int) + point_index.GetCount() * sizeof(int)
+ extents.GetCount() * sizeof(Rectf) + points.GetCount() * sizeof(const Pointf *)
+ sobr_map.GetCount() * (sizeof(double) + sizeof(Pointf) + 4 * sizeof(int))
+ par_ku_map.GetCount() * (6 * sizeof(int))
+ cobce_obec_map.GetCount() * (6 * sizeof(int))
+ tel_ku_map.GetCount() * (6 * sizeof(int))
+ bud_id_zdb.GetCount() * (5 * sizeof(int) + sizeof(Pointf))
+ bud_id_ob.GetCount() * 200
+ ku_index.GetCount() * (4 * sizeof(int))
+ bud_id_index.GetCount() * (4 * sizeof(int))
+ obec_kod_index.GetCount() * (4 * sizeof(int));
*/
;
}
VfkStream::Data::Data(VfkStream *vfk_, Table *table_)
: vfk(vfk_), table(table_)
{
header = table->header;
row_buffer.SetCount(table->columns.GetCount());
row_index = -1;
}
int64 VfkStream::Data::GetCount() const
{
if(!table->IsScanned())
vfk->ScanTable(*table);
return table->header ? vfk->header.GetCount() : table->row_count;
}
const Vector<Value>& VfkStream::Data::operator [] (int64 row) const
{
if(!table->IsScanned())
vfk->ScanTable(*table);
if(header)
return vfk->header[(int)row];
ASSERT(row >= 0 && row < table->row_count);
if(row != row_index) {
row_index = row;
vfk->ReadRow(*table, row_index = row, row_buffer);
}
return row_buffer;
}
GisObject VfkStream::Data::GetPath(int64 row, double resolution) const
{
return Null;
/*
int bs = table->segment_index[row + 0], es = table->segment_index[row + 1];
if(es <= bs)
return Null;
RefPtr<GisObjectPath> path = new GisObjectPath;
path->extent = table->extents[row];
if(path->extent.Width() <= resolution && path->extent.Height() <= resolution) {
path->index.SetCount(1, 1);
path->points.SetCount(1, path->extent.CenterPoint());
}
else {
path->index.Reserve(es - bs);
int bx = table->point_index[bs], ex = table->point_index[es];
for(int t = bs; t < es; t++)
path->index.Add(table->point_index[t + 1] - bx);
path->points.Reserve(ex - bx);
for(int t = bx; t < ex; t++)
path->points.Add(*table->points[t]);
}
return GisObject(~path);
*/
}
GisObject VfkStream::Data::GetArea(int64 row, double resolution) const
{
return Null;
/*
int bs = table->segment_index[row + 0], es = table->segment_index[row + 1];
if(es <= bs)
return Null;
RefPtr<GisObjectArea> area = new GisObjectArea;
area->extent = table->extents[row];
if(area->extent.Width() <= resolution && area->extent.Height() <= resolution) {
area->index.SetCount(1, 1);
area->points.SetCount(1, area->extent.CenterPoint());
}
else {
area->index.Reserve(es - bs);
int bx = table->point_index[bs], ex = table->point_index[es];
for(int t = bs; t < es; t++)
area->index.Add(table->point_index[t + 1] - bx);
area->points.Reserve(ex - bx);
for(int t = bx; t < ex; t++)
area->points.Add(*table->points[t]);
}
return GisObject(~area);
*/
}
VfkStream::VfkStream()
{
charset = CHARSET_DEFAULT;
}
void VfkStream::Open(const VectorMap<int, String>& fns)
{
Close();
charset = CHARSET_ISO8859_2;
file_groups <<= fns;
streams.SetCount(file_groups.GetCount());
for(int i = 0; i < streams.GetCount(); i++)
if(!streams[i].Open(file_groups[i]))
throw Exc(NFormat("cannot open file '%s'", file_groups[i]));
indexfilename = GetTempFileName("vfk");
if(!indexfile.Open(indexfilename, FileStream::CREATE))
throw Exc(NFormat("cannot create indexfile '%s'", indexfilename));
String hdrname = "X_HEADER";
Table& hdr = tables.Add(hdrname);
hdr.name = hdr.rawname = hdrname;
hdr.header = true;
hdr.row_count = 0;
ASSERT(hdr.columns.GetCount() == HDR_ID);
hdr.AddColumn(Column("ID", STRING_V, 30));
ASSERT(hdr.columns.GetCount() == HDR_ORD);
hdr.AddColumn(Column("ORD", INT_V));
ASSERT(hdr.columns.GetCount() == HDR_STR);
hdr.AddColumn(Column("STR", STRING_V, 1000));
ASSERT(hdr.columns.GetCount() == HDR_NUM);
hdr.AddColumn(Column("NUM", DOUBLE_V));
ASSERT(hdr.columns.GetCount() == HDR_DTM);
hdr.AddColumn(Column("DTM", TIME_V));
ASSERT(hdr.columns.GetCount() == HDR_COUNT);
Scan();
}
void VfkStream::Close()
{
streams.Clear();
if(indexfile.IsOpen()) {
indexfile.Close();
FileDelete(indexfilename);
}
tables.Clear();
header.Clear();
}
int VfkStream::SizeOfInstance() const
{
int si = sizeof(*this);
for(int i = 0; i < tables.GetCount(); i++)
si += SizeOf(tables[i]);
return si;
}
/*
int VfkStream::MappingSizeOfInstance() const
{
return mapping.IsOpen() ? mapping.GetLength() : 0;
}
*/
Vector<String> VfkStream::GetTables() const
{
Vector<String> out;
out <<= tables.GetKeys();
return out;
}
VfkStream::Data VfkStream::GetData(String table)
{
int f = tables.Find(table);
ASSERT(f >= 0);
/*
if(table == "HRANICE_PARCEL")
ScanSBP(table, "HP_ID");
else if(table == "OBRAZY_BUDOV")
ScanSBP(table, "OB_ID");
else if(table == "DALSI_PRVKY_MAPY")
ScanSBP(table, "DPM_ID");
*/
return GetDataRaw(f);
}
void VfkStream::Dump()
{
puts(NFormat("Index file: %s", indexfilename));
puts(NFormat("%d file group(s):", file_groups.GetCount()));
for(int i = 0; i < file_groups.GetCount(); i++)
puts(NFormat("\t[%d] = %d / %s (%n B)", i, file_groups.GetKey(i), file_groups[i],
streams[i].IsOpen() ? streams[i].GetSize() : 0));
puts("Tables:");
for(int t = 0; t < tables.GetCount(); t++) {
const Table& tbl = tables[t];
puts(NFormat("\tTable(%d, %s (%s)) sections:\n", t, tbl.name, tbl.rawname));
for(int s = 0; s < tbl.file_index.GetCount(); s++)
puts(NFormat("\t\t[%d]: file index [%d], range %n .. %n, %n bytes, %n rows",
s, tbl.file_index[s], tbl.begin_offset[s], tbl.end_offset[s],
tbl.end_offset[s] - tbl.begin_offset[s], tbl.row_count));
/*
for(int c = 0; c < tbl.columns.GetCount(); c++) {
const Column& col = tbl.columns[c];
puts(NFormat("\t\t(%d, %s): %s %~d", c, col.name, GetVTypeName(col.vtype), col.width));
}
*/
Data data = GetData(tbl.name);
puts(NFormat("%d row(s):", data.GetCount()));
for(int i = 0; i < 10 && i < data.GetCount(); i++) {
const Vector<Value>& row = data[i];
String out;
for(int v = 0; v < row.GetCount(); v++)
out << (v ? ";" : "") << StdFormat(row[v]);
puts(out);
}
}
}
void VfkStream::SpeedTest()
{
for(int i = 0; i < tables.GetCount(); i++) {
int begin = msecs();
Data data = GetData(tables[i].name);
int get = msecs();
if(data.GetCount() > 0)
data[0];
int first = msecs();
for(int r = 1; r < data.GetCount(); r++)
data[r];
int nth = msecs();
puts(NFormat("%s: get(%d), first(%d), nth(%2v)",
tables[i].name, get - begin, first - get, (nth - first) / max<double>((double)data.GetCount() - 1, 1)));
}
}
bool VfkStream::IsDateTime(String field) const
{
return field == "PLATNOST" || field == "VYTVORENO";
}
WString VfkStream::ReadString(const char *b, const char **endptr) const
{
if(*b++ != '\"')
throw Exc("'\"' expected");
StringBuffer out;
for(;;) {
const char *b0 = b;
while(*b && *b != '\"')
b++;
out.Cat(b0, b - b0);
if(*b != '\"' || *++b != '\"')
break;
out.Cat(*b++);
}
if(endptr)
*endptr = b;
return ToUnicode((String)out, charset);
}
void VfkStream::ScanHeader(const char *b, Table& table)
{
int colid = 0;
while(*b && *b != '\n') {
if(IsAlpha(*b)) {
const char *id = b;
while(IsIdent(*++b))
;
Column col;
col.name = String(id, b);
try {
while(*b == ' ')
b++;
col.vtype = ERROR_V;
col.width = Null;
switch(*b++) {
case 'N': {
col.vtype = DOUBLE_V;
break;
}
case 'T': {
col.vtype = STRING_V;
if(!IsDigit(*b))
throw Exc("missing string width");
col.width = ScanInt(b, &b);
break;
}
case 'D': {
col.vtype = TIME_V;
break;
}
default: {
throw Exc(NFormat("invalid data type '%c'", *--b));
}
}
if(colid < table.columns.GetCount()) {
const Column& old = table.columns[colid];
if(old.name != col.name)
throw Exc(NFormat("column name mismatch (%s / %s)", old.name, col.name));
if(old.vtype != col.vtype)
throw Exc(NFormat("column type mismatch (%d / %d)", old.vtype, col.vtype));
if(old.width != col.width)
throw Exc(NFormat("column width mismatch (%~d / %~d)", old.width, col.width));
}
else
table.AddColumn(col);
colid++;
}
catch(Exc e) {
throw Exc(NFormat("column '%s': %s", colid, e));
}
}
else
b++;
}
}
void VfkStream::SkipRow(Stream& strm)
{
RTIMING("VfkStream::SkipRow");
enum { BATCH = 100 };
char buffer[BATCH + 1];
int count = strm.Get(buffer, BATCH);
buffer[count] = '\n';
const char *p = buffer;
for(;;)
if(*p == '\n') {
if(p - buffer < count) {
strm.SeekCur((p - buffer) - count + 1);
return;
}
buffer[count = strm.Get(buffer, BATCH)] = '\n';
p = buffer;
if(!count)
return;
}
else if(*p++ == '\"') {
for(;;) {
if(*p == '\n' && p - buffer >= count) {
buffer[count = strm.Get(buffer, BATCH)] = '\n';
p = buffer;
if(!count)
return;
}
else if(*p++ == '\"') {
if(*p == '\n' && p - buffer >= count) {
buffer[count = strm.Get(buffer, BATCH)] = '\n';
p = buffer;
if(!count)
return;
}
if(*p != '\"')
break;
p++;
}
}
}
}
/*
void VfkStream::ScanRow(Table& table) const
{
table.row_offsets.Add(b - (const char *)mapping.Begin() - 1);
return SkipRow(b);
}
*/
void VfkStream::ReadRow(const Table& table, int64 index, Vector<Value>& row)
{
RTIMING("VfkStream::ReadRow");
indexfile.Seek(table.row_offsets_xpos + 12 * index);
int64 off = indexfile.Get64le();
int len = indexfile.Get16le();
int ixf = indexfile.Get16le();
if(off < 0 || len < 0 || ixf < 0 || ixf > streams.GetCount())
return;
Buffer<char> rowbuf(len + 1);
Stream& strm = streams[ixf];
strm.Seek(off);
strm.Get(rowbuf, len);
rowbuf[len] = 0;
const char *b = rowbuf;
for(int i = 0; *b++ == ';' && i < row.GetCount(); i++) {
switch(table.columns[i].vtype) {
case DOUBLE_V: {
row[i] = ScanDouble(b, &b);
break;
}
case TIME_V: {
if(*b == '\"') {
row[i] = VfkReadTime(b + 1, &b);
if(*b == '\"')
b++;
}
break;
}
case STRING_V: {
row[i] = ReadString(b, &b);
break;
}
default: NEVER(); return;
}
}
}
void VfkStream::Scan()
{
RTIMING("VfkStream::Scan");
for(int i = 0; i < file_groups.GetCount(); i++)
ScanFile(i);
}
void VfkStream::ScanFile(int fx)
{
RTIMING("VfkStream::ScanFile");
Stream& strm = streams[fx];
int64 last_line = strm.GetSize();
while(last_line > 0) {
strm.Seek(last_line - 1);
if(strm.Get() == '\n')
break;
last_line--;
}
strm.Seek(0);
try {
int c;
int64 rowpos = strm.GetPos();
while((c = strm.Get()) == '&' && ((c = strm.Get()) == 'H' || c == 'D') && IsAlpha(strm.Term())) {
char type = c;
int64 begin = strm.GetPos();
SkipRow(strm);
rowpos = strm.GetPos();
int len = (int)(strm.GetPos() - begin);
StringBuffer linebuf(len + 1);
strm.Seek(begin);
strm.Get(linebuf, len);
linebuf[len] = 0;
const char *b = linebuf;
const char *id = b;
while(IsIdent(*++b))
;
String ident(id, b);
if(*b++ != ';')
throw Exc(NFormat("';' expected after '%s' (found: '%c', %2:02x)", ident, *b));
if(type == 'D') {
String fident = "X_" + ident;
int f = tables.Find(fident);
if(f < 0)
throw Exc(NFormat("unexpected data for filter table '%s'", ident));
// b = ScanRow(b, tables[f]);
}
else if(IsAlpha(*b)) {
String fident = "X_" + ident;
Table& tbl = tables.GetAdd(fident);
tbl.name = tbl.rawname = fident;
tbl.row_count = 0;
ScanHeader(b, tbl);
}
else {
do {
Vector<Value> row;
row.SetCount(HDR_COUNT);
if(*b == '\"') {
WString text = ReadString(b, &b);
if(IsDateTime(ident) && !IsNull(text)) {
Time dt = VfkReadTime(text.ToString(), NULL);
if(IsNull(dt))
throw Exc(NFormat("invalid date/time value %s", AsCString(text.ToString())));
row[HDR_DTM] = dt;
}
else {
row[HDR_STR] = text;
if(ident == "CODEPAGE")
if(text == WString("EE8MSWIN1250")) charset = CHARSET_WIN1250;
}
}
else {
double num = ScanDouble(b, &b);
if(IsNull(num))
throw Exc("invalid numeric value");
row[HDR_NUM] = num;
}
int l = header.FindLast(ident);
row[HDR_ID] = ident;
row[HDR_ORD] = (l >= 0 ? (int)header[l][HDR_ORD] + 1 : 0);
header.Add(ident) = row;
}
while(*b++ == ';');
b--;
}
}
strm.Seek(rowpos);
while(strm.Get() == '&' && strm.Get() == 'B' && IsAlpha(strm.Term())) {
int64 header_offset = strm.GetPos();
SkipRow(strm);
int64 begin_offset = strm.GetPos();
int len = (int)(begin_offset - header_offset);
Buffer<char> linebuf(len + 1);
strm.Seek(header_offset);
strm.Get(linebuf, len);
linebuf[len] = 0;
const char *b = linebuf;
const char *id = b;
while(IsIdent(*++b))
;
int idlen = b - id;
String ident(id, b);
if(*b++ != ';')
throw Exc(NFormat("';' expected after '%s' (found: '%c', %2:02x)", ident, *b));
String name = ident;
for(const VFKLongName *ln = vfk_long_names; ln->shortname; ln++)
if(name == ln->shortname) {
name = ln->longname;
break;
}
Table& tbl = tables.GetAdd(name);
tbl.name = name;
tbl.rawname = ident;
ScanHeader(b, tbl);
int64 p = begin_offset, e = last_line;
Buffer<char> idbuf(idlen + 3);
while(p < e) {
int64 m = (p + e) >> 1;
while(m > p) {
char part[100];
int partsize = (int)min<int64>(m - p, sizeof(part));
strm.Seek(m - partsize);
strm.Get(part, partsize);
const char *x = &part[partsize];
while(x > part && x[-1] != '\n')
x--;
int lfpos = x - part;
if(x > part && --x > part && x[-1] == '\r')
x--;
m -= partsize - lfpos;
if(x <= part)
continue;
if(*--x != '\xA4')
break;
m -= lfpos - (x - part);
}
strm.Seek(m);
if(strm.Get(idbuf, idlen + 3) != idlen + 3 || idbuf[0] != '&' || idbuf[1] != 'D'
|| memcmp(~idbuf + 2, id, idlen) || idbuf[idlen + 2] != ';')
e = m;
else {
SkipRow(strm);
p = strm.GetPos();
}
}
int xgrp = file_groups.GetKey(fx);
int f;
for(f = 0; f < tbl.file_index.GetCount(); f++)
if(file_groups.GetKey(tbl.file_index[f]) == xgrp)
break;
if(f >= tbl.file_index.GetCount()) {
tbl.file_index.Add(fx);
tbl.begin_offset.Add(begin_offset);
tbl.end_offset.Add(p);
}
strm.Seek(p);
}
}
catch(Exc e) {
throw Exc(NFormat("%s (offset %n): %s", file_groups[fx], strm.GetPos(), e));
}
}
void VfkStream::ScanTable(Table& tbl)
{
RTIMING("VfkStream::ScanTable");
if(tbl.row_count >= 0)
return;
tbl.row_count = 0;
tbl.row_offsets_xpos = indexfile.GetPos();
int idlen = tbl.rawname.GetLength();
enum { READBUF = 10000000 };
Buffer<char> readbuf(READBUF + 1);
for(int i = 0; i < tbl.file_index.GetCount(); i++) {
RTIMING("VfkStream::ScanTable / file");
int fx = tbl.file_index[i];
Stream& strm = streams[fx];
int64 pos = tbl.begin_offset[i], end = tbl.end_offset[i];
while(pos < end) {
RTIMING("VfkStream::ScanTable / buffer");
strm.Seek(pos);
int part = strm.Get(readbuf, (int)min<int64>(end - pos, READBUF));
readbuf[part] = '\n';
const char *b = readbuf, *e = b + part;
for(;;) {
RTIMING("VfkStream::ScanTable / row");
int64 boff = pos + (b - ~readbuf);
if(e - b < idlen + 3) {
pos = boff;
break;
}
if(b[0] != '&' || b[1] != 'D' || memcmp(b + 2, tbl.rawname, idlen) || b[2 + idlen] != ';') {
pos = end;
break;
}
b += 3 + idlen;
int64 eoff = -1;
while(b < e) {
if(*b == '\n') {
if(b < e)
eoff = pos + (++b - ~readbuf);
break;
}
else if(*b++ == '\"') {
for(;;)
if(*b == '\n' && b >= e)
break;
else if(*b++ == '\"') {
if(*b == '\n' && b >= e)
break;
if(*b != '\"')
break;
b++;
}
}
}
if(eoff < 0) {
pos = boff;
break;
}
RTIMING("VfkStream::ScanTable / index stream write");
indexfile.Put64le(boff);
indexfile.Put16le((int)(eoff - boff));
indexfile.Put16le(fx);
tbl.row_count++;
}
}
}
}
VfkStream::Data VfkStream::GetDataRaw(int t)
{
RTIMING("VfkStream::GetData");
return Data(this, &tables[t]);
}
/*
void VfkStream::ScanSOBR()
{
int f = tables.Find("SOURADNICE_OBRAZU");
if(f < 0 || !tables[f].sobr_map.IsEmpty())
return;
Table& sobr = tables[f];
int id = sobr.columns.Find("ID");
int px = sobr.columns.Find("SOURADNICE_Y");
int py = sobr.columns.Find("SOURADNICE_X");
if(id < 0 || px < 0 || py < 0)
return;
Data data = GetDataRaw(f);
for(int i = 0, dc = data.GetCount(); i < dc; i++) {
const Vector<Value>& row = data[i];
double x = row[px], y = row[py];
if(!IsNull(x) && !IsNull(y))
sobr.sobr_map.Add(row[id], Pointf(-x, -y));
}
}
*/
/*
void VfkStream::ScanSBP(String table, String sbp_id)
{
int tf = tables.Find(table), sf = tables.Find("SPOJENI_B_POLOH"), of = tables.Find("SOURADNICE_OBRAZU");
if(tf < 0 || sf < 0 || of < 0)
return;
Table& tbl = tables[tf];
int tid = tbl.columns.Find("ID");
if(tid < 0 || tbl.scanned_sbp)
return;
Data tdata = GetDataRaw(tf);
tbl.segment_index.SetCount(tdata.GetCount() + 1, 0);
tbl.point_index.Add(0);
tbl.extents.SetCount(tdata.GetCount(), Null);
tbl.scanned_sbp = true;
Table& sbp = tables[sf];
int rid = sbp.columns.Find(sbp_id);
int por = sbp.columns.Find("PORADOVE_CISLO_BODU");
int pid = sbp.columns.Find("BP_ID");
if(rid < 0 || por < 0 || pid < 0)
return;
ScanSOBR();
Table& sobr = tables[of];
Index<double> rid_index;
Vector< Vector<int> > por_lists;
Vector< Vector<double> > pid_lists;
Data sdata = GetDataRaw(sf);
for(int i = 0, sc = sdata.GetCount(); i < sc; i++) {
const Vector<Value>& row = sdata[i];
if(!IsNull(row[rid])) {
int n = rid_index.FindAdd(row[rid]);
por_lists.At(n).Add(row[por]);
pid_lists.At(n).Add(row[pid]);
}
}
for(int i = 0, tc = tdata.GetCount(); i < tc; i++) {
Rectf ext = Null;
int f = rid_index.Find(tdata[i][tid]);
if(f >= 0) {
Vector<int>& por = por_lists[f];
Vector<double>& pid = pid_lists[f];
IndexSort(por, pid);
for(int j = 0; j < pid.GetCount(); j++) {
int p = sobr.sobr_map.Find(pid[j]);
if(p >= 0)
ext |= *(tbl.points.Add() = &sobr.sobr_map[p]);
}
if(!pid.IsEmpty())
tbl.point_index.Add(tbl.points.GetCount());
}
tbl.extents[i] = ext;
tbl.segment_index[i + 1] = tbl.point_index.GetCount() - 1;
}
}
*/
/*
void VfkStream::ScanParKUMap()
{
int pf = tables.Find("PARCELY");
if(pf < 0)
return;
Table& par = tables[pf];
if(!par.par_ku_map.IsEmpty())
return;
Data pdata = GetDataRaw(pf);
int pid = par.columns.Find("BUD_ID");
if(pid < 0)
return;
int kid = par.columns.Find("KATUZE_KOD");
if(kid < 0)
return;
for(int i = 0, pc = pdata.GetCount(); i < pc; i++) {
const Vector<Value>& row = pdata[i];
par.par_ku_map.Add(row[pid], row[kid]);
}
}
*/
/*
void VfkStream::ScanTelKUMap()
{
int tf = tables.Find("TELESA");
if(tf < 0)
return;
Table& tel = tables[tf];
if(!tel.tel_ku_map.IsEmpty())
return;
Data tdata = GetDataRaw(tf);
int tid = tel.columns.Find("ID");
if(tid < 0)
return;
int kid = tel.columns.Find("KATUZE_KOD");
if(kid < 0)
return;
for(int i = 0, tc = tdata.GetCount(); i < tc; i++) {
const Vector<Value>& row = tdata[i];
tel.tel_ku_map.Add(row[tid], row[kid]);
}
}
*/
/*
void VfkStream::ScanKuIndex()
{
int kf = tables.Find("KATASTR_UZEMI");
if(kf < 0)
return;
Table& kat = tables[kf];
if(!kat.ku_index.IsEmpty())
return;
Data tdata = GetDataRaw(kf);
int kod = kat.columns.Find("KOD");
if(kod < 0)
return;
int tc = tdata.GetCount();
kat.ku_index.Reserve(tc);
for(int i = 0; i < tc; i++)
kat.ku_index.Add(tdata[i][kod]);
}
*/
/*
void VfkStream::ScanBudIndex()
{
int bf = tables.Find("BUDOVY");
if(bf < 0)
return;
Table& bud = tables[bf];
if(!bud.bud_id_index.IsEmpty())
return;
Data tdata = GetDataRaw(bf);
int bid = bud.columns.Find("ID");
if(bid < 0)
return;
int tc = tdata.GetCount();
bud.bud_id_index.Reserve(tc);
for(int i = 0; i < tc; i++)
bud.bud_id_index.Add(tdata[i][bid]);
}
*/
/*
void VfkStream::ScanObrBud()
{
int of = tables.Find("OBRAZY_BUDOV");
if(of < 0)
return;
Table& obr = tables[of];
if(!obr.bud_id_ob.IsEmpty() || !obr.bud_id_zdb.IsEmpty())
return;
Data tdata = GetDataRaw(of);
int bid = obr.columns.Find("BUD_ID");
int sx = obr.columns.Find("SOURADNICE_X");
int sy = obr.columns.Find("SOURADNICE_Y");
int obt = obr.columns.Find("OBRBUD_TYPE");
if(bid < 0 || sx < 0 || sy < 0 || obt < 0)
return;
int tc = tdata.GetCount();
for(int i = 0; i < tc; i++) {
const Vector<Value>& row = tdata[i];
int budid = row[bid];
Pointf pt(row[sy], row[sx]);
String tp = row[obt];
if(!IsNull(pt.x) && !IsNull(pt.y))
if(tp == "ZDB")
obr.bud_id_zdb.Add(budid, -pt);
else if(tp == "OB")
obr.bud_id_ob.GetAdd(budid).Add(-pt);
}
}
*/
/*
void VfkStream::ScanObceIndex()
{
int of = tables.Find("OBCE");
if(of < 0)
return;
Table& obce = tables[of];
if(!obce.obec_kod_index.IsEmpty())
return;
Data tdata = GetDataRaw(of);
int kid = obce.columns.Find("KOD");
if(kid < 0)
return;
int tc = tdata.GetCount();
obce.obec_kod_index.Reserve(tc);
for(int i = 0; i < tc; i++)
obce.obec_kod_index.Add(tdata[i][kid]);
}
*/
/*
void VfkStream::ScanCastiObciMap()
{
int cf = tables.Find("CASTI_OBCI");
if(cf < 0)
return;
Table& cobce = tables[cf];
if(!cobce.cobce_obec_map.IsEmpty())
return;
Data cdata = GetDataRaw(cf);
int ck = cobce.columns.Find("KOD");
if(ck < 0)
return;
int ok = cobce.columns.Find("OBCE_KOD");
if(ok < 0)
return;
for(int i = 0, cc = cdata.GetCount(); i < cc; i++) {
const Vector<Value>& row = cdata[i];
cobce.cobce_obec_map.Add(row[ck], row[ok]);
}
}
*/
/*
void VfkStream::ScanPAR()
{
int pf = tables.Find("PARCELY");
if(pf < 0)
return;
Table& par = tables[pf];
if(par.scanned_sbp)
return;
par.scanned_sbp = true;
Data pdata = GetDataRaw(pf);
par.segment_index.SetCount(pdata.GetCount() + 1, 0);
par.point_index.Add(0);
par.extents.SetCount(pdata.GetCount(), Null);
int pid = par.columns.Find("ID");
if(pid < 0)
return;
int hf = tables.Find("HRANICE_PARCEL");
if(hf < 0)
return;
Table& hp = tables[hf];
int hp1 = hp.columns.Find("PAR_ID_1");
int hp2 = hp.columns.Find("PAR_ID_2");
if(hp1 < 0 || hp2 < 0)
return;
ScanSBP("HRANICE_PARCEL", "HP_ID");
Index<double> hp1ix, hp2ix;
Data hdata = GetDataRaw(hf);
hp1ix.Reserve(hdata.GetCount());
hp2ix.Reserve(hdata.GetCount());
for(int i = 0, dc = hdata.GetCount(); i < dc; i++) {
const Vector<Value>& row = hdata[i];
hp1ix.Add(row[hp1]);
hp2ix.Add(row[hp2]);
}
for(int i = 0, pc = pdata.GetCount(); i < pc; i++) {
Rectf ext = Null;
double id = pdata[i][pid];
Index<const Pointf *, PtrHash> sb, se;
Vector<int> sh;
for(int i1 = hp1ix.Find(id); i1 >= 0; i1 = hp1ix.FindNext(i1)) {
int bi = hp.point_index[hp.segment_index[i1]], li = hp.point_index[hp.segment_index[i1 + 1]] - 1;
if(bi < li) {
sh.Add(i1);
sb.Add(hp.points[bi]);
se.Add(hp.points[li]);
}
}
for(int i2 = hp2ix.Find(id); i2 >= 0; i2 = hp2ix.FindNext(i2)) {
int bi = hp.point_index[hp.segment_index[i2]], li = hp.point_index[hp.segment_index[i2 + 1]] - 1;
if(bi < li) {
sh.Add(i2);
sb.Add(hp.points[bi]);
se.Add(hp.points[li]);
}
}
for(;;) {
int f;
for(f = 0; f < sh.GetCount() && sb.IsUnlinked(f); f++)
;
if(f >= sh.GetCount())
break;
int begin = par.points.GetCount();
for(int bi = hp.point_index[hp.segment_index[sh[f]]],
ei = hp.point_index[hp.segment_index[sh[f] + 1]]; bi < ei; bi++)
ext |= *(par.points.Add() = hp.points[bi]);
sb.Unlink(f);
se.Unlink(f);
const Pointf *close = sb[f];
const Pointf *next = se[f];
while(next != close) {
bool direct = true;
if((f = sb.Find(next)) >= 0)
direct = true;
else if((f = se.Find(next)) >= 0)
direct = false;
else {
double d, b = 1e100;
for(int x = 0; x < sh.GetCount(); x++)
if(!sb.IsUnlinked(x)) {
if((d = Distance(*sb[x], *next)) < b) {
f = x;
direct = true;
b = d;
}
if((d = Distance(*se[x], *next)) < b) {
f = x;
direct = false;
b = d;
}
}
if(f < 0)
break;
}
int bi = hp.point_index[hp.segment_index[sh[f]]];
int ei = hp.point_index[hp.segment_index[sh[f] + 1]];
if(direct) {
if(hp.points[bi] != next)
ext |= *(par.points.Add() = hp.points[bi]);
while(++bi < ei)
ext |= *(par.points.Add() = hp.points[bi]);
next = hp.points[bi - 1];
}
else {
if(hp.points[--ei] != next)
ext |= *(par.points.Add() = hp.points[ei]);
while(--ei >= bi)
ext |= *(par.points.Add() = hp.points[ei]);
next = hp.points[ei + 1];
}
sb.Unlink(f);
se.Unlink(f);
}
if(par.points.GetCount() > begin + 1 && par.points.Top() == par.points[begin])
par.points.Drop();
par.point_index.Add(par.points.GetCount());
}
par.segment_index[i + 1] = par.point_index.GetCount() - 1;
par.extents[i] = ext;
}
}
*/