gmio/src/gmio_stl/internal/stla_infos_get.c

151 lines
5.4 KiB
C

/****************************************************************************
** gmio
** Copyright Fougue (2 Mar. 2015)
** contact@fougue.pro
**
** This software is a reusable library whose purpose is to provide complete
** I/O support for various CAD file formats (eg. STL)
**
** This software is governed by the CeCILL-B license under French law and
** abiding by the rules of distribution of free software. You can use,
** modify and/ or redistribute the software under the terms of the CeCILL-B
** license as circulated by CEA, CNRS and INRIA at the following URL
** "http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html".
****************************************************************************/
#include "stla_infos_get.h"
#include "../../gmio_core/error.h"
#include "../../gmio_core/internal/min_max.h"
#include "../../gmio_core/internal/string.h"
#include "../../gmio_core/internal/string_ascii_utils.h"
#include "stl_rw_common.h"
#include <string.h>
static uint32_t stla_facet_count(
const struct gmio_string* strbuff, const char* end_ptr)
{
const char* substr_at = NULL;
size_t strbuff_pos = 0;
uint32_t facet_count = 0;
do {
substr_at = gmio_ascii_istrstr(strbuff->ptr + strbuff_pos, "endfacet");
if (substr_at != NULL && substr_at < end_ptr) {
++facet_count;
/* Note: strlen("endfacet") == 8 */
strbuff_pos = (substr_at - strbuff->ptr) + 8;
}
else {
substr_at = NULL;
}
} while (substr_at != NULL);
return facet_count;
}
enum {
BUFF_OVERLAP_SIZE = 14,
BUFF_OVERLAP_SIZE_DIV2 = BUFF_OVERLAP_SIZE / 2
};
int gmio_stla_infos_get(
struct gmio_stl_infos_get_args* args, unsigned flags)
{
struct gmio_stream* stream = &args->stream;
struct gmio_stl_infos* infos = &args->infos;
void* mblock_ptr = args->stream_memblock.ptr;
/* Leave one byte to end the string buffer with 0 */
const size_t mblock_size = args->stream_memblock.size - 1;
struct gmio_string strbuff = gmio_string(mblock_ptr, 0, mblock_size);
const gmio_bool_t flag_facet_count =
(flags & GMIO_STL_INFO_FLAG_FACET_COUNT) != 0;
const gmio_bool_t flag_size =
(flags & GMIO_STL_INFO_FLAG_SIZE) != 0;
const gmio_bool_t flag_stla_solidname =
(flags & GMIO_STLA_INFO_FLAG_SOLIDNAME) != 0;
int err = GMIO_ERROR_OK;
if (!gmio_check_memblock(&err, &args->stream_memblock))
return err;
if (flags != 0) {
/* 'overlap' stores the ending/starting bytes of the previous/current
* stream buffers(memblock) */
char overlap[14] = {0}; /* 14 == 2*(strlen("endfacet") - 1) */
gmio_bool_t endsolid_found = GMIO_FALSE;
while (!endsolid_found && gmio_no_error(err)) {
const char* substr_at = NULL;
const size_t read_size =
gmio_stream_read(stream, mblock_ptr, 1, mblock_size);
const int stream_err = gmio_stream_error(&args->stream);
const gmio_bool_t overlap_has_contents = overlap[0] != 0;
gmio_bool_t endsolid_in_overlap = GMIO_FALSE;
err = stream_err;
strbuff.len = read_size;
strbuff.ptr[strbuff.len] = 0;
/* Copy first half of overlap buffer */
if (overlap_has_contents) {
strncpy(&overlap[BUFF_OVERLAP_SIZE_DIV2],
mblock_ptr,
GMIO_MIN(BUFF_OVERLAP_SIZE_DIV2, read_size));
}
/* Find "endsolid" in overlap */
if (overlap_has_contents) {
substr_at = strstr(overlap, "endsolid");
endsolid_found = substr_at != NULL;
endsolid_in_overlap = endsolid_found;
}
/* Find "endsolid" in memblock */
if (!endsolid_found) {
substr_at = gmio_ascii_istrstr(strbuff.ptr, "endsolid");
endsolid_found = substr_at != NULL;
}
/* Update stream size */
if (flag_size) {
/* Note: strlen("endsolid") == 8 */
if (endsolid_found) {
if (!endsolid_in_overlap)
infos->size += (substr_at - strbuff.ptr) + 8;
/* TODO : gérer le cas où "endsolid" se trouve dans overlap */
}
else {
infos->size += read_size;
}
}
/* Find "endfacet" tokens */
if (flag_facet_count && !endsolid_in_overlap) {
const char* endsolid_ptr =
endsolid_found ? substr_at : gmio_string_end(&strbuff);
/* Check in overlap */
const gmio_bool_t endfacet_in_overlap =
overlap_has_contents
&& strstr(overlap, "endfacet") != NULL;
infos->facet_count += endfacet_in_overlap ? 1 : 0;
/* Check in memblock */
infos->facet_count += stla_facet_count(&strbuff, endsolid_ptr);
}
/* Copy second half of overlap buffer */
if (!endsolid_found && read_size >= BUFF_OVERLAP_SIZE_DIV2) {
memset(&overlap, 0, sizeof(overlap));
strncpy(overlap,
&strbuff.ptr[read_size - BUFF_OVERLAP_SIZE_DIV2],
GMIO_MIN(BUFF_OVERLAP_SIZE_DIV2, read_size));
}
}
}
return err;
}