mirror of https://github.com/HandBrake/HandBrake
227 lines
4.6 KiB
C
227 lines
4.6 KiB
C
/* parsecsv.c
|
|
|
|
Copyright (c) 2003-2025 HandBrake Team
|
|
This file is part of the HandBrake source code
|
|
Homepage: <http://handbrake.fr/>.
|
|
It may be used under the terms of the GNU General Public License v2.
|
|
For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include "handbrake/handbrake.h"
|
|
#include "parsecsv.h"
|
|
|
|
/* Internal declarations */
|
|
#define is_newline(_x) ( (_x) == 13 || \
|
|
(_x) == 11 || \
|
|
(_x) == 10 )
|
|
|
|
#define is_white(_x) ( (_x) == '\t' || \
|
|
(_x) == ' ' || \
|
|
is_newline(_x) )
|
|
|
|
#define is_sep(_x) ( (_x) == ',' )
|
|
|
|
#define is_esc(_x) ( (_x) == '\\' )
|
|
|
|
#define CSV_CHAR_ERROR 0x8000
|
|
#define CSV_CHAR_EOF 0x4000
|
|
#define CSV_CHAR_ROWSEP 0x2000
|
|
#define CSV_CHAR_COLSEP 0x1000
|
|
|
|
#define CSV_PARSE_NORMAL 0x0000
|
|
#define CSV_PARSE_SEEK 0x0001
|
|
#define CSV_PARSE_ESC 0x0002
|
|
|
|
static uint16_t hb_parse_character( hb_csv_file_t * file );
|
|
static void hb_trim_end( char *text );
|
|
|
|
/* Open a CSV File */
|
|
hb_csv_file_t *hb_open_csv_file( const char *filepath )
|
|
{
|
|
hb_csv_file_t *file = NULL;
|
|
FILE * fileref;
|
|
|
|
if( filepath == NULL )
|
|
{
|
|
return file;
|
|
}
|
|
|
|
fileref = hb_fopen(filepath, "r");
|
|
if( fileref == NULL )
|
|
{
|
|
return file;
|
|
}
|
|
|
|
file = malloc( sizeof( hb_csv_file_t ) );
|
|
if( file == NULL )
|
|
{
|
|
return file;
|
|
}
|
|
|
|
file->fileref = fileref;
|
|
file->eof = 0;
|
|
file->parse_state = CSV_PARSE_SEEK;
|
|
file->curr_col = 0;
|
|
file->curr_row = 0;
|
|
return file;
|
|
}
|
|
|
|
void hb_close_csv_file( hb_csv_file_t *file )
|
|
{
|
|
if( file == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
fclose( file->fileref );
|
|
free( file );
|
|
}
|
|
|
|
/* Parse CSV Cells */
|
|
hb_csv_cell_t *hb_read_next_cell( hb_csv_file_t *file )
|
|
{
|
|
hb_csv_cell_t *cell = NULL;
|
|
uint16_t c;
|
|
int index;
|
|
|
|
if( file == NULL )
|
|
{
|
|
return cell;
|
|
}
|
|
|
|
if( file->eof )
|
|
{
|
|
return cell;
|
|
}
|
|
|
|
cell = malloc( sizeof( hb_csv_cell_t ) );
|
|
if( cell == NULL )
|
|
{
|
|
return cell;
|
|
}
|
|
|
|
cell->cell_row = file->curr_row;
|
|
cell->cell_col = file->curr_col;
|
|
index = 0;
|
|
while( CSV_CHAR_EOF != (c = hb_parse_character( file ) ) )
|
|
{
|
|
if( c == CSV_CHAR_ROWSEP )
|
|
{
|
|
file->curr_row++;
|
|
file->curr_col = 0;
|
|
break;
|
|
}
|
|
else if( c == CSV_CHAR_COLSEP )
|
|
{
|
|
file->curr_col++;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if( index < 1023 )
|
|
{
|
|
cell->cell_text[index] = (char)c;
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( c == CSV_CHAR_EOF )
|
|
{
|
|
file->eof = 1;
|
|
}
|
|
|
|
/* Terminate the cell text */
|
|
cell->cell_text[index] = '\0';
|
|
hb_trim_end( cell->cell_text );
|
|
return cell;
|
|
}
|
|
|
|
void hb_dispose_cell( hb_csv_cell_t *cell )
|
|
{
|
|
if( cell == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
free( cell );
|
|
}
|
|
|
|
/* Raw parsing */
|
|
static uint16_t hb_parse_character( hb_csv_file_t * file )
|
|
{
|
|
int byte;
|
|
uint16_t c = 0;
|
|
int need_char = 1;
|
|
|
|
if( file == NULL )
|
|
{
|
|
return CSV_CHAR_ERROR;
|
|
}
|
|
|
|
while( need_char )
|
|
{
|
|
byte = fgetc( file->fileref );
|
|
if( feof( file->fileref ) )
|
|
{
|
|
return CSV_CHAR_EOF;
|
|
}
|
|
if( ferror( file->fileref ) )
|
|
{
|
|
return CSV_CHAR_ERROR;
|
|
}
|
|
|
|
if( file->parse_state == CSV_PARSE_SEEK && is_white(byte) )
|
|
{
|
|
continue;
|
|
}
|
|
else if( file->parse_state != CSV_PARSE_ESC && is_esc(byte) )
|
|
{
|
|
file->parse_state = CSV_PARSE_ESC;
|
|
continue;
|
|
}
|
|
else if( file->parse_state != CSV_PARSE_ESC && is_sep(byte) )
|
|
{
|
|
file->parse_state = CSV_PARSE_SEEK;
|
|
need_char = 0;
|
|
c = CSV_CHAR_COLSEP;
|
|
}
|
|
else if( file->parse_state == CSV_PARSE_ESC )
|
|
{
|
|
file->parse_state = CSV_PARSE_NORMAL;
|
|
need_char = 0;
|
|
c = (uint16_t)byte;
|
|
}
|
|
else if( is_newline(byte) )
|
|
{
|
|
file->parse_state = CSV_PARSE_SEEK;
|
|
need_char = 0;
|
|
c = CSV_CHAR_ROWSEP;
|
|
}
|
|
else
|
|
{
|
|
file->parse_state = CSV_PARSE_NORMAL;
|
|
need_char = 0;
|
|
c = (uint16_t)byte;
|
|
}
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
static void hb_trim_end( char *text )
|
|
{
|
|
if( text == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
int i;
|
|
|
|
for( i = strlen(text) - 1; i >= 0 && is_white(text[i]) ; i-- )
|
|
{
|
|
text[i] = '\0';
|
|
}
|
|
}
|