Create few classes, few repos

master
Dmitry Isaenko 2024-01-07 17:23:27 +03:00
parent 9b41f9c3c0
commit 280dcd0fb0
11 changed files with 348 additions and 61 deletions

View File

@ -0,0 +1,139 @@
package ru.redrise.marinesco;
import java.nio.charset.StandardCharsets;
import lombok.extern.slf4j.Slf4j;
/* ANSI_BLACK = "\u001B[30m";
ANSI_YELLOW = "\u001B[33m";
ANSI_PURPLE = "\u001B[35m";
ANSI_CYAN = "\u001B[36m";
ANSI_WHITE = "\u001B[37m"; */
/**
* Debug tool like hexdump <3
*/
@Slf4j
public class RainbowDump {
private static final String ANSI_RESET = "\u001B[0m";
private static final String ANSI_RED = "\u001B[31m";
private static final String ANSI_GREEN = "\u001B[32m";
private static final String ANSI_BLUE = "\u001B[34m";
private static StringBuilder stringBuilder;
public static void hexDumpUTF8(byte[] byteArray) {
stringBuilder = new StringBuilder(" -- RainbowDump --\n");
if (byteArray == null || byteArray.length == 0)
return;
int k = 0;
boolean lastCharCyrillic = false;
stringBuilder.append(String.format("%s%08x %s", ANSI_BLUE, 0, ANSI_RESET));
for (int i = 0; i < byteArray.length; i++) {
if (k == 8)
stringBuilder.append(" ");
if (k == 16) {
stringBuilder.append(ANSI_GREEN + "| " + ANSI_RESET);
lastCharCyrillic = printChars(byteArray, i, lastCharCyrillic);
stringBuilder.append("\n")
.append(String.format("%s%08x %s", ANSI_BLUE, i, ANSI_RESET));
k = 0;
}
stringBuilder.append(String.format("%02x ", byteArray[i]));
k++;
}
int paddingSize = 16 - (byteArray.length % 16);
if (paddingSize != 16) {
for (int i = 0; i < paddingSize; i++) {
stringBuilder.append(" ");
}
if (paddingSize > 7) {
stringBuilder.append(" ");
}
}
stringBuilder.append(ANSI_GREEN + "| " + ANSI_RESET);
printChars(byteArray, byteArray.length);
stringBuilder.append("\n")
.append(ANSI_RESET)
.append(new String(byteArray, StandardCharsets.UTF_8))
.append("\n");
log.info(stringBuilder.toString());
}
private static void printChars(byte[] byteArray, int pointer){
printChars(byteArray, pointer, false);
}
private static boolean printChars(byte[] byteArray, int pointer, boolean skipFirstByte){
int j;
if (pointer < 16)
j = 0;
else
j = pointer-16;
int utf8val = 0;
if (skipFirstByte){
++j;
stringBuilder.append(" ");
}
for (; j < pointer; j++){
utf8val = 0;
if (byteArray.length > (j+1))
utf8val = ((byteArray[j] & 0xff) << 8) | (byteArray[j+1] & 0xff);
if ((byteArray[j] > 21) && (byteArray[j] < 126)) // man ascii
stringBuilder.append((char) byteArray[j]);
else if (byteArray[j] == 0x0a)
stringBuilder.append("↲"); //"␤"
else if (byteArray[j] == 0x0d)
stringBuilder.append("←"); // "␍"
else if (utf8val >= 0xd080 && utf8val <= 0xd3bf){
byte[] arr = new byte[0x2];
System.arraycopy(byteArray, j, arr, 0, 2);
stringBuilder.append(new String(arr, StandardCharsets.UTF_8)+" ");
++j;
}
else
stringBuilder.append(".");
}
return (utf8val >= 0xd080 && utf8val <= 0xd3bf && j > pointer);
}
public static void hexDumpUTF8Legacy(byte[] byteArray) {
StringBuilder stringBuilderLegacy = new StringBuilder("HexDumpUTF8Legacy");
stringBuilderLegacy.append(ANSI_BLUE);
if (byteArray == null || byteArray.length == 0)
return;
for (int i = 0; i < byteArray.length; i++)
stringBuilderLegacy.append(String.format("%02d-", i % 100));
stringBuilderLegacy.append(">" + ANSI_RED).append(byteArray.length).append(ANSI_RESET).append("\n");
for (byte b : byteArray)
stringBuilderLegacy.append(String.format("%02x ", b));
stringBuilderLegacy.append("\n")
.append(new String(byteArray, StandardCharsets.UTF_8))
.append("\n");
log.info(stringBuilderLegacy.toString());
}
/*
public static void binDumpInt(int value) {
log.info(Converter.intToBinaryString(value));
}
*/
public static void binDumpLong(long value) {
log.info(String.format("%64s", Long.toBinaryString(value)).replace(' ', '0') + " | " + value);
}
public static String formatDecHexString(long value) {
return String.format("%-20d 0x%x", value, value);
}
public static String formatDecHexString(int value) {
return String.format("%-20d 0x%x", value, value);
}
}

View File

@ -0,0 +1,11 @@
package ru.redrise.marinesco.data;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import ru.redrise.marinesco.library.Author;
@Repository
public interface AuthorRepository extends CrudRepository<Author, Long>{
}

View File

@ -0,0 +1,11 @@
package ru.redrise.marinesco.data;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import ru.redrise.marinesco.library.Genre;
@Repository
public interface GenreRepository extends CrudRepository<Genre, String>{
}

View File

@ -0,0 +1,10 @@
package ru.redrise.marinesco.data;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import ru.redrise.marinesco.library.InpEntry;
@Repository
public interface InpEntryRepository extends CrudRepository<InpEntry, Long>{
}

View File

@ -0,0 +1,11 @@
package ru.redrise.marinesco.data;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import ru.redrise.marinesco.library.LibraryMetadata;
@Repository
public interface LibraryMetadataRepository extends CrudRepository<LibraryMetadata, Long>{
}

View File

@ -0,0 +1,30 @@
package ru.redrise.marinesco.library;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
@AllArgsConstructor
public class Author {
// private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(unique=true)
private String authorName;
public Author(String name){
this.authorName = name;
}
}

View File

@ -0,0 +1,17 @@
package ru.redrise.marinesco.library;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.Data;
@Data
@Entity
public class Genre {
@Id
private String genreId;
private String humanReadableDescription;
public Genre(String genreId){
this.genreId = genreId;
}
}

View File

@ -3,31 +3,49 @@ package ru.redrise.marinesco.library;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Transient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.RainbowDump;
@Slf4j
@Entity
@Data
public class InpEntry {
private List<String> authors = new ArrayList<>(); // Surname,name,by-father
private List<String> generes = new ArrayList<>();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToMany
private List<Author> authors; // Surname,name,by-father
@ManyToMany
private List<Genre> genres;
private String title;
private String series;
private String serNo;
private String fsFileName;
private String fileSize; // extracted
private String fsFileName; // inside zip
private String fileSize; // extracted, in bytes
private String libId; // same to filename
private String deleted; // is deleted flag
private String fileExtension; // - concatenate to fsFileName
private LocalDate addedDate;
private String container;
@Transient
private int position;
public InpEntry(byte[] line) throws Exception{
public InpEntry(byte[] line, String container) throws Exception{
// AUTHOR;GENRE;TITLE;SERIES;SERNO;FILE;SIZE;LIBID;DEL;EXT;DATE;
this.container = container;
this.authors = new ArrayList<>();
this.genres = new ArrayList<>();
parseAuthors(line);
parseGenere(line);
this.title = parseNextString(line);
@ -40,10 +58,11 @@ public class InpEntry {
this.fileExtension = parseNextString(line);
this.addedDate = LocalDate.parse(parseNextString(line));
for (String author : authors)
log.info(author);
for (String gen : generes)
log.info(gen);
/*
for (Author author : authors)
log.info(author.getAuthorName());
for (Genre gen : genres)
log.info(gen.getGenreId());
log.info(title);
log.info(series);
@ -56,10 +75,11 @@ public class InpEntry {
log.info(addedDate.toString());
log.info("-----------------");
//*/
}
private void parseAuthors(byte[] line) throws Exception{
for (int i = 0; i < line.length; i++){
if (line[i] == ':' && i+1 < line.length && line[i+1] == 0x04){
if (line[i] == 0x04){
splitAuthors(new String(line, 0, i, StandardCharsets.UTF_8));
position = i+1;
return;
@ -69,23 +89,27 @@ public class InpEntry {
throw new Exception("Invalid 'inp' file format (parse Authors)");
}
private void splitAuthors(String allAuthors){
authors = Arrays.asList(allAuthors.split(":"));
for (String author : allAuthors.split(":")){
authors.add(new Author(author));
}
}
private void parseGenere(byte[] line) throws Exception{
for (int i = position; i < line.length; i++){
if (line[i] == ':'){
if (line[i] == ':' && i+1 < line.length && line[i+1] == 0x04){
generes.add(new String(line, position, i-position, StandardCharsets.UTF_8));
position = i+2;
return;
}
generes.add(new String(line, position, i-position, StandardCharsets.UTF_8));
if (line[i] == 0x04){
splitGenres(new String(line, 0, i, StandardCharsets.UTF_8));
position = i+1;
return;
}
}
RainbowDump.hexDumpUTF8(line);
throw new Exception("Invalid 'inp' file format (parse Genere)");
}
private void splitGenres(String allGenres){
for (String genre : allGenres.split(":")){
genres.add(new Genre(genre));
}
}
private String parseNextString(byte[] line) throws Exception{
for (int i = position; i < line.length; i++){
@ -95,7 +119,7 @@ public class InpEntry {
return resultingString;
}
}
RainbowDump.hexDumpUTF8(line);
throw new Exception("Invalid 'inp' file format (parse Title)");
}
}

View File

@ -1,22 +1,13 @@
package ru.redrise.marinesco.library;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Slf4j
//@Entity
@Data
public class InpFile {
public class InpFileScanner {
private String name;
private final String name;
private final List<InpEntry> inpEntries;
public InpFile(byte[] content, String name) throws Exception{
public InpFileScanner(byte[] content, String name) throws Exception{
this.name = name.substring(0, name.lastIndexOf('.'));
this.inpEntries = new ArrayList<>();
log.info("FILE RELATED "+this.name);
parseContent(content);
}
@ -27,7 +18,7 @@ public class InpFile {
if (content[i] == '\n'){
byte[] line = new byte[i-lastIndex];
System.arraycopy(content, lastIndex, line, 0, i-lastIndex-1);
inpEntries.add(new InpEntry(line));
new InpEntry(line, name);
//RainbowDump.hexDumpUTF8(line);
if (isNextCarriageReturn(i, content)){

View File

@ -13,6 +13,10 @@ import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.data.AuthorRepository;
import ru.redrise.marinesco.data.GenreRepository;
import ru.redrise.marinesco.data.InpEntryRepository;
import ru.redrise.marinesco.data.LibraryMetadataRepository;
@Slf4j
@Component
@ -21,13 +25,23 @@ public class InpxScanner {
private String filesLocation = "";
private FileSystemResource libraryLocation;
private LibraryMetadataRepository libraryMetadataRepository;
private AuthorRepository authorRepository;
private GenreRepository genreRepository;
private InpEntryRepository inpEntryRepository;
private LibraryMetadata collectionFileMeta;
private LibraryMetadata versionFileMeta;
public InpxScanner(AuthorRepository authorRepository,
GenreRepository genreRepository,
InpEntryRepository inpEntryRepository,
LibraryMetadataRepository libraryMetadataRepository) {
this.authorRepository = authorRepository;
this.genreRepository = genreRepository;
this.libraryMetadataRepository = libraryMetadataRepository;
}
public void reScan() throws Exception {
libraryLocation = new FileSystemResource(filesLocation);
LibraryMetadata libraryMetadata = new LibraryMetadata();
final FileSystemResource libraryLocation = new FileSystemResource(filesLocation);
File inpxFile = Stream.of(libraryLocation.getFile().listFiles())
.filter(file -> file.getName().endsWith(".inpx"))
@ -35,44 +49,38 @@ public class InpxScanner {
.get();
log.info("INPX file found as " + inpxFile.getName());
boolean breaker = false;
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(inpxFile))) {
ZipEntry zipEntry = zipInputStream.getNextEntry();
while (zipEntry != null) {
//log.info("Now parsing: " + zipEntry.getName());
if (zipEntry.isDirectory()) {
zipEntry = zipInputStream.getNextEntry();
continue;
}
/* Lines:
* 1 - Collection Display Name
* 2 - Collection file name
* 3 - num: 0 - fb2, 1 - non-FB2
* 4 - description
*/
if (zipEntry.getName().toLowerCase().equals("collection.info"))
setMetadata("collection.info", zipInputStream);
// version.info contains only 1 string
if (zipEntry.getName().toLowerCase().equals("version.info"))
setMetadata("version.info", zipInputStream);
if (zipEntry.getName().toLowerCase().contains("collection.info"))
libraryMetadata.setCollectionInfo(readPlainText(zipInputStream));
if (zipEntry.getName().toLowerCase().endsWith(".inp")){
if (breaker)
break;
breaker = true;
if (zipEntry.getName().toLowerCase().contains("version.info"))
libraryMetadata.setVersionInfo(readPlainText(zipInputStream));
if (zipEntry.getName().toLowerCase().endsWith(".inp")) {
/*
if (breaker) {
zipEntry = zipInputStream.getNextEntry();
continue;
}
breaker = true;// */
parseInp(zipInputStream, zipEntry.getSize(), zipEntry.getName());
}
zipEntry = zipInputStream.getNextEntry();
}
}
}
private void setMetadata(String filename, ZipInputStream zipInputStream) throws Exception {
collectionFileMeta = new LibraryMetadata(filename, readPlainText(zipInputStream));
libraryMetadataRepository.save(libraryMetadata);
}
private String readPlainText(ZipInputStream zipInputStream) throws Exception {
@ -105,7 +113,9 @@ public class InpxScanner {
block = new byte[blockSize];
}
}
new InpFile(inpByteBuffer.array(), fileName);
// TODO : FIX!
//inpFileRepository.save(new InpFile(inpByteBuffer.array(), fileName));
new InpFileScanner(inpByteBuffer.array(), fileName);
}
public String getFilesLocation() {

View File

@ -1,15 +1,48 @@
package ru.redrise.marinesco.library;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/*
* collection.info lines:
* 1 - Collection Display Name
* 2 - Collection file name
* 3 - num: 0 - fb2, 1 - non-FB2
* 4 - description
// version.info contains only 1 string
*/
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LibraryMetadata {
@Id
private String filename;
private String content;
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String libraryName;
private String libraryFileName; // makes no sense, fuck it either way
private Integer libraryType; // used to be good idea but still nobody bother to fill it right so ignore this shit
private String description;
private String version;
public void setVersionInfo(String content) throws Exception {
this.version = content.trim();
}
public void setCollectionInfo(String content) throws Exception {
String[] lines = content.split("\n");
if (lines.length < 4)
throw new Exception("Invalid 'collection.info' file. It contains only "+lines.length+" lines!");
libraryName = lines[0].trim();
libraryFileName = lines[1].trim();
libraryType = Integer.parseInt(lines[2].trim());
description = lines[3].trim();
}
}