From 4ce2757d33f1acbdd3f32bec58c79032776b2f68 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 7 Nov 2015 15:57:30 +0100 Subject: Merging upstream version 1.5~rc1. Signed-off-by: Daniel Baumann --- ChangeLog | 6 ++++ INSTALL | 6 ++-- NEWS | 27 ++-------------- README | 7 ++--- carg_parser.c | 10 +++--- carg_parser.h | 2 +- configure | 18 +++++------ doc/pdlzip.1 | 2 +- lzip.h | 18 +++++------ main.c | 90 ++++++++++++++++++++++++++---------------------------- testsuite/check.sh | 51 +++++++++++++++++++------------ 11 files changed, 111 insertions(+), 126 deletions(-) diff --git a/ChangeLog b/ChangeLog index c2be48d..e8b6ef1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2013-07-26 Antonio Diaz Diaz + + * Version 1.5-rc1 released. + * main.c (show_header): Do not show header version in lzip mode. + * Minor fixes. + 2013-05-27 Antonio Diaz Diaz * Version 1.4 released. diff --git a/INSTALL b/INSTALL index 6f5affc..3d1ec67 100644 --- a/INSTALL +++ b/INSTALL @@ -1,7 +1,7 @@ Requirements ------------ You will need a C compiler. -I use gcc 4.8.0 and 3.3.6, but the code should compile with any +I use gcc 4.8.1 and 3.3.6, but the code should compile with any standards compliant compiler. Gcc is available at http://gcc.gnu.org. @@ -10,9 +10,9 @@ Procedure --------- 1. Unpack the archive if you have not done so already: - lzip -cd pdlzip[version].tar.lz | tar -xf - + tar -xf pdlzip[version].tar.lz or - gzip -cd pdlzip[version].tar.gz | tar -xf - + lzip -cd pdlzip[version].tar.lz | tar -xf - This creates the directory ./pdlzip[version] containing the source from the main archive. diff --git a/NEWS b/NEWS index 98ce57f..48dd9a9 100644 --- a/NEWS +++ b/NEWS @@ -1,26 +1,5 @@ -Changes in version 1.4: +Changes in version 1.5: -The options "-f, --force", "-F, --recompress", "-k, --keep", and -"-o, --output", have been ported from clzip. +Decompressing and testing no more show file version in lzip mode. -Pdlzip now accepts more than one file in the command line. - -Decompression time has been reduced by 5%. - -The dependence of "-t" on the existence of "/dev/null" has been removed. - -The value returned by "-d" and "-t" in case of data error has been fixed. - -Information shown at verbosity levels 2 and 3 has been changed. - -Option "-n, --threads" is now accepted and ignored for compatibility -with plzip. - -"configure" now accepts options with a separate argument. - -Configure option "--datadir" has been renamed to "--datarootdir" to -follow GNU Standards. - -The target "install-as-lzip" has been added to the Makefile. - -The target "install-bin" has been added to the Makefile. +Minor fixes. diff --git a/README b/README index 80aab86..fe86adf 100644 --- a/README +++ b/README @@ -1,10 +1,7 @@ Description -Pdlzip is a lossless data compressor based on the LZMA algorithm, with -very safe integrity checking and a user interface similar to the one of -gzip or bzip2. Pdlzip decompresses almost as fast as gzip and compresses -better than bzip2, which makes it well suited for software distribution -and data archiving. +Pdlzip is a lossless data compressor with a user interface similar to +the one of lzip, bzip2 or gzip. Pdlzip uses the lzip file format; the files produced by pdlzip are (hope)fully compatible with lzip-1.4 or newer. Pdlzip is in fact a diff --git a/carg_parser.c b/carg_parser.c index 7ea8a2f..2958c67 100644 --- a/carg_parser.c +++ b/carg_parser.c @@ -1,4 +1,4 @@ -/* Pdlzip - Data compressor based on the LZMA algorithm +/* Pdlzip - LZMA lossless data compressor Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. This program is free software: you have unlimited permission @@ -72,15 +72,14 @@ static char parse_long_option( struct Arg_parser * const ap, int * const argindp ) { unsigned len; - int index = -1; - int i; + int index = -1, i; char exact = 0, ambig = 0; for( len = 0; opt[len+2] && opt[len+2] != '='; ++len ) ; /* Test all long options for either exact match or abbreviated matches. */ for( i = 0; options[i].code != 0; ++i ) - if( options[i].name && !strncmp( options[i].name, &opt[2], len ) ) + if( options[i].name && strncmp( options[i].name, &opt[2], len ) == 0 ) { if( strlen( options[i].name ) == len ) /* Exact match found */ { index = i; exact = 1; break; } @@ -148,8 +147,7 @@ static char parse_short_option( struct Arg_parser * const ap, while( cind > 0 ) { - int index = -1; - int i; + int index = -1, i; const unsigned char code = opt[cind]; char code_str[2]; code_str[0] = code; code_str[1] = 0; diff --git a/carg_parser.h b/carg_parser.h index a750bd4..94d3716 100644 --- a/carg_parser.h +++ b/carg_parser.h @@ -1,4 +1,4 @@ -/* Pdlzip - Data compressor based on the LZMA algorithm +/* Pdlzip - LZMA lossless data compressor Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. This program is free software: you have unlimited permission diff --git a/configure b/configure index 13864f0..458caa2 100755 --- a/configure +++ b/configure @@ -1,14 +1,14 @@ #! /bin/sh -# configure script for Pdlzip - Data compressor based on the LZMA algorithm +# configure script for Pdlzip - LZMA lossless data compressor # Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. # # This configure script is free software: you have unlimited permission # to copy, distribute and modify it. pkgname=pdlzip -pkgversion=1.4 +pkgversion=1.5-rc1 progname=pdlzip -srctrigger=doc/pdlzip.1 +srctrigger=doc/${progname}.1 # clear some things potentially inherited from environment. LC_ALL=C @@ -100,14 +100,14 @@ while [ $# != 0 ] ; do *=* | *-*-*) ;; *) echo "configure: unrecognized option: '${option}'" 1>&2 - echo "Try 'configure --help' for more information." + echo "Try 'configure --help' for more information." 1>&2 exit 1 ;; esac # Check if the option took a separate argument if [ "${arg2}" = yes ] ; then if [ $# != 0 ] ; then args="${args} \"$1\"" ; shift - else echo "configure: Missing argument to \"${option}\"" 1>&2 + else echo "configure: Missing argument to '${option}'" 1>&2 exit 1 fi fi @@ -125,10 +125,8 @@ if [ -z "${srcdir}" ] ; then fi if [ ! -r "${srcdir}/${srctrigger}" ] ; then - exec 1>&2 - echo - echo "configure: Can't find sources in ${srcdir} ${srcdirtext}" - echo "configure: (At least ${srctrigger} is missing)." + echo "configure: Can't find sources in ${srcdir} ${srcdirtext}" 1>&2 + echo "configure: (At least ${srctrigger} is missing)." 1>&2 exit 1 fi @@ -166,7 +164,7 @@ echo "CFLAGS = ${CFLAGS}" echo "LDFLAGS = ${LDFLAGS}" rm -f Makefile cat > Makefile << EOF -# Makefile for Pdlzip - Data compressor based on the LZMA algorithm +# Makefile for Pdlzip - LZMA lossless data compressor # Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. # This file was generated automatically by configure. Do not edit. # diff --git a/doc/pdlzip.1 b/doc/pdlzip.1 index ec12d69..1029375 100644 --- a/doc/pdlzip.1 +++ b/doc/pdlzip.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. -.TH PDLZIP "1" "May 2013" "Pdlzip 1.4" "User Commands" +.TH PDLZIP "1" "July 2013" "Pdlzip 1.5-rc1" "User Commands" .SH NAME Pdlzip \- reduces the size of files .SH SYNOPSIS diff --git a/lzip.h b/lzip.h index 0ec2756..32236ed 100644 --- a/lzip.h +++ b/lzip.h @@ -1,4 +1,4 @@ -/* Pdlzip - Data compressor based on the LZMA algorithm +/* Pdlzip - LZMA lossless data compressor Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. This program is free software: you have unlimited permission @@ -49,12 +49,11 @@ struct Pretty_print const char * name; const char * stdin_name; int longest_name; - int verbosity; bool first_post; }; void Pp_init( struct Pretty_print * const pp, const char * const filenames[], - const int num_filenames, const int v ); + const int num_filenames ); static inline void Pp_set_name( struct Pretty_print * const pp, const char * const filename ) @@ -124,7 +123,7 @@ static inline uint8_t Fh_version( const File_header data ) { return data[4]; } static inline bool Fh_verify_version( const File_header data ) - { return ( data[4] <= 1 ); } + { return ( data[4] == 1 ); } static inline unsigned Fh_get_dictionary_size( const File_header data ) { @@ -134,15 +133,15 @@ static inline unsigned Fh_get_dictionary_size( const File_header data ) return sz; } -static inline bool Fh_set_dictionary_size( File_header data, const int sz ) +static inline bool Fh_set_dictionary_size( File_header data, const unsigned sz ) { if( sz >= min_dictionary_size && sz <= max_dictionary_size ) { data[5] = real_bits( sz - 1 ); if( sz > min_dictionary_size ) { - const int base_size = 1 << data[5]; - const int wedge = base_size / 16; + const unsigned base_size = 1 << data[5]; + const unsigned wedge = base_size / 16; int i; for( i = 7; i >= 1; --i ) if( base_size - ( i * wedge ) >= sz ) @@ -161,9 +160,6 @@ typedef uint8_t File_trailer[20]; enum { Ft_size = 20 }; -static inline int Ft_versioned_size( const int version ) - { return ( ( version >= 1 ) ? 20 : 12 ); } - static inline unsigned Ft_get_data_crc( const File_trailer data ) { unsigned tmp = 0; @@ -213,7 +209,7 @@ int writeblock( const int fd, const uint8_t * const buf, const int size ); /* defined in main.c */ extern int verbosity; - +void cleanup_and_fail( const int retval ); void show_error( const char * const msg, const int errcode, const bool help ); void internal_error( const char * const msg ); diff --git a/main.c b/main.c index 6142505..0428c84 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,4 @@ -/* Pdlzip - Data compressor based on the LZMA algorithm +/* Pdlzip - LZMA lossless data compressor 2009-08-14 : Igor Pavlov : Public domain Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. @@ -154,7 +154,7 @@ static const char * format_num( unsigned num ) } -void show_header( const File_header header ) +static void show_header( const File_header header ) { const char * const prefix[8] = { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; @@ -167,8 +167,6 @@ void show_header( const File_header header ) for( i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i ) { num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; np = ""; } - if( verbosity >= 4 ) - fprintf( stderr, "version %d, ", Fh_version( header ) ); fprintf( stderr, "dictionary size %s%4u %sB. ", np, num, p ); } @@ -281,12 +279,13 @@ static int open_instream( const char * const name, struct stat * const in_statsp const bool can_read = ( i == 0 && ( S_ISBLK( mode ) || S_ISCHR( mode ) || S_ISFIFO( mode ) || S_ISSOCK( mode ) ) ); - if( i != 0 || ( !S_ISREG( mode ) && ( !to_stdout || !can_read ) ) ) + const bool no_ofile = to_stdout || program_mode == m_test; + if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || !no_ofile ) ) ) { if( verbosity >= 0 ) fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n", program_name, name, - ( can_read && !to_stdout ) ? + ( can_read && !no_ofile ) ? " and '--stdout' was not specified" : "" ); close( infd ); infd = -1; @@ -297,22 +296,6 @@ static int open_instream( const char * const name, struct stat * const in_statsp } -void cleanup_and_fail( const int retval ) - { - if( delete_output_on_interrupt ) - { - delete_output_on_interrupt = false; - if( verbosity >= 0 ) - fprintf( stderr, "%s: Deleting output file '%s', if it exists.\n", - program_name, output_filename ); - if( outfd >= 0 ) { close( outfd ); outfd = -1; } - if( remove( output_filename ) != 0 && errno != ENOENT ) - show_error( "WARNING: deletion of output file (apparently) failed.", 0, false ); - } - exit( retval ); - } - - /* assure at least a minimum size for buffer 'buf' */ static void * resize_buffer( void * buf, const int min_size ) { @@ -396,6 +379,22 @@ static bool check_tty( const int infd, const enum Mode program_mode ) } +void cleanup_and_fail( const int retval ) + { + if( delete_output_on_interrupt ) + { + delete_output_on_interrupt = false; + if( verbosity >= 0 ) + fprintf( stderr, "%s: Deleting output file '%s', if it exists.\n", + program_name, output_filename ); + if( outfd >= 0 ) { close( outfd ); outfd = -1; } + if( remove( output_filename ) != 0 && errno != ENOENT ) + show_error( "WARNING: deletion of output file (apparently) failed.", 0, false ); + } + exit( retval ); + } + + /* Set permissions, owner and times. */ static void close_and_set_permissions( const struct stat * const in_statsp ) { @@ -426,11 +425,11 @@ static int compress( const struct Lzma_options * const encoder_options, const int infd, struct Pretty_print * const pp ) { int retval = 0; - File_header header; CLzmaEncHandle encoder; + File_header header; + Fh_set_magic( header ); if( verbosity >= 1 ) Pp_show_msg( pp, 0 ); - Fh_set_magic( header ); if( !Fh_set_dictionary_size( header, encoder_options->dictionary_size ) || encoder_options->match_len_limit < min_match_len_limit || encoder_options->match_len_limit > max_match_len ) @@ -480,11 +479,14 @@ static bool read_inbuf( const int infd, uint8_t inBuf[], } +/* 5 bytes of LZMA properties and 8 bytes of uncompressed size */ +enum { lzma_header_size = LZMA_PROPS_SIZE + 8 }; + static int lzma_decode( uint64_t unpackSize, CLzmaDec *decoder, const int infd, uint8_t inBuf[], int * const inPos, int * const inSize, const bool testing ) { - unsigned long long total_in = 13, total_out = 0; + unsigned long long total_in = lzma_header_size, total_out = 0; uint8_t outBuf[OUT_BUF_SIZE]; int outPos = 0; const bool thereIsSize = (unpackSize != (uint64_t)-1); @@ -540,8 +542,7 @@ static int lzma_decode( uint64_t unpackSize, CLzmaDec *decoder, const int infd, static int lzip_decode( CLzmaDec *decoder, const int infd, uint8_t inBuf[], - int * const inPos, int * const inSize, - const int member_version ) + int * const inPos, int * const inSize ) { unsigned long long total_in = Fh_size, total_out = 0; uint8_t outBuf[OUT_BUF_SIZE]; @@ -579,27 +580,25 @@ static int lzip_decode( CLzmaDec *decoder, const int infd, uint8_t inBuf[], { File_trailer trailer; int i; - const int trailer_size = Ft_versioned_size( member_version ); bool error = false; if( status != LZMA_STATUS_FINISHED_WITH_MARK ) { show_error( "Data error.", 0, false ); return 2; } - if( *inSize - *inPos < trailer_size && + if( *inSize - *inPos < Ft_size && !read_inbuf( infd, inBuf, inPos, inSize ) ) return 1; - if( *inSize - *inPos < trailer_size ) + if( *inSize - *inPos < Ft_size ) { error = true; if( verbosity >= 0 ) fprintf( stderr, "Trailer truncated at trailer position %u;" " some checks may fail.\n", (unsigned)(*inSize - *inPos) ); - for( i = *inSize - *inPos; i < trailer_size; ++i ) + for( i = *inSize - *inPos; i < Ft_size; ++i ) inBuf[*inPos+i] = 0; } - for( i = 0; i < trailer_size; ++i ) + for( i = 0; i < Ft_size; ++i ) trailer[i] = inBuf[(*inPos)++]; - total_in += trailer_size; - if( member_version == 0 ) Ft_set_member_size( trailer, total_in ); + total_in += Ft_size; if( Ft_get_data_crc( trailer ) != ( crc ^ 0xFFFFFFFFU ) ) { error = true; @@ -647,28 +646,29 @@ static int decompress( const int infd, struct Pretty_print * const pp, int retval = 0; bool lzip_mode = true; bool first_member; - /* 5 bytes of LZMA properties and 8 bytes of uncompressed size */ - uint8_t raw_props[LZMA_PROPS_SIZE+8]; + uint8_t raw_props[lzma_header_size]; for( first_member = true; ; first_member = false ) { int i; File_header header; - if( inSize - inPos < Fh_size && + if( inSize - inPos < lzma_header_size && !read_inbuf( infd, inBuf, &inPos, &inSize ) ) return 1; - if( inSize - inPos < Fh_size ) /* End Of File */ + if( inSize - inPos <= Fh_size ) /* End Of File */ { if( first_member ) - { Pp_show_msg( pp, "Error reading member header" ); retval = 1; } + { Pp_show_msg( pp, "File ends unexpectedly at member header" ); + retval = 2; } break; } for( i = 0; i < Fh_size; ++i ) raw_props[i] = header[i] = inBuf[inPos++]; if( !Fh_verify_magic( header ) ) { if( !first_member ) break; /* trailing garbage */ - if( inSize - inPos >= 13 - Fh_size ) /* try lzma-alone */ + if( inSize - inPos >= lzma_header_size - Fh_size ) /* try lzma-alone */ { - for( i = Fh_size; i < 13; ++i ) raw_props[i] = inBuf[inPos++]; + for( i = Fh_size; i < lzma_header_size; ++i ) + raw_props[i] = inBuf[inPos++]; for( i = 0; i < 8; ++i ) unpackSize += (uint64_t)raw_props[LZMA_PROPS_SIZE+i] << (i * 8); if( ( raw_props[12] == 0 || raw_props[12] == 0xFF ) && @@ -714,8 +714,7 @@ static int decompress( const int infd, struct Pretty_print * const pp, cleanup_and_fail( 1 ); } if( lzip_mode ) - retval = lzip_decode( &decoder, infd, inBuf, &inPos, &inSize, - Fh_version( header ) ); + retval = lzip_decode( &decoder, infd, inBuf, &inPos, &inSize ); else retval = lzma_decode( unpackSize, &decoder, infd, inBuf, &inPos, &inSize, testing ); @@ -747,14 +746,13 @@ static void set_signals( void ) void Pp_init( struct Pretty_print * const pp, const char * const filenames[], - const int num_filenames, const int v ) + const int num_filenames ) { unsigned stdin_name_len; int i; pp->name = 0; pp->stdin_name = "(stdin)"; pp->longest_name = 0; - pp->verbosity = v; pp->first_post = false; stdin_name_len = strlen( pp->stdin_name ); @@ -939,7 +937,7 @@ int main( const int argc, const char * const argv[] ) ( filenames_given || default_output_filename[0] ) ) set_signals(); - Pp_init( &pp, filenames, num_filenames, verbosity ); + Pp_init( &pp, filenames, num_filenames ); output_filename = resize_buffer( output_filename, 1 ); for( i = 0; i < num_filenames; ++i ) diff --git a/testsuite/check.sh b/testsuite/check.sh index bd7bf3a..994abc2 100755 --- a/testsuite/check.sh +++ b/testsuite/check.sh @@ -1,5 +1,5 @@ #! /bin/sh -# check script for Pdlzip - Data compressor based on the LZMA algorithm +# check script for Pdlzip - LZMA lossless data compressor # Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. # # This script is free software: you have unlimited permission @@ -22,18 +22,40 @@ mkdir tmp cd "${objdir}"/tmp cat "${testdir}"/test.txt > in || framework_failure +in_lz="${testdir}"/test.txt.lz fail=0 printf "testing pdlzip-%s..." "$2" -"${LZIP}" -t "${testdir}"/test.txt.lz || fail=1 -"${LZIP}" -cd "${testdir}"/test.txt.lz > copy || fail=1 +"${LZIP}" -cqs-1 in > /dev/null +if [ $? = 1 ] ; then printf . ; else fail=1 ; printf - ; fi +"${LZIP}" -cqs0 in > /dev/null +if [ $? = 1 ] ; then printf . ; else fail=1 ; printf - ; fi +"${LZIP}" -cqs4095 in > /dev/null +if [ $? = 1 ] ; then printf . ; else fail=1 ; printf - ; fi +"${LZIP}" -cqm274 in > /dev/null +if [ $? = 1 ] ; then printf . ; else fail=1 ; printf - ; fi +"${LZIP}" -tq in +if [ $? = 2 ] ; then printf . ; else fail=1 ; printf - ; fi +"${LZIP}" -tq < in +if [ $? = 2 ] ; then printf . ; else fail=1 ; printf - ; fi +"${LZIP}" -cdq in +if [ $? = 2 ] ; then printf . ; else fail=1 ; printf - ; fi +"${LZIP}" -cdq < in +if [ $? = 2 ] ; then printf . ; else fail=1 ; printf - ; fi +dd if="${in_lz}" bs=1 count=6 2> /dev/null | "${LZIP}" -tq +if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi +dd if="${in_lz}" bs=1 count=20 2> /dev/null | "${LZIP}" -tq +if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi + +"${LZIP}" -t "${in_lz}" || fail=1 +"${LZIP}" -cd "${in_lz}" > copy || fail=1 cmp in copy || fail=1 printf . -"${LZIP}" -cfq "${testdir}"/test.txt.lz > out -if [ $? != 1 ] ; then fail=1 ; printf - ; else printf . ; fi -"${LZIP}" -cF "${testdir}"/test.txt.lz > out || fail=1 +"${LZIP}" -cfq "${in_lz}" > out +if [ $? = 1 ] ; then printf . ; else fail=1 ; printf - ; fi +"${LZIP}" -cF "${in_lz}" > out || fail=1 "${LZIP}" -cd out | "${LZIP}" -d > copy || fail=1 cmp in copy || fail=1 printf . @@ -43,45 +65,36 @@ printf . cmp in copy || fail=1 printf . -"${LZIP}" -cqs-1 in > out -if [ $? != 1 ] ; then fail=1 ; printf - ; else printf . ; fi -"${LZIP}" -cqs0 in > out -if [ $? != 1 ] ; then fail=1 ; printf - ; else printf . ; fi -"${LZIP}" -cqs4095 in > out -if [ $? != 1 ] ; then fail=1 ; printf - ; else printf . ; fi -"${LZIP}" -cqm274 in > out -if [ $? != 1 ] ; then fail=1 ; printf - ; else printf . ; fi - for i in s4Ki 0 1 2 3 4 5 6 7 8s16 9s16 ; do "${LZIP}" -k -$i in || fail=1 mv -f in.lz copy.lz || fail=1 printf "garbage" >> copy.lz || fail=1 "${LZIP}" -df copy.lz || fail=1 cmp in copy || fail=1 - printf . done +printf . for i in s4Ki 0 1 2 3 4 5 6 7 8s16 9s16 ; do "${LZIP}" -c -$i in > out || fail=1 printf "g" >> out || fail=1 "${LZIP}" -cd out > copy || fail=1 cmp in copy || fail=1 - printf . done +printf . for i in s4Ki 0 1 2 3 4 5 6 7 8s16 9s16 ; do "${LZIP}" -$i < in > out || fail=1 "${LZIP}" -d < out > copy || fail=1 cmp in copy || fail=1 - printf . done +printf . for i in s4Ki 0 1 2 3 4 5 6 7 8s16 9s16 ; do "${LZIP}" -f -$i -o out < in || fail=1 "${LZIP}" -df -o copy < out.lz || fail=1 cmp in copy || fail=1 - printf . done +printf . "${LZIP}" < in > anyothername || fail=1 "${LZIP}" -d anyothername || fail=1 -- cgit v1.2.3