calvinmetcalf / shapefile-js

Convert a Shapefile to GeoJSON. Not many caveats.
http://calvinmetcalf.github.io/shapefile-js/
715 stars 228 forks source link

please upgrade to JSZip 3 #142

Closed haayman-imagem closed 2 years ago

haayman-imagem commented 3 years ago

I get an error: The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.

In my application I've also installed the latest version of JSZip (3.5.0) but shpjs still uses version 2.4.0. These don't go well together apparently

calvinmetcalf commented 3 years ago

yes jszip3 switched to an async api for some reason despite being a syncronous process so I'd need to rewrite a bunch of stuff, so for the time being I think you're stuck with having to use both versions

lnedialkov commented 3 years ago

+1

Using the FileReader API together with JSZip ^2.4.0 is problematic seemingly due to a bug in JSZip where the following error gets thrown:

Error: End of data reached (data length = 0, asked index = 4). Corrupted zip ?
    at NodeBufferReader.checkIndex (dataReader.js:26)
    at NodeBufferReader.checkOffset (dataReader.js:17)
    at NodeBufferReader.push.Z2WY.NodeBufferReader.readData (nodeBufferReader.js:16)
    at NodeBufferReader.readString (dataReader.js:75)
    at ZipEntries.isSignature (zipEntries.js:46)
    at ZipEntries.readEndOfCentral (zipEntries.js:170)
    at ZipEntries.load (zipEntries.js:274)
    at new ZipEntries (zipEntries.js:22)
    at JSZip.push.mfCZ.module.exports [as load] (load.js:19)
    at new JSZip (index.js:39)

I've tried the following approach in typescript:

jsZip.loadAsync(file).then((zip: JSZip) => {
    const files = zip.file(/.+/);
    const promises = files.map(a => {
      if (a.name.endsWith('.shp') || a.name.endsWith('.dbf')) {
        return a.async('nodebuffer')
          .then(contents => {
            return { name: a.name, contents };
          });
      } else {
        return a.async('string').then(contents => {
          return { name: a.name, contents };
        });
      }
    });
    Promise.all(promises).then(shpFiles => {
        const files = shpFiles.reduce((res, shpFile) => {
          res[shpFile.name] = shpFile.contents;
          return res;
        }, {});
        return shpFiles
          .filter(shpFile => shpFile.name.endsWith('.shp'))
          .map(shpFile => {
            const name = shpFile.name.replace('.shp', '');

            let dbf;
            if (files[name + '.dbf']) {
              dbf = shp.parseDbf(
                files[name + '.dbf'],
                files[name + '.cpg']
              );
            }
            const shpf = shp.parseShp(
              files[name + '.shp'],
              files[name + '.prj']
            );
            const geoJson: FeatureCollection = shp.combine([ shpf, dbf ]);
            console.log(geoJson);
            return geoJson;
          });
      });
});

With the code above no error gets throws by the latest JSZip version, however something with the shp/dbf decoding seems to be very off. For a shapefile archive with 2 features inside I get 242 items in a FeatureCollection with null for geometry and gibberish inside the properties object.

Any ideas on how I can fix the decoding will be greatly appreciated! Thanks!