mapshaper 0.5.116 → 0.5.117

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ v0.5.117
2
+ * Support reading DBF files larger than 2GB (command line program only).
3
+
1
4
  v0.5.116
2
5
  * Prevent 0-length DBF string fields, for interoperability with PostGIS.
3
6
 
package/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.116";
3
+ var VERSION = "0.5.117";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -17628,7 +17628,9 @@ ${svg}
17628
17628
  binArr, buf;
17629
17629
 
17630
17630
  this.readToBinArray = function(start, length) {
17631
- if (bufSize < start + length) error("Out-of-range error");
17631
+ if (bufSize < start + length) {
17632
+ error("Out-of-range error");
17633
+ }
17632
17634
  if (!binArr) binArr = new BinArray(src);
17633
17635
  binArr.position(start);
17634
17636
  return binArr;
@@ -21137,6 +21139,9 @@ ${svg}
21137
21139
  // http://www.digitalpreservation.gov/formats/fdd/fdd000325.shtml
21138
21140
  // http://www.clicketyclick.dk/databases/xbase/format/index.html
21139
21141
  // http://www.clicketyclick.dk/databases/xbase/format/data_types.html
21142
+ // esri docs:
21143
+ // https://support.esri.com/en/technical-article/000007920
21144
+ // https://desktop.arcgis.com/en/arcmap/latest/manage-data/shapefiles/geoprocessing-considerations-for-shapefile-output.htm
21140
21145
 
21141
21146
  // source: http://webhelp.esri.com/arcpad/8.0/referenceguide/index.htm#locales/task_code.htm
21142
21147
  var languageIds = [0x01,'437',0x02,'850',0x03,'1252',0x08,'865',0x09,'437',0x0A,'850',0x0B,'437',0x0D,'437',0x0E,'850',0x0F,'437',0x10,'850',0x11,'437',0x12,'850',0x13,'932',0x14,'850',0x15,'437',0x16,'850',0x17,'865',0x18,'437',0x19,'437',0x1A,'850',0x1B,'437',0x1C,'863',0x1D,'850',0x1F,'852',0x22,'852',0x23,'852',0x24,'860',0x25,'850',0x26,'866',0x37,'850',0x40,'852',0x4D,'936',0x4E,'949',0x4F,'950',0x50,'874',0x57,'1252',0x58,'1252',0x59,'1252',0x64,'852',0x65,'866',0x66,'865',0x67,'861',0x6A,'737',0x6B,'857',0x6C,'863',0x78,'950',0x79,'949',0x7A,'936',0x7B,'932',0x7C,'874',0x86,'737',0x87,'852',0x88,'857',0xC8,'1250',0xC9,'1251',0xCA,'1254',0xCB,'1253',0xCC,'1257'];
@@ -21273,11 +21278,12 @@ ${svg}
21273
21278
  // @src is a Buffer or ArrayBuffer or filename
21274
21279
  //
21275
21280
  function DbfReader(src, encodingArg) {
21276
- if (utils.isString(src)) {
21277
- error("[DbfReader] Expected a buffer, not a string");
21278
- }
21279
- var bin = new BinArray(src);
21280
- var header = readHeader(bin);
21281
+ var opts = {
21282
+ cacheSize: 0x2000000, // 32MB
21283
+ bufferSize: 0x400000 // 4MB
21284
+ };
21285
+ var dbfFile = utils.isString(src) ? new FileReader(src, opts) : new BufferReader(src);
21286
+ var header = readHeader(dbfFile);
21281
21287
 
21282
21288
  // encoding and fields are set on first access
21283
21289
  var fields;
@@ -21293,7 +21299,11 @@ ${svg}
21293
21299
 
21294
21300
  this.getFields = getFieldNames;
21295
21301
 
21296
- this.getBuffer = function() {return bin.buffer();};
21302
+ // TODO: switch to streaming output under Node.js
21303
+ this.getBuffer = function() {
21304
+ return dbfFile.readSync(0, dbfFile.size());
21305
+ // return bin.buffer();
21306
+ };
21297
21307
 
21298
21308
  this.deleteField = function(f) {
21299
21309
  prepareToRead();
@@ -21334,7 +21344,10 @@ ${svg}
21334
21344
  });
21335
21345
  }
21336
21346
 
21337
- function readHeader(bin) {
21347
+ function readHeader(reader) {
21348
+ // fetch enough bytes to accomodate any header
21349
+ var maxHeaderLen = 32 * 256 + 1; // 255 fields * fieldRecSize + headerRecSize + terminator
21350
+ var bin = reader.readToBinArray(0, Math.min(maxHeaderLen, reader.size()));
21338
21351
  bin.position(0).littleEndian();
21339
21352
  var header = {
21340
21353
  version: bin.readInt8(),
@@ -21420,30 +21433,32 @@ ${svg}
21420
21433
  return new Function('return {' + args.join(',') + '};');
21421
21434
  }
21422
21435
 
21423
- function findEofPos(bin) {
21424
- var pos = bin.size() - 1;
21425
- if (bin.peek(pos) != 0x1A) { // last byte may or may not be EOF
21426
- pos++;
21427
- }
21428
- return pos;
21429
- }
21436
+ // function findEofPos(bin) {
21437
+ // var pos = bin.size() - 1;
21438
+ // if (bin.peek(pos) != 0x1A) { // last byte may or may not be EOF
21439
+ // pos++;
21440
+ // }
21441
+ // return pos;
21442
+ // }
21430
21443
 
21431
21444
  function getRecordReader() {
21432
21445
  prepareToRead();
21433
21446
  var readers = fields.map(getFieldReader),
21434
- eofOffs = findEofPos(bin),
21435
21447
  create = getRecordConstructor(),
21436
21448
  values = [];
21437
21449
 
21438
21450
  return function readRow(r) {
21439
- var offs = getRowOffset(r),
21451
+ var bin = dbfFile.readToBinArray(getRowOffset(r), header.recordSize),
21452
+ rowOffs = bin.position(),
21440
21453
  fieldOffs, field;
21454
+ if (bin.bytesLeft() < header.recordSize ||
21455
+ bin.bytesLeft() == header.recordSize && bin.peek(bin.size() - 1) == 0x1A) {
21456
+ // check for observed data error: last data byte contains EOF
21457
+ stop('Invalid DBF file: encountered end-of-file while reading data');
21458
+ }
21441
21459
  for (var c=0, cols=fields.length; c<cols; c++) {
21442
21460
  field = fields[c];
21443
- fieldOffs = offs + field.columnOffset;
21444
- if (fieldOffs + field.size > eofOffs) {
21445
- stop('Invalid DBF file: encountered end-of-file while reading data');
21446
- }
21461
+ fieldOffs = rowOffs + field.columnOffset;
21447
21462
  bin.position(fieldOffs);
21448
21463
  values[c] = readers[c](bin, field.size);
21449
21464
  }
@@ -21533,14 +21548,17 @@ ${svg}
21533
21548
  var maxSamples = 50;
21534
21549
  var buf = utils.createBuffer(256);
21535
21550
  var index = {};
21536
- var f, chars, sample, hash;
21551
+ var f, chars, sample, hash, bin, rowOffs;
21537
21552
  // include non-ascii field names, if any
21538
21553
  samples = getNonAsciiHeaders();
21539
21554
  for (var r=0; r<rows; r++) {
21555
+ bin = dbfFile.readToBinArray(getRowOffset(r), header.recordSize);
21556
+ rowOffs = bin.position();
21540
21557
  for (var c=0; c<cols; c++) {
21541
21558
  if (samples.length >= maxSamples) break;
21542
21559
  f = stringFields[c];
21543
- bin.position(getRowOffset(r) + f.columnOffset);
21560
+ // bin.position(getRowOffset(r) + f.columnOffset);
21561
+ bin.position(rowOffs + f.columnOffset);
21544
21562
  chars = readStringBytes(bin, f.size, buf);
21545
21563
  if (chars > 0 && bufferContainsHighBit(buf, chars)) {
21546
21564
  sample = utils.createBuffer(buf.slice(0, chars)); //
@@ -21556,9 +21574,9 @@ ${svg}
21556
21574
  }
21557
21575
  }
21558
21576
 
21559
- function importDbfTable(buf, o) {
21577
+ function importDbfTable(src, o) {
21560
21578
  var opts = o || {};
21561
- return new ShapefileTable(buf, opts.encoding);
21579
+ return new ShapefileTable(src, opts.encoding);
21562
21580
  }
21563
21581
 
21564
21582
  // Implements the DataTable api for DBF file data.
@@ -21567,8 +21585,8 @@ ${svg}
21567
21585
  // just the shapes and exporting in Shapefile format.
21568
21586
  // TODO: consider accepting just the filename, so buffer doesn't consume memory needlessly.
21569
21587
  //
21570
- function ShapefileTable(buf, encoding) {
21571
- var reader = new DbfReader(buf, encoding),
21588
+ function ShapefileTable(src, encoding) {
21589
+ var reader = new DbfReader(src, encoding),
21572
21590
  altered = false,
21573
21591
  table;
21574
21592
 
@@ -21577,15 +21595,23 @@ ${svg}
21577
21595
  // export DBF records on first table access
21578
21596
  table = new DataTable(reader.readRows());
21579
21597
  reader = null;
21580
- buf = null; // null out references to DBF data for g.c.
21598
+ src = null; // null out references to DBF data for g.c.
21581
21599
  }
21582
21600
  return table;
21583
21601
  }
21584
21602
 
21585
21603
  this.exportAsDbf = function(opts) {
21586
- // export original dbf bytes if possible, for performance
21604
+ // export original dbf bytes if possible
21605
+ // (e.g. if the data attributes haven't changed)
21587
21606
  var useOriginal = !!reader && !altered && !opts.field_order && !opts.encoding;
21588
- if (useOriginal) return reader.getBuffer();
21607
+ if (useOriginal) {
21608
+ try {
21609
+ // Maximum Buffer in current Node.js is 2GB
21610
+ // We fall back to import-export if getBuffer() fails.
21611
+ // This may produce a buffer that does not exceed the maximum size.
21612
+ return reader.getBuffer();
21613
+ } catch(e) {}
21614
+ }
21589
21615
  return Dbf.exportRecords(getTable().getRecords(), opts.encoding, opts.field_order);
21590
21616
  };
21591
21617
 
@@ -23595,7 +23621,7 @@ ${svg}
23595
23621
  if (input.cpg && !opts.encoding) {
23596
23622
  opts.encoding = input.cpg.content;
23597
23623
  }
23598
- table = importDbfTable(input.dbf.content, opts);
23624
+ table = importDbfTable(input.dbf.content || input.dbf.filename, opts);
23599
23625
  return {
23600
23626
  info: {},
23601
23627
  layers: [{data: table}]
@@ -23693,18 +23719,10 @@ ${svg}
23693
23719
  content;
23694
23720
 
23695
23721
  cli.checkFileExists(path, cache);
23696
- if (fileType == 'shp' && !cached) {
23697
- // let ShpReader read the file (supports larger files)
23722
+ if ((fileType == 'shp' || fileType == 'json' || fileType == 'text' || fileType == 'dbf') && !cached) {
23723
+ // these file types are read incrementally
23698
23724
  content = null;
23699
23725
 
23700
- } else if (fileType == 'json' && !cached) {
23701
- // postpone reading of JSON files, to support incremental parsing
23702
- content = null;
23703
-
23704
- } else if (fileType == 'text' && !cached) {
23705
- // content = cli.readFile(path); // read from buffer
23706
- content = null; // read from file, to support largest files (see mapshaper-delim-import.js)
23707
-
23708
23726
  } else if (fileType && isSupportedBinaryInputType(path)) {
23709
23727
  content = cli.readFile(path, null, cache);
23710
23728
  if (utils.isString(content)) {
@@ -23761,7 +23779,11 @@ ${svg}
23761
23779
  obj.shx = {filename: shxPath, content: cli.readFile(shxPath, null, cache)};
23762
23780
  }
23763
23781
  if (!obj.dbf && cli.isFile(dbfPath, cache)) {
23764
- obj.dbf = {filename: dbfPath, content: cli.readFile(dbfPath, null, cache)};
23782
+ // obj.dbf = {filename: dbfPath, content: cli.readFile(dbfPath, null, cache)};
23783
+ obj.dbf = {
23784
+ filename: dbfPath,
23785
+ content: (cache && (dbfPath in cache)) ? cli.readFile(dbfPath, null, cache) : null
23786
+ };
23765
23787
  }
23766
23788
  if (obj.dbf && cli.isFile(cpgPath, cache)) {
23767
23789
  obj.cpg = {filename: cpgPath, content: cli.readFile(cpgPath, 'utf-8', cache).trim()};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.5.116",
3
+ "version": "0.5.117",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.116";
3
+ var VERSION = "0.5.117";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -17628,7 +17628,9 @@ ${svg}
17628
17628
  binArr, buf;
17629
17629
 
17630
17630
  this.readToBinArray = function(start, length) {
17631
- if (bufSize < start + length) error("Out-of-range error");
17631
+ if (bufSize < start + length) {
17632
+ error("Out-of-range error");
17633
+ }
17632
17634
  if (!binArr) binArr = new BinArray(src);
17633
17635
  binArr.position(start);
17634
17636
  return binArr;
@@ -21137,6 +21139,9 @@ ${svg}
21137
21139
  // http://www.digitalpreservation.gov/formats/fdd/fdd000325.shtml
21138
21140
  // http://www.clicketyclick.dk/databases/xbase/format/index.html
21139
21141
  // http://www.clicketyclick.dk/databases/xbase/format/data_types.html
21142
+ // esri docs:
21143
+ // https://support.esri.com/en/technical-article/000007920
21144
+ // https://desktop.arcgis.com/en/arcmap/latest/manage-data/shapefiles/geoprocessing-considerations-for-shapefile-output.htm
21140
21145
 
21141
21146
  // source: http://webhelp.esri.com/arcpad/8.0/referenceguide/index.htm#locales/task_code.htm
21142
21147
  var languageIds = [0x01,'437',0x02,'850',0x03,'1252',0x08,'865',0x09,'437',0x0A,'850',0x0B,'437',0x0D,'437',0x0E,'850',0x0F,'437',0x10,'850',0x11,'437',0x12,'850',0x13,'932',0x14,'850',0x15,'437',0x16,'850',0x17,'865',0x18,'437',0x19,'437',0x1A,'850',0x1B,'437',0x1C,'863',0x1D,'850',0x1F,'852',0x22,'852',0x23,'852',0x24,'860',0x25,'850',0x26,'866',0x37,'850',0x40,'852',0x4D,'936',0x4E,'949',0x4F,'950',0x50,'874',0x57,'1252',0x58,'1252',0x59,'1252',0x64,'852',0x65,'866',0x66,'865',0x67,'861',0x6A,'737',0x6B,'857',0x6C,'863',0x78,'950',0x79,'949',0x7A,'936',0x7B,'932',0x7C,'874',0x86,'737',0x87,'852',0x88,'857',0xC8,'1250',0xC9,'1251',0xCA,'1254',0xCB,'1253',0xCC,'1257'];
@@ -21273,11 +21278,12 @@ ${svg}
21273
21278
  // @src is a Buffer or ArrayBuffer or filename
21274
21279
  //
21275
21280
  function DbfReader(src, encodingArg) {
21276
- if (utils.isString(src)) {
21277
- error("[DbfReader] Expected a buffer, not a string");
21278
- }
21279
- var bin = new BinArray(src);
21280
- var header = readHeader(bin);
21281
+ var opts = {
21282
+ cacheSize: 0x2000000, // 32MB
21283
+ bufferSize: 0x400000 // 4MB
21284
+ };
21285
+ var dbfFile = utils.isString(src) ? new FileReader(src, opts) : new BufferReader(src);
21286
+ var header = readHeader(dbfFile);
21281
21287
 
21282
21288
  // encoding and fields are set on first access
21283
21289
  var fields;
@@ -21293,7 +21299,11 @@ ${svg}
21293
21299
 
21294
21300
  this.getFields = getFieldNames;
21295
21301
 
21296
- this.getBuffer = function() {return bin.buffer();};
21302
+ // TODO: switch to streaming output under Node.js
21303
+ this.getBuffer = function() {
21304
+ return dbfFile.readSync(0, dbfFile.size());
21305
+ // return bin.buffer();
21306
+ };
21297
21307
 
21298
21308
  this.deleteField = function(f) {
21299
21309
  prepareToRead();
@@ -21334,7 +21344,10 @@ ${svg}
21334
21344
  });
21335
21345
  }
21336
21346
 
21337
- function readHeader(bin) {
21347
+ function readHeader(reader) {
21348
+ // fetch enough bytes to accomodate any header
21349
+ var maxHeaderLen = 32 * 256 + 1; // 255 fields * fieldRecSize + headerRecSize + terminator
21350
+ var bin = reader.readToBinArray(0, Math.min(maxHeaderLen, reader.size()));
21338
21351
  bin.position(0).littleEndian();
21339
21352
  var header = {
21340
21353
  version: bin.readInt8(),
@@ -21420,30 +21433,32 @@ ${svg}
21420
21433
  return new Function('return {' + args.join(',') + '};');
21421
21434
  }
21422
21435
 
21423
- function findEofPos(bin) {
21424
- var pos = bin.size() - 1;
21425
- if (bin.peek(pos) != 0x1A) { // last byte may or may not be EOF
21426
- pos++;
21427
- }
21428
- return pos;
21429
- }
21436
+ // function findEofPos(bin) {
21437
+ // var pos = bin.size() - 1;
21438
+ // if (bin.peek(pos) != 0x1A) { // last byte may or may not be EOF
21439
+ // pos++;
21440
+ // }
21441
+ // return pos;
21442
+ // }
21430
21443
 
21431
21444
  function getRecordReader() {
21432
21445
  prepareToRead();
21433
21446
  var readers = fields.map(getFieldReader),
21434
- eofOffs = findEofPos(bin),
21435
21447
  create = getRecordConstructor(),
21436
21448
  values = [];
21437
21449
 
21438
21450
  return function readRow(r) {
21439
- var offs = getRowOffset(r),
21451
+ var bin = dbfFile.readToBinArray(getRowOffset(r), header.recordSize),
21452
+ rowOffs = bin.position(),
21440
21453
  fieldOffs, field;
21454
+ if (bin.bytesLeft() < header.recordSize ||
21455
+ bin.bytesLeft() == header.recordSize && bin.peek(bin.size() - 1) == 0x1A) {
21456
+ // check for observed data error: last data byte contains EOF
21457
+ stop('Invalid DBF file: encountered end-of-file while reading data');
21458
+ }
21441
21459
  for (var c=0, cols=fields.length; c<cols; c++) {
21442
21460
  field = fields[c];
21443
- fieldOffs = offs + field.columnOffset;
21444
- if (fieldOffs + field.size > eofOffs) {
21445
- stop('Invalid DBF file: encountered end-of-file while reading data');
21446
- }
21461
+ fieldOffs = rowOffs + field.columnOffset;
21447
21462
  bin.position(fieldOffs);
21448
21463
  values[c] = readers[c](bin, field.size);
21449
21464
  }
@@ -21533,14 +21548,17 @@ ${svg}
21533
21548
  var maxSamples = 50;
21534
21549
  var buf = utils.createBuffer(256);
21535
21550
  var index = {};
21536
- var f, chars, sample, hash;
21551
+ var f, chars, sample, hash, bin, rowOffs;
21537
21552
  // include non-ascii field names, if any
21538
21553
  samples = getNonAsciiHeaders();
21539
21554
  for (var r=0; r<rows; r++) {
21555
+ bin = dbfFile.readToBinArray(getRowOffset(r), header.recordSize);
21556
+ rowOffs = bin.position();
21540
21557
  for (var c=0; c<cols; c++) {
21541
21558
  if (samples.length >= maxSamples) break;
21542
21559
  f = stringFields[c];
21543
- bin.position(getRowOffset(r) + f.columnOffset);
21560
+ // bin.position(getRowOffset(r) + f.columnOffset);
21561
+ bin.position(rowOffs + f.columnOffset);
21544
21562
  chars = readStringBytes(bin, f.size, buf);
21545
21563
  if (chars > 0 && bufferContainsHighBit(buf, chars)) {
21546
21564
  sample = utils.createBuffer(buf.slice(0, chars)); //
@@ -21556,9 +21574,9 @@ ${svg}
21556
21574
  }
21557
21575
  }
21558
21576
 
21559
- function importDbfTable(buf, o) {
21577
+ function importDbfTable(src, o) {
21560
21578
  var opts = o || {};
21561
- return new ShapefileTable(buf, opts.encoding);
21579
+ return new ShapefileTable(src, opts.encoding);
21562
21580
  }
21563
21581
 
21564
21582
  // Implements the DataTable api for DBF file data.
@@ -21567,8 +21585,8 @@ ${svg}
21567
21585
  // just the shapes and exporting in Shapefile format.
21568
21586
  // TODO: consider accepting just the filename, so buffer doesn't consume memory needlessly.
21569
21587
  //
21570
- function ShapefileTable(buf, encoding) {
21571
- var reader = new DbfReader(buf, encoding),
21588
+ function ShapefileTable(src, encoding) {
21589
+ var reader = new DbfReader(src, encoding),
21572
21590
  altered = false,
21573
21591
  table;
21574
21592
 
@@ -21577,15 +21595,23 @@ ${svg}
21577
21595
  // export DBF records on first table access
21578
21596
  table = new DataTable(reader.readRows());
21579
21597
  reader = null;
21580
- buf = null; // null out references to DBF data for g.c.
21598
+ src = null; // null out references to DBF data for g.c.
21581
21599
  }
21582
21600
  return table;
21583
21601
  }
21584
21602
 
21585
21603
  this.exportAsDbf = function(opts) {
21586
- // export original dbf bytes if possible, for performance
21604
+ // export original dbf bytes if possible
21605
+ // (e.g. if the data attributes haven't changed)
21587
21606
  var useOriginal = !!reader && !altered && !opts.field_order && !opts.encoding;
21588
- if (useOriginal) return reader.getBuffer();
21607
+ if (useOriginal) {
21608
+ try {
21609
+ // Maximum Buffer in current Node.js is 2GB
21610
+ // We fall back to import-export if getBuffer() fails.
21611
+ // This may produce a buffer that does not exceed the maximum size.
21612
+ return reader.getBuffer();
21613
+ } catch(e) {}
21614
+ }
21589
21615
  return Dbf.exportRecords(getTable().getRecords(), opts.encoding, opts.field_order);
21590
21616
  };
21591
21617
 
@@ -23595,7 +23621,7 @@ ${svg}
23595
23621
  if (input.cpg && !opts.encoding) {
23596
23622
  opts.encoding = input.cpg.content;
23597
23623
  }
23598
- table = importDbfTable(input.dbf.content, opts);
23624
+ table = importDbfTable(input.dbf.content || input.dbf.filename, opts);
23599
23625
  return {
23600
23626
  info: {},
23601
23627
  layers: [{data: table}]
@@ -23693,18 +23719,10 @@ ${svg}
23693
23719
  content;
23694
23720
 
23695
23721
  cli.checkFileExists(path, cache);
23696
- if (fileType == 'shp' && !cached) {
23697
- // let ShpReader read the file (supports larger files)
23722
+ if ((fileType == 'shp' || fileType == 'json' || fileType == 'text' || fileType == 'dbf') && !cached) {
23723
+ // these file types are read incrementally
23698
23724
  content = null;
23699
23725
 
23700
- } else if (fileType == 'json' && !cached) {
23701
- // postpone reading of JSON files, to support incremental parsing
23702
- content = null;
23703
-
23704
- } else if (fileType == 'text' && !cached) {
23705
- // content = cli.readFile(path); // read from buffer
23706
- content = null; // read from file, to support largest files (see mapshaper-delim-import.js)
23707
-
23708
23726
  } else if (fileType && isSupportedBinaryInputType(path)) {
23709
23727
  content = cli.readFile(path, null, cache);
23710
23728
  if (utils.isString(content)) {
@@ -23761,7 +23779,11 @@ ${svg}
23761
23779
  obj.shx = {filename: shxPath, content: cli.readFile(shxPath, null, cache)};
23762
23780
  }
23763
23781
  if (!obj.dbf && cli.isFile(dbfPath, cache)) {
23764
- obj.dbf = {filename: dbfPath, content: cli.readFile(dbfPath, null, cache)};
23782
+ // obj.dbf = {filename: dbfPath, content: cli.readFile(dbfPath, null, cache)};
23783
+ obj.dbf = {
23784
+ filename: dbfPath,
23785
+ content: (cache && (dbfPath in cache)) ? cli.readFile(dbfPath, null, cache) : null
23786
+ };
23765
23787
  }
23766
23788
  if (obj.dbf && cli.isFile(cpgPath, cache)) {
23767
23789
  obj.cpg = {filename: cpgPath, content: cli.readFile(cpgPath, 'utf-8', cache).trim()};