From 01514423543eaf0f52ad08745acde154e71da562 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 1 Feb 2023 22:23:15 +0100 Subject: [PATCH 1/2] Add basic shapefile (.shp, .shx) support The shapefile support includes recognition of the magic 0x0000270a and parsing the file length. The source code is based on the template file and file_bmp.c. The shapefile format is described at [1], the article links to other resources, like the Technical Description[2]. [1]: https://en.wikipedia.org/wiki/Shapefile [2]: https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf --- src/Makefile.am | 1 + src/file_list.c | 6 ++++ src/file_shp.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 src/file_shp.c diff --git a/src/Makefile.am b/src/Makefile.am index 8e2cd442..d7494e2b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -324,6 +324,7 @@ file_C = filegen.c \ file_ses.c \ file_sgcta.c \ file_shn.c \ + file_shp.c \ file_sib.c \ file_sig.c \ file_sit.c \ diff --git a/src/file_list.c b/src/file_list.c index 3173741e..f76403c5 100644 --- a/src/file_list.c +++ b/src/file_list.c @@ -854,6 +854,9 @@ extern const file_hint_t file_hint_sgcta; #if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_shn) extern const file_hint_t file_hint_shn; #endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_shp) +extern const file_hint_t file_hint_shp; +#endif #if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sib) extern const file_hint_t file_hint_sib; #endif @@ -1899,6 +1902,9 @@ file_enable_t array_file_enable[]= #if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_shn) { .enable=0, .file_hint=&file_hint_shn }, #endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_shp) + { .enable=0, .file_hint=&file_hint_shp }, +#endif #if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sib) { .enable=0, .file_hint=&file_hint_sib }, #endif diff --git a/src/file_shp.c b/src/file_shp.c new file mode 100644 index 00000000..47195a05 --- /dev/null +++ b/src/file_shp.c @@ -0,0 +1,84 @@ +/* + + File: file_shp.c + + Copyright (C) 2023 Grzegorz Szymaszek + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_shp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +static void register_header_check_shp(file_stat_t *file_stat); + +const file_hint_t file_hint_shp= { + .extension="shp", + .description="Shapefile", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_shp +}; + +static const uint8_t shp_header[4] = {0x00, 0x00, 0x27, 0x0a}; + +/* https://en.wikipedia.org/wiki/Shapefile */ +struct shp_header +{ + int32_t magic; + int32_t reserved[5]; + int32_t size; + int32_t version; + int32_t shape_type; +} __attribute__ ((gcc_struct, __packed__)); + +static int header_check_shp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct shp_header *shp=(const struct shp_header *)buffer; + (void) buffer_size; + (void) safe_header_only; + (void) file_recovery; + + if(buffer[0]!=0 || buffer[1]!=0 || buffer[2]!=0x27 || buffer[3]!=0x0a) + return 0; + if(be32(shp->size) >= 100) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_shp.extension; + file_recovery_new->min_filesize=100; + file_recovery_new->calculated_file_size=(uint64_t)be32(shp->size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + return 0; +} + +static void register_header_check_shp(file_stat_t *file_stat) +{ + register_header_check(0, shp_header, sizeof(shp_header), &header_check_shp, file_stat); +} +#endif From ca8e5cab23d1e1c91135f68eb441d2fc8e7c2e5d Mon Sep 17 00:00:00 2001 From: Christophe Grenier Date: Fri, 3 Feb 2023 15:34:55 +0100 Subject: [PATCH 2/2] src/file_shp.c: fix filesize detection. Add some frama-c annotations --- src/file_shp.c | 69 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/src/file_shp.c b/src/file_shp.c index 47195a05..f708e889 100644 --- a/src/file_shp.c +++ b/src/file_shp.c @@ -32,11 +32,14 @@ #include "filegen.h" #include "common.h" +/*@ + @ requires valid_register_header_check(file_stat); + @*/ static void register_header_check_shp(file_stat_t *file_stat); const file_hint_t file_hint_shp= { .extension="shp", - .description="Shapefile", + .description="ESRI Shapefile", .max_filesize=PHOTOREC_MAX_FILE_SIZE, .recover=1, .enable_by_default=1, @@ -55,26 +58,60 @@ struct shp_header int32_t shape_type; } __attribute__ ((gcc_struct, __packed__)); +/*@ + @ requires buffer_size >= sizeof(struct shp_header); + @ requires separation: \separated(&file_hint_shp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null); + @ ensures (\result == 1) ==> (file_recovery_new->handle == \null); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_shp.extension); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 100); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 100); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @ assigns file_recovery_new->filename[0]; + @ assigns file_recovery_new->time; + @ assigns file_recovery_new->file_stat; + @ assigns file_recovery_new->handle; + @ assigns file_recovery_new->file_size; + @ assigns file_recovery_new->location.list.prev; + @ assigns file_recovery_new->location.list.next; + @ assigns file_recovery_new->location.end; + @ assigns file_recovery_new->location.data; + @ assigns file_recovery_new->extension; + @ assigns file_recovery_new->min_filesize; + @ assigns file_recovery_new->calculated_file_size; + @ assigns file_recovery_new->data_check; + @ assigns file_recovery_new->file_check; + @ assigns file_recovery_new->file_rename; + @ assigns file_recovery_new->offset_error; + @ assigns file_recovery_new->offset_ok; + @ assigns file_recovery_new->checkpoint_status; + @ assigns file_recovery_new->checkpoint_offset; + @ assigns file_recovery_new->flags; + @ assigns file_recovery_new->extra; + @ assigns file_recovery_new->data_check_tmp; + @*/ static int header_check_shp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) { const struct shp_header *shp=(const struct shp_header *)buffer; - (void) buffer_size; - (void) safe_header_only; - (void) file_recovery; + const uint64_t size = 2 * be32(shp->size); - if(buffer[0]!=0 || buffer[1]!=0 || buffer[2]!=0x27 || buffer[3]!=0x0a) + if(le32(shp->version) != 1000) return 0; - if(be32(shp->size) >= 100) - { - reset_file_recovery(file_recovery_new); - file_recovery_new->extension=file_hint_shp.extension; - file_recovery_new->min_filesize=100; - file_recovery_new->calculated_file_size=(uint64_t)be32(shp->size); - file_recovery_new->data_check=&data_check_size; - file_recovery_new->file_check=&file_check_size; - return 1; - } - return 0; + if(size < 100) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_shp.extension; + file_recovery_new->min_filesize=100; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; } static void register_header_check_shp(file_stat_t *file_stat)