package Data::QuickMemoPlus::Reader;
use 5.008001;
use strict;
use warnings;
use JSON;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
our $VERSION = "0.01";
use Exporter qw(import);
our @EXPORT_OK = qw( lqm_to_str );
our $suppress_header = 0;
sub lqm_to_str {
## pass an lqm file exported from QuickMemo+
my ( $lqm_file ) = @_;
if (not -f $lqm_file){
warn "$lqm_file is not a file";
return '';
}
my $note_created_time = "";
if ( $lqm_file =~ /(QuickMemo\+_(\d{6}_\d{6})(\(\d+\))?)/i) {
$note_created_time = $2;
}
my $ref_json_str = extract_json_from_lqm( $lqm_file );
return '' if not $ref_json_str;
my ($extracted_text, $note_category) = extract_text_from_json($ref_json_str);
my $header = "Created date: $note_created_time\n";
$header .= "Category: $note_category\n";
$header .= "-"x79 . "\n";
$header = '' if $suppress_header;
return $header . $extracted_text;
}
#####################################
# Unzip jlqm file and
# return json file contents.
#
sub extract_json_from_lqm {
# unzip
# extract the memoinfo.jlqm file.
my $lqm_file = shift;
# Read a Zip file
my $lqm_zip = Archive::Zip->new();
unless ( $lqm_zip->read( $lqm_file ) == AZ_OK ) {
warn "Error reading $lqm_file";
####### to do: add the zip error to the warning?
return "";
}
my $jlqm_filename = "memoinfo.jlqm";
my $member = $lqm_zip->memberNamed( $jlqm_filename );
############### to do: add warning here if memoinfo.jlqm is missing.
if( not $member ){
warn "File not found: $jlqm_filename in archive $lqm_file";
return "";
}
my ( $string, $status ) = $member->contents();
if(not $status == AZ_OK){
warn "Error extracting $jlqm_filename from $lqm_file : Status = $status";
return "";
}
return \$string;
}
###############################################
# Decode json file contents and
# return the text in 'DescRaw'
sub extract_text_from_json {
my $ref_json_string = shift;
############# To do: eval this and trap errors.
my $href_memo = decode_json $$ref_json_string;
if (not $href_memo){
warn "Error decoding text";
return '','';
}
my $text = "";
foreach( @{$href_memo->{MemoObjectList}} ) {
$text .= $_->{DescRaw};
$text .= "\n";
}
my $category = $href_memo->{Category}->{CategoryName};
$category //= '';
$category =~ s/[^\w-]/_/;
return $text, $category;
}
1;
__END__
####
use strict;
use Test::More 0.98;
use_ok $_ for qw(
LG::QuickMemo_Plus::Extract::Memo
);
done_testing;
##
##
use strict;
use Test::More tests => 5;
use Test::Warn;
use LG::QuickMemo_Plus::Extract::Memo qw( lqm_to_str );
my $lqm_file = 'not_a_file';
warning_is {lqm_to_str($lqm_file)} "$lqm_file is not a file", "warning for missing file.";
$lqm_file = 't/data/good_file.lqm';
warning_is {lqm_to_str($lqm_file)} [], "no warnings for good file.";
$lqm_file = 't/data/junk.lqm';
warnings_like {lqm_to_str($lqm_file)}
[ {carped => qr/format error:/i},
qr/Error reading $lqm_file/,
],
"warnings for non-zip, junk file.";
$lqm_file = 't/data/missing_jlqm.lqm';
warnings_like {lqm_to_str($lqm_file)}
[ qr/File not found: memoinfo.jlqm in archive $lqm_file/,
],
"warnings for archive missing file - memoinfo.jlqm.";
$lqm_file = 't/data/garbled.lqm';
warnings_like {lqm_to_str($lqm_file)}
[ {carped => qr/error: inflate error data error/i},
qr/Error extracting memoinfo.jlqm from $lqm_file/,
],
"warnings for garbled file - memoinfo.jlqm.";
##
##
use warnings;
use strict;
use Test::More tests => 10;
use LG::QuickMemo_Plus::Extract::Memo qw( lqm_to_str );
BEGIN {
unshift @INC, 't/lib';
}
use_ok 'ExampleMemo';
can_ok 'LG::QuickMemo_Plus::Extract::Memo', 'lqm_to_str';
can_ok 'ExampleMemo', 'memo_with_header';
can_ok 'ExampleMemo', 'memo_with_header_no_timestamp';
can_ok 'ExampleMemo', 'memo_no_header';
can_ok 'ExampleMemo', 'jlqm';
my $lqm_file = 't/data/QuickMemo+_191208_220400(5).lqm';
is ( lqm_to_str($lqm_file), ExampleMemo::memo_with_header(), 'memo with full header' );
$lqm_file = 't/data/good_file.lqm';
is ( lqm_to_str($lqm_file), ExampleMemo::memo_with_header_no_timestamp(), 'memo with header - missing timestamp' );
$LG::QuickMemo_Plus::Extract::Memo::suppress_header = 1;
is ( lqm_to_str($lqm_file), ExampleMemo::memo_no_header(), 'memo with no header' );
is ( ${LG::QuickMemo_Plus::Extract::Memo::extract_json_from_lqm($lqm_file)}, ExampleMemo::jlqm(), 'jlqm json contents' );