first commit
This commit is contained in:
3180
project/fm_viewer/module/bmff.cpp
Normal file
3180
project/fm_viewer/module/bmff.cpp
Normal file
File diff suppressed because it is too large
Load Diff
494
project/fm_viewer/module/bmff.h
Normal file
494
project/fm_viewer/module/bmff.h
Normal file
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
bmff : Blackbox Media Works Format Free
|
||||
jykang 20190923
|
||||
*/
|
||||
|
||||
#ifndef _BMFF_H_
|
||||
#define _BMFF_H_
|
||||
#if (SUPPORT_FORMAT_FREE)
|
||||
|
||||
#define MH3000 1
|
||||
#define MODEL_CONFIG MH3000
|
||||
|
||||
/*
|
||||
============================================================
|
||||
/mnt/app/bmff /dev/mmcblk0 sq1920 0 24 0 noaging noemmc mstar
|
||||
============================================================
|
||||
OpenDevice OK.../dev/mmcblk0
|
||||
mblocks = 31090688(15181MiB) , SD1: 31101840, SD2: 31085775
|
||||
serial number = 0xdeadface
|
||||
FAT total sectors = 0
|
||||
sectors per FAT = 0
|
||||
================================================================
|
||||
frontHeight = 1920, rearHeight = 0
|
||||
frontFileSize = 120Mb, rearFileSize = 0Mb
|
||||
frontParkFileSize = 0Mb, rearParkFileSize = 0Mb
|
||||
frontEventFileSize = 120Mb, rearEventFileSize = 0Mb
|
||||
================================================================
|
||||
NF_Clusters:3840, NR_Clusters:0, EF_Clusters:3840, ER_Clusters:0, PF_Clusters:0, PR_Clusters=0
|
||||
OpenDevice OK.../dev/mmcblk0
|
||||
mblocks = 31090688(15181MiB)
|
||||
DataSectors = 31080832, DataClusters = 485638, SectorsPerFat = 3840
|
||||
AvailableDataClusters = 483332, ScrapsClusters = 3332
|
||||
NormalPercent = 88%, EventPercent = 12%, ManualPercent = 0%, ParkingNormalPercent = 0%, ParkingEventPercent = 0%
|
||||
TotalNormalFileClusters = 422400, TotalEventFileClusters = 57600, TotalManualFileClusters = 0, TotalParkingNormalFileClusters = 0, T
|
||||
otalParkingEventFileClusters = 0
|
||||
NormalFiles = 110, EventFiles = 15, ManualFiles = 0, ParkingNormalFiles = 0, ParkingEventFiles = 0
|
||||
NormalRecords = 110, EventRecords = 15, ManualRecords = 0, ParkingNormalRecords = 0, ParkingEventRecords = 0
|
||||
NormalDirectoryClusters = 1, EventDirectoryClusters = 1
|
||||
RootDirectoryStartCluster = 2, clusters = 1
|
||||
LogDirectoryStartCluster = 3, clusters = 1
|
||||
LogFilesStartCluster = 4, clusters = 288
|
||||
ParkingDirectoryStartCluster = 292, clusters = 0
|
||||
NormalDirectoryStartCluster = 292, clusters = 1
|
||||
EventDirectoryStartCluster = 293, clusters = 1
|
||||
ManualDirectoryStartCluster = 294, clusters = 1
|
||||
ParkingNormalDirectoryStartCluster = 295, clusters = 0
|
||||
ParkingEventDirectoryStartCluster = 295, clusters = 0
|
||||
|
||||
RootDirectoryStartSector = 9856
|
||||
LogDirectoryStartSector = 9920
|
||||
LogFilesStartSector = 9984
|
||||
ParkingDirectoryStartSector = 28416
|
||||
NormalDirectoryStartSector = 28416
|
||||
EventDirectoryStartSector = 28480
|
||||
ManualDirectoryStartSector = 28544
|
||||
ParkingNormalDirectoryStartSector = 28608
|
||||
ParkingEventDirectoryStartSector = 28608
|
||||
serial number = 0xdeadface
|
||||
FAT total sectors = 31088640
|
||||
sectors per FAT = 3840
|
||||
OpenDevice OK.../dev/mmcblk0
|
||||
MBR write OK...
|
||||
Free Clusters = 5346
|
||||
OpenDevice OK.../dev/mmcblk0
|
||||
*/
|
||||
|
||||
// https://github.com/sryze/wdd/blob/master/src/wdd.c
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef WIN32
|
||||
#include <QString>
|
||||
#include <Windows.h>
|
||||
#include <stdint.h>
|
||||
#else // WIN32
|
||||
#include <unistd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif // WIN32
|
||||
#include <string>
|
||||
using std::string;
|
||||
|
||||
#define MIN_SECTORS 0xec000 // 8GB == 0x1000000 ???
|
||||
#define MAX_SECTORS 0x80000000 // 1TB
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
// #define SECTORS_PER_CLUSTER 128
|
||||
#define SECTORS_PER_CLUSTER 64
|
||||
#define CLUSTER_SIZE (SECTORS_PER_CLUSTER * SECTOR_SIZE)
|
||||
#define FAT_RESERVED_SECTORS (128)
|
||||
#define FAT_BOOT_SECTOR_COPY_POSITION 6
|
||||
#define SPF_UNIT 0x80
|
||||
|
||||
#define ACTIVE_PARTITION_FLAG 0
|
||||
#define FILE_SYSTEM_ID 0xc
|
||||
// #define FIRST_SECTOR (2048)
|
||||
#define SIGNATURE 0xaa55
|
||||
#define BM_SERIAL_NUMBER 0xdeadface
|
||||
#define BM_FACTORY_SERIAL_NUMBER 0xdeadfac2
|
||||
|
||||
#define MBR_DISK_SERIAL_NUMBER(mbr) (*((unsigned int *)((char*)(mbr) + 0x1b8)))
|
||||
#define MBR_SIGNATURE(mbr) (*((unsigned short *)((char*)(mbr) + 0x1fe)))
|
||||
|
||||
#define PARTITION_TABLE_PTR(mbr,index) ((char*)(mbr) + 0x1be + (0x10 * (index)))
|
||||
#define PT_ACTIVE_PARTITION_FLAG(mbr,index) (*PARTITION_TABLE_PTR(mbr,index))
|
||||
#define PT_FILE_SYSTEM_ID(mbr,index) (*(PARTITION_TABLE_PTR(mbr,index) + 4))
|
||||
#define PT_FIRST_SECTOR(mbr,index) (*(unsigned int *)(PARTITION_TABLE_PTR(mbr,index) + 8))
|
||||
#define PT_TOTAL_SECTORS(mbr,index) (*(unsigned int *)(PARTITION_TABLE_PTR(mbr,index) + 12))
|
||||
|
||||
#define BS_OEM_ID_POS(bs) ((char*)(bs) + 0x3)
|
||||
#define BS_OEM_ID_SIZE 8
|
||||
#define BS_BYTES_PER_SECTOR(bs) (*(unsigned short *)((char*)(bs) + 0xb))
|
||||
#define BS_SECTORS_PER_CLUSTER(bs) (*(unsigned char *)((char*)(bs) + 0xd))
|
||||
#define BS_RESERVED_SECTORS(bs) (*(unsigned short *)((char*)(bs) + 0xe))
|
||||
#define BS_TOTAL_SECTORS(bs) (*(unsigned int *)((char*)(bs) + 0x20))
|
||||
#define BS_SECTORS_PER_FAT(bs) (*(unsigned int *)((char*)(bs) + 0x24))
|
||||
|
||||
#define SIS_SIGNATURE_FIRST(sis) (*(unsigned int *)((char*)(sis) + 0x0))
|
||||
#define SIS_SIGNATURE_MIDDLE(sis) (*(unsigned int *)((char*)(sis) + 0x1e4))
|
||||
#define SIS_LAST_FREE_CLUSTER(sis) (*(unsigned int *)((char*)(sis) + 0x1e8))
|
||||
#define SIS_LAST_ALLOCATED_CLUSTER(sis) (*(unsigned int *)((char*)(sis) + 0x1ec))
|
||||
#define SIS_SIGNATURE_LAST(sis) (*(unsigned int *)((char*)(sis) + 0x1fc))
|
||||
#define DIRECTORY_OVERHEAD (0xc0)
|
||||
|
||||
#define LOG_DIRECTORY "SYSTEM "
|
||||
#define NORMAL_DIRECTORY "NORMAL "
|
||||
#define EVENT_DIRECTORY "EVENT "
|
||||
#define MANUAL_DIRECTORY "MANUAL "
|
||||
#define PARKING_DIRECTORY "PARKING "
|
||||
#define SYSTEM_DIRECTORY "SYSTEM "
|
||||
#define PARKING_NORMAL_DIRECTORY "NORMAL "
|
||||
#define PARKING_EVENT_DIRECTORY "EVENT "
|
||||
|
||||
#define NORMAL_FRONT_FILE ".NORM_FRON_"
|
||||
#define NORMAL_REAR_FILE ".NORM_REAR_"
|
||||
#define EVENT_FRONT_FILE ".EVEN_FRON_"
|
||||
#define EVENT_REAR_FILE ".EVEN_REAR_"
|
||||
#define MANUAL_FRONT_FILE ".MANU_FRON_"
|
||||
#define MANUAL_REAR_FILE ".MANU_REAR_"
|
||||
#define PARKING_FRONT_FILE ".PARK_FRON_"
|
||||
#define PARKING_REAR_FILE ".PARK_REAR_"
|
||||
#define LOG_SYSTEM0_FILE "HISTORY DM0"
|
||||
#define LOG_SYSTEM1_FILE "HISTORY DM1"
|
||||
#define LOG_SYSTEM2_FILE "HISTORY DM2"
|
||||
#define LOG_RECORD0_FILE "RECORD DM0"
|
||||
#define LOG_RECORD1_FILE "RECORD DM1"
|
||||
#define PARAM_FILE "PARAM ENC"
|
||||
|
||||
#define MiB (1024 * 1024)
|
||||
#define KiB (1024)
|
||||
|
||||
#define FREE_SPACE_CLUSTERS (1600) // 100MiB
|
||||
|
||||
#if (MODEL_CONFIG == FRC)
|
||||
#define FILE_OVERHEAD_MIB (0)
|
||||
#else
|
||||
#define FILE_OVERHEAD_MIB (4)
|
||||
#endif
|
||||
#define GET_FILE_SIZE_BY_SEC(fs60, sec) ((((fs60 / MiB) - FILE_OVERHEAD_MIB) * (sec) / 60 + FILE_OVERHEAD_MIB) * MiB)
|
||||
|
||||
#if (USE_H265 == 0)
|
||||
#define WQHD30_FILE_SIZE ((105 * 210 / 100) * MiB)
|
||||
#define WQHD27_FILE_SIZE ((96 * 210 / 100) * MiB)
|
||||
#define WQHD25_FILE_SIZE ((90 * 210 / 100) * MiB)
|
||||
#define WQHD22_FILE_SIZE ((79 * 210 / 100) * MiB)
|
||||
#define WQHD16_FILE_SIZE ((60 * 210 / 100) * MiB)
|
||||
#define WQHD07_FILE_SIZE ((31 * 210 / 100) * MiB)
|
||||
#define WQHD06_FILE_SIZE ((30 * 210 / 100) * MiB)
|
||||
|
||||
#define SQ1920_30_FILE_SIZE ((105 * 210 / 100) * MiB)
|
||||
#define SQ1920_27_FILE_SIZE ((96 * 210 / 100) * MiB)
|
||||
#define SQ1920_25_FILE_SIZE (SQ1600_25_FILE_SIZE)
|
||||
#define SQ1920_22_FILE_SIZE ((79 * 210 / 100) * MiB)
|
||||
#define SQ1920_16_FILE_SIZE ((60 * 210 / 100) * MiB)
|
||||
#define SQ1920_07_FILE_SIZE ((31 * 210 / 100) * MiB)
|
||||
#define SQ1920_06_FILE_SIZE ((30 * 210 / 100) * MiB)
|
||||
|
||||
#define SHD30_FILE_SIZE ((92 * 210 / 100) * MiB)
|
||||
#define SHD27_FILE_SIZE ((84 * 210 / 100) * MiB)
|
||||
#define SHD25_FILE_SIZE ((78 * 210 / 100) * MiB)
|
||||
#define SHD22_FILE_SIZE ((69 * 210 / 100) * MiB)
|
||||
#define SHD16_FILE_SIZE ((54 * 210 / 100) * MiB)
|
||||
#define SHD07_FILE_SIZE ((27 * 210 / 100) * MiB)
|
||||
#define SHD06_FILE_SIZE ((26 * 210 / 100) * MiB)
|
||||
|
||||
#define SQ1600_30_FILE_SIZE ((92 * 210 / 100) * MiB)
|
||||
#define SQ1600_27_FILE_SIZE ((84 * 210 / 100) * MiB)
|
||||
// #define SQ1600_25_FILE_SIZE ((78 * 210 / 100) * MiB)
|
||||
#define SQ1600_25_FILE_SIZE (120 * MiB)
|
||||
#define SQ1600_22_FILE_SIZE ((69 * 210 / 100) * MiB)
|
||||
#define SQ1600_16_FILE_SIZE ((54 * 210 / 100) * MiB)
|
||||
#define SQ1600_07_FILE_SIZE ((27 * 210 / 100) * MiB)
|
||||
#define SQ1600_06_FILE_SIZE ((26 * 210 / 100) * MiB)
|
||||
|
||||
// #define FHD30_FILE_SIZE ((69 * 210 / 100) * MiB)
|
||||
#define FHD30_FILE_SIZE (108 * MiB)
|
||||
// #define FHD27_FILE_SIZE /*((63 * 210 / 100) * MiB)*/
|
||||
#define FHD27_FILE_SIZE (96 * MiB)
|
||||
#define FHD25_FILE_SIZE ((60 * 210 / 100) * MiB)
|
||||
#define FHD22_FILE_SIZE ((54 * 210 / 100) * MiB)
|
||||
#define FHD16_FILE_SIZE ((42 * 210 / 100) * MiB)
|
||||
#define FHD07_FILE_SIZE ((21 * 210 / 100) * MiB)
|
||||
#define FHD06_FILE_SIZE ((20 * 210 / 100) * MiB)
|
||||
|
||||
#define HD30_FILE_SIZE ((36 * 210 / 100) * MiB)
|
||||
// #define HD27_FILE_SIZE ((32 * 210 / 100) * MiB)
|
||||
#define HD27_FILE_SIZE (53 * MiB)
|
||||
#define HD25_FILE_SIZE ((31 * 210 / 100) * MiB)
|
||||
#define HD22_FILE_SIZE ((27 * 210 / 100) * MiB)
|
||||
#define HD16_FILE_SIZE ((21 * 210 / 100) * MiB)
|
||||
#define HD07_FILE_SIZE ((14 * 210 / 100) * MiB)
|
||||
#define HD06_FILE_SIZE (HD07_FILE_SIZE)
|
||||
#else
|
||||
// #define WQHD30_FILE_SIZE ((71 * 210 / 100) * MiB) // 9.3Mbps
|
||||
#define WQHD30_FILE_SIZE ((68 * 210 / 100) * MiB) // 9.3Mbps
|
||||
#define WQHD27_FILE_SIZE ((64 * 210 / 100) * MiB) // 8.4Mbps
|
||||
#define WQHD25_FILE_SIZE ((60 * 210 / 100) * MiB) // 7.8Mbps
|
||||
#define WQHD22_FILE_SIZE ((53 * 210 / 100) * MiB) // 6.8Mbps
|
||||
#define WQHD16_FILE_SIZE ((40 * 210 / 100) * MiB) // 5.0Mbps
|
||||
#define WQHD07_FILE_SIZE ((21 * 210 / 100) * MiB) // 2.2Mbps
|
||||
#define WQHD06_FILE_SIZE ((20 * 210 / 100) * MiB) // 2.0Mbps
|
||||
|
||||
#define SQ1920_30_FILE_SIZE ((68 * 210 / 100) * MiB)
|
||||
#define SQ1920_27_FILE_SIZE ((64 * 210 / 100) * MiB)
|
||||
#define SQ1920_25_FILE_SIZE ((60 * 210 / 100) * MiB)
|
||||
#define SQ1920_22_FILE_SIZE ((53 * 210 / 100) * MiB)
|
||||
#define SQ1920_16_FILE_SIZE ((40 * 210 / 100) * MiB)
|
||||
#define SQ1920_07_FILE_SIZE ((21 * 210 / 100) * MiB)
|
||||
#define SQ1920_06_FILE_SIZE ((20 * 210 / 100) * MiB)
|
||||
|
||||
#define SHD30_FILE_SIZE ((62 * 210 / 100) * MiB) // 8.1Mbps
|
||||
#define SHD27_FILE_SIZE ((56 * 210 / 100) * MiB) // 7.3Mbps
|
||||
#define SHD25_FILE_SIZE ((52 * 210 / 100) * MiB) // 6.8Mbps
|
||||
#define SHD22_FILE_SIZE ((47 * 210 / 100) * MiB) // 6.0Mbps
|
||||
#define SHD16_FILE_SIZE ((36 * 210 / 100) * MiB) // 4.3Mbps
|
||||
#define SHD07_FILE_SIZE ((19 * 210 / 100) * MiB) // 1.9Mbps
|
||||
#define SHD06_FILE_SIZE ((18 * 210 / 100) * MiB) // 1.7Mbps
|
||||
|
||||
#define SQ1600_30_FILE_SIZE SHD30_FILE_SIZE
|
||||
#define SQ1600_27_FILE_SIZE SHD27_FILE_SIZE
|
||||
#define SQ1600_25_FILE_SIZE SHD25_FILE_SIZE
|
||||
#define SQ1600_22_FILE_SIZE SHD22_FILE_SIZE
|
||||
#define SQ1600_16_FILE_SIZE SHD16_FILE_SIZE
|
||||
#define SQ1600_07_FILE_SIZE SHD07_FILE_SIZE
|
||||
#define SQ1600_06_FILE_SIZE SHD06_FILE_SIZE
|
||||
|
||||
#define FHD30_FILE_SIZE ((47 * 210 / 100) * MiB) // 6.0Mbps
|
||||
#define FHD27_FILE_SIZE ((43 * 210 / 100) * MiB) // 5.4Mbps
|
||||
#define FHD25_FILE_SIZE ((40 * 210 / 100) * MiB) // 5.0Mbps
|
||||
#define FHD22_FILE_SIZE ((36 * 210 / 100) * MiB) // 4.4Mbps
|
||||
#define FHD16_FILE_SIZE ((28 * 210 / 100) * MiB) // 3.2Mbps
|
||||
#define FHD07_FILE_SIZE ((15 * 210 / 100) * MiB) // 1.4Mbps
|
||||
#define FHD06_FILE_SIZE ((14 * 210 / 100) * MiB) // 1.2Mbps
|
||||
|
||||
#define HD30_FILE_SIZE ((24 * 210 / 100) * MiB) // 2.7Mbps
|
||||
#define HD27_FILE_SIZE ((22 * 210 / 100) * MiB) // 2.4Mbps
|
||||
#define HD25_FILE_SIZE ((21 * 210 / 100) * MiB) // 2.2Mbps
|
||||
#define HD22_FILE_SIZE ((19 * 210 / 100) * MiB) // 2.0Mbps
|
||||
#define HD16_FILE_SIZE ((15 * 210 / 100) * MiB) // 1.4Mbps
|
||||
#define HD07_FILE_SIZE ((10 * 210 / 100) * MiB) // 0.62Mbps
|
||||
#define HD06_FILE_SIZE (HD07_FILE_SIZE) // 0.62Mbps
|
||||
#endif
|
||||
// #define WQHD30_FILE_SIZE ((103 * 210 / 100) * MiB) // 9.3Mbps
|
||||
// #define WQHD27_FILE_SIZE ((93 * 210 / 100) * MiB) // 8.4Mbps
|
||||
// #define WQHD22_FILE_SIZE ((77 * 210 / 100) * MiB) // 6.8Mbps
|
||||
// #define WQHD16_FILE_SIZE ((57 * 210 / 100) * MiB) // 5.0Mbps
|
||||
// #define WQHD07_FILE_SIZE ((28 * 210 / 100) * MiB) // 2.2Mbps
|
||||
|
||||
// #define SHD30_FILE_SIZE ((84 * 210 / 100) * MiB) // 8.1Mbps
|
||||
// #define SHD27_FILE_SIZE ((76 * 210 / 100) * MiB) // 7.3Mbps
|
||||
// #define SHD22_FILE_SIZE ((63 * 210 / 100) * MiB) // 6.0Mbps
|
||||
// #define SHD16_FILE_SIZE ((47 * 210 / 100) * MiB) // 4.3Mbps
|
||||
// #define SHD07_FILE_SIZE ((23 * 210 / 100) * MiB) // 1.9Mbps
|
||||
|
||||
// #define FHD30_FILE_SIZE ((60 * 210 / 100) * MiB) // 6.0Mbps
|
||||
// #define FHD27_FILE_SIZE ((54 * 210 / 100) * MiB) // 5.4Mbps
|
||||
// #define FHD22_FILE_SIZE ((45 * 210 / 100) * MiB) // 4.4Mbps
|
||||
// #define FHD16_FILE_SIZE ((34 * 210 / 100) * MiB) // 3.2Mbps
|
||||
// #define FHD07_FILE_SIZE ((18 * 210 / 100) * MiB) // 1.4Mbps
|
||||
|
||||
// #define HD30_FILE_SIZE ((29 * 210 / 100) * MiB) // 2.7Mbps
|
||||
// #define HD27_FILE_SIZE ((27 * 210 / 100) * MiB) // 2.4Mbps
|
||||
// #define HD22_FILE_SIZE ((23 * 210 / 100) * MiB) // 2.0Mbps
|
||||
// #define HD16_FILE_SIZE ((18 * 210 / 100) * MiB) // 1.4Mbps
|
||||
// #define HD07_FILE_SIZE ((11 * 210 / 100) * MiB) // 0.62Mbps
|
||||
|
||||
#define LOG0_FILE_SIZE (4 * MiB)
|
||||
#define LOG1_FILE_SIZE (4 * MiB)
|
||||
#define LOG2_FILE_SIZE (1 * MiB)
|
||||
#define PARAM_FILE_SIZE (128 * SECTOR_SIZE)
|
||||
|
||||
int GetPhysicalDrive(WCHAR DL);
|
||||
|
||||
class BmFF
|
||||
{
|
||||
public:
|
||||
BmFF();
|
||||
int Init(const char *device, int normalFrontFileSize, int normalRearFileSize,
|
||||
int eventFrontFileSize, int eventRearFileSize, int parkFrontFileSize, int parkRearFileSize);
|
||||
// int Init2(const char *device, int frontHeight, int rearHeight, int frontFps);
|
||||
int Init2(const char *device, int frontHeight, int rearHeight, int frontFps, int parkFps);
|
||||
void SetEmmc(void) {mEmmc = true; FIRST_SECTOR = 0;}
|
||||
void SetMstarPark(void) {mMstarPark = true;}
|
||||
int MakeDisk(void);
|
||||
bool VerifyDisk(void);
|
||||
int InvalidateDisk(void);
|
||||
void SetStoragePercent(bool park);
|
||||
char GetFileSystem();
|
||||
void ZeroBlocks(int startSector, int nSectors);
|
||||
// bool RenameRecordFile(string srcFileName, string trgFileName);
|
||||
bool mNoPrintFlag;// = false;
|
||||
bool IsFactoryAging(void) { return mSerialNumber == BM_FACTORY_SERIAL_NUMBER; }
|
||||
bool IsRecovered() {return mRecovered;}
|
||||
|
||||
public:
|
||||
//OVERLAPPED mOV;
|
||||
int FIRST_SECTOR;// = 2048;
|
||||
bool mMstarPark;// = false;
|
||||
bool mEmmc;// = false;
|
||||
unsigned long mBlocks;
|
||||
unsigned long mPtTotalSectors;
|
||||
int mSectorsPerFat;
|
||||
int mDataTotalClusters;
|
||||
#ifdef WIN32
|
||||
HANDLE mFd;
|
||||
QString mDeviceName;
|
||||
#else // WIN32
|
||||
int mFd;
|
||||
string mDeviceName;
|
||||
#endif // WIN32
|
||||
char mRdMasterBootRecord[SECTOR_SIZE];
|
||||
char mRdFat32BootSector[SECTOR_SIZE];
|
||||
char mRdSystemInformationSector[SECTOR_SIZE];
|
||||
char mWrMasterBootRecord[SECTOR_SIZE];
|
||||
char mWrFat32BootSector[SECTOR_SIZE];
|
||||
char mWrSystemInformationSector[SECTOR_SIZE];
|
||||
unsigned long mSerialNumber;// = 0;
|
||||
bool mMakeFactoryAging;// = false;
|
||||
|
||||
int mRootDirectoryStartSector;
|
||||
int mLogDirectoryStartSector;
|
||||
int mLogFilesStartSector;
|
||||
int mNormalDirectoryStartSector;
|
||||
int mEventDirectoryStartSector;
|
||||
int mManualDirectoryStartSector;
|
||||
int mParkingDirectoryStartSector;
|
||||
int mParkingNormalDirectoryStartSector;
|
||||
int mParkingEventDirectoryStartSector;
|
||||
|
||||
int mRootDirectoryStartCluster;// = 2;
|
||||
int mLogDirectoryStartCluster;
|
||||
int mLogFilesStartCluster;
|
||||
int mNormalDirectoryStartCluster;
|
||||
int mEventDirectoryStartCluster;
|
||||
int mManualDirectoryStartCluster;
|
||||
int mParkingDirectoryStartCluster;
|
||||
int mParkingNormalDirectoryStartCluster;
|
||||
int mParkingEventDirectoryStartCluster;
|
||||
|
||||
int mRootDirectoryClusters;// = 1;
|
||||
int mLogDirectoryClusters;// = 1;
|
||||
int mNormalDirectoryClusters;
|
||||
int mEventDirectoryClusters;
|
||||
int mManualDirectoryClusters;
|
||||
int mParkingDirectoryClusters;
|
||||
int mParkingNormalDirectoryClusters;
|
||||
int mParkingEventDirectoryClusters;
|
||||
|
||||
int mNormalFiles;
|
||||
int mEventFiles;
|
||||
int mManualFiles;
|
||||
int mParkingNormalFiles;
|
||||
int mParkingEventFiles;
|
||||
int mNormalRecords;
|
||||
int mEventRecords;
|
||||
int mManualRecords;
|
||||
int mParkingNormalRecords;
|
||||
int mParkingEventRecords;
|
||||
|
||||
int mNormalFrontFileClusters;
|
||||
int mNormalRearFileClusters;
|
||||
int mEventFrontFileClusters;
|
||||
int mEventRearFileClusters;
|
||||
int mManualFrontFileClusters;
|
||||
int mManualRearFileClusters;
|
||||
int mParkingFrontFileClusters;
|
||||
int mParkingRearFileClusters;
|
||||
|
||||
unsigned int mCurrentFatOffset;
|
||||
|
||||
unsigned int *mMemFat;
|
||||
char *mMemRootDirectory;
|
||||
char *mMemLogDirectory;
|
||||
char *mMemNormalDirectory;
|
||||
char *mMemEventDirectory;
|
||||
char *mMemManualDirectory;
|
||||
char *mMemParkingDirectory;
|
||||
char *mMemParkingNormalDirectory;
|
||||
char *mMemParkingEventDirectory;
|
||||
|
||||
unsigned int mFlushStartOffset;
|
||||
|
||||
int mNormalPercent;// = 60;
|
||||
int mEventPercent;// = 15;
|
||||
int mManualPercent;// = 5;
|
||||
int mParkingNormalPercent;// = 18;
|
||||
int mParkingEventPercent;// = 2;
|
||||
|
||||
bool mRecoverFlag;// = false;
|
||||
bool mFormatFlag;// = false;
|
||||
bool mRecovered;// = false;
|
||||
|
||||
protected:
|
||||
int OpenDevice(bool bWrite);
|
||||
void CloseDevice(void);
|
||||
|
||||
void AllocMem(void);
|
||||
void FreeMem(void);
|
||||
|
||||
int GetBlocks(void);
|
||||
int GetBlocksFirst(void);
|
||||
int GetMBR(void);
|
||||
int GetFATBS(void);
|
||||
int GetFAT(void);
|
||||
void CalcFat(void);
|
||||
void HexDump(char *buff, int size);
|
||||
int ChkMBR(void);
|
||||
int ChkPT(void);
|
||||
int UpdateInfo(void);
|
||||
int UpdateInfoFirst(void);
|
||||
void MakeMBR(void);
|
||||
void MakeFATBS(void);
|
||||
void MakeSIS(void);
|
||||
|
||||
void MakeRootDirectory(void);
|
||||
void MakeLogDirectory(void);
|
||||
void MakeParkingDirectory(void);
|
||||
void MakeRecordDirectory(char *data, int directoryStartCluster,
|
||||
const char *fileFullNameFront, const char *fileName83Front, const char *fileFullNameRear, const char *fileName83Rear,
|
||||
int nRecords, int frontFileClusters, int rearFileClusters, int parentStartCluster);
|
||||
|
||||
int WriteAll(void);
|
||||
void MakeMemDirectories(void);
|
||||
int WriteDirectories(void);
|
||||
int WriteSectors(char *data, unsigned int startSector, unsigned int sectors);
|
||||
|
||||
void AddFatElement(unsigned int *pFatBuff, int size);
|
||||
void SetFatElement(unsigned int *pFatBuff, unsigned int startCluster, int size);
|
||||
void SetDirFirstCluster(char *pDirBuff, unsigned int cluster);
|
||||
void SetDirFirstClusterLong(char *pDirBuff, unsigned int cluster);
|
||||
void SetDirFileAttribute(char *pDirBuff, unsigned char attribute);
|
||||
void SetDirFileAttributeLong(char *pDirBuff, unsigned char attribute);
|
||||
void SetDirFileSize(char *pDirBuff, unsigned int fileSize);
|
||||
void SetDirFileSizeLong(char *pDirBuff, unsigned int fileSize);
|
||||
void SetDirFileName(char *pDirBuff, const char *fileName83);
|
||||
void SetDirFileNameLong(char *pDirBuff, const char *fileName83, const char *fileFullName);
|
||||
unsigned char FileNameChecksum(const char *fileName83);
|
||||
void UTF8CharCopy(char *target_u, const char *source_c, int size);
|
||||
void CharUTF8Copy(char *target_c, const char *source_u, int size);
|
||||
void GetDirFirstCluster(char *pDirBuff, unsigned int &cluster);
|
||||
void GetDirFirstClusterLong(char *pDirBuff, unsigned int &cluster);
|
||||
void GetDirFileAttribute(char *pDirBuff, unsigned char &attribute);
|
||||
void GetDirFileAttributeLong(char *pDirBuff, unsigned char &attribute);
|
||||
void GetDirFileSize(char *pDirBuff, unsigned int &fileSize);
|
||||
void GetDirFileSizeLong(char *pDirBuff, unsigned int &fileSize);
|
||||
void GetDirFileName(char *pDirBuff, char *fileName83);
|
||||
void GetDirFileNameLong(char *pDirBuff, char *fileName83, char *fileFullName);
|
||||
|
||||
bool VerifyMBR(void);
|
||||
bool VerifyFATBS(void);
|
||||
bool VerifyFAT(void);
|
||||
bool VerifyDirectories(void);
|
||||
bool VerifyRootDirectory(char *buff);
|
||||
bool VerifyLogDirectory(char *buff);
|
||||
bool VerifyParkingDirectory(char *buff);
|
||||
bool VerifyRecordDirectory(char *buff, int buffSize, char *headNameHidden, char *headNameNormmal, int nRecords, int frontFileClusters, int rearFileClusters);
|
||||
bool ReadSectors(char *data, unsigned int startSector, unsigned int sectors);
|
||||
void ForceFlush(void);
|
||||
|
||||
//#ifdef WIN32
|
||||
// QString ReadFileName(int cluster);
|
||||
// void WriteFileName(QString fname, int cluster);
|
||||
// bool GetDirStartAndSectors(QString fileName, int &startSector, int &nSectors, int &nFiles);
|
||||
//#else // WIN32
|
||||
string ReadFileName(int cluster);
|
||||
void WriteFileName(string fname, int cluster);
|
||||
bool GetDirStartAndSectors(string fileName, int &startSector, int &nSectors, int &nFiles);
|
||||
//#endif // WIN32
|
||||
int RecoverDirectories(void);
|
||||
|
||||
int GetFileSize(int height, int fps);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // #if (SUPPORT_FORMAT_FREE)
|
||||
295
project/fm_viewer/module/fm_version_checker.cpp
Normal file
295
project/fm_viewer/module/fm_version_checker.cpp
Normal file
@@ -0,0 +1,295 @@
|
||||
|
||||
#include "fm_version_checker.h"
|
||||
#if (USE_VERSION_CHECK)
|
||||
#include "../rm_include.h"
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonObject>
|
||||
|
||||
#if (RM_MODEL == RM_MODEL_TYPE_TB4000)
|
||||
static QString VERSION_URL = "https://www.telebit.co.kr/html/download/pcviewer_version.json";
|
||||
#if(SUB_MODEL_TB5000)
|
||||
static QString VERSION_MODEL_NAME = "TB5000";
|
||||
#else // SUB_MODEL_TB5000
|
||||
static QString VERSION_MODEL_NAME = "TB4000";
|
||||
#endif // SUB_MODEL_TB5000
|
||||
#endif // TB4000 + TB5000
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
#include "../cfg/rm_settings_cfg_emt_kr.h"
|
||||
|
||||
|
||||
//static const char VERSION_URL[] = "http://fmproject2.iptime.org/emt/nexian/versions.php";
|
||||
// static const char VERSION_MODEL_NAME[] = "viewer";
|
||||
static const char VERSION_URL[] = "https://nexiandownload.kr/API/app_data.php";
|
||||
//static const char VERSION_MODEL_NAME[] = "PCV";
|
||||
|
||||
// 모델별 확인되면 해당 URL 로 이동, 확인되지 않으면 NM5000_URL 로 이동
|
||||
static const char NM5000_URL[] = "https://nexiandownload.kr/download_view.php?TYPE_CD=PCV&PRODUCT_SEQ=&&seq=PST_0011";
|
||||
static const char MIRROR5_URL[] = "https://nexiandownload.kr/download_view.php?TYPE_CD=PCV&PRODUCT_SEQ=&seq=PST_0012";
|
||||
static const char NP5000_URL[] = "https://nexiandownload.kr/download_view.php?TYPE_CD=PCV&PRODUCT_SEQ=&seq=PST_0013";
|
||||
static const char PRO5_URL[] = "https://nexiandownload.kr/download_view.php?TYPE_CD=PCV&PRODUCT_SEQ=&seq=PST_0014";
|
||||
|
||||
#endif // @RM_MODEL_EMT_KR
|
||||
|
||||
FMVersionChecker* FMVersionChecker::_instance = NULL;
|
||||
|
||||
FMVersionChecker::FMVersionChecker(QObject *parent): QObject(parent)
|
||||
{
|
||||
_checkedViewer = false;
|
||||
}
|
||||
void FMVersionChecker::start()
|
||||
{
|
||||
//qInfo() << __FUNCTION__;
|
||||
//_updates.clear();
|
||||
|
||||
// 이미 처리 완료
|
||||
if(_checkedViewer) {
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkAccessManager* manager = new QNetworkAccessManager();
|
||||
connect(manager,SIGNAL(finished(QNetworkReply*)),SLOT(onFinished(QNetworkReply*)));
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(VERSION_URL));
|
||||
manager->get(request);
|
||||
}
|
||||
// URL 정보 확인 결과
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
void FMVersionChecker::onFinished(QNetworkReply* reply)
|
||||
{
|
||||
if(reply->error())
|
||||
{
|
||||
#if (USER_LOGER)
|
||||
if(RMApp::instance()->userLog) {
|
||||
RMApp::instance()->appendLog("ERROR","VERSION_CHECK:" + reply->errorString());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else // 정상 수신
|
||||
{
|
||||
QString nv = reply->readAll(); // 데이터 불러오기
|
||||
if (nv.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
_checkedViewer = true;
|
||||
#if (1) // 양산서버
|
||||
// <pre>{</pre>
|
||||
nv = nv.replace("<pre>","").replace("</pre>","");
|
||||
QJsonDocument doc = QJsonDocument::fromJson(nv.toUtf8());
|
||||
QJsonObject root = doc.object();
|
||||
if(!root.contains("models")) {
|
||||
return;
|
||||
}
|
||||
QString currentVersion = QString().sprintf("%d.%d.%d",RM_MODEL_VERSION_0,RM_MODEL_VERSION_1,RM_MODEL_VERSION_2); // ,RM_MODEL_SVN_VERSION
|
||||
QJsonArray obj = root.value("models").toArray();
|
||||
for(int i=0;i<obj.size();i++) {
|
||||
QJsonObject item = obj.at(i).toObject();
|
||||
if(!item.contains("model") || !item.contains("data")) {
|
||||
continue;
|
||||
}
|
||||
// Pro 5 -> pro5, 실제 모델 확인은 필요 없음
|
||||
// QString model = item.value("model").toString().replace(" ","").trimmed().toLower();
|
||||
QJsonObject data = item.value("data").toObject();
|
||||
if(!data.contains("PCV")) {
|
||||
continue;
|
||||
}
|
||||
QJsonObject pcv = data.value("PCV").toObject();
|
||||
if(!pcv.contains("version"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QString version = pcv.value("version").toString().toLower().replace("v","").trimmed();
|
||||
if(version != currentVersion) { //
|
||||
QMap<QString,QString> info;
|
||||
for(int j=0;j<pcv.keys().size();j++) {
|
||||
QString key = pcv.keys().at(j);
|
||||
info.insert(key,pcv.value(key).toString());
|
||||
}
|
||||
emit updateFound(info);
|
||||
break;
|
||||
}
|
||||
} // for
|
||||
#else // 개발서버
|
||||
QJsonDocument doc = QJsonDocument::fromJson(nv.toUtf8());
|
||||
QJsonArray obj = doc.array();
|
||||
QString currentVersion = QString().sprintf("%d.%d.%d.%d",RM_MODEL_VERSION_0,RM_MODEL_VERSION_1,RM_MODEL_VERSION_2,RM_MODEL_SVN_VERSION);
|
||||
for(int i=0;i<obj.size();i++) {
|
||||
QJsonObject item = obj.at(i).toObject();
|
||||
if(item.contains("model") &&
|
||||
item.contains("fw") &&
|
||||
item.value("model").toString().trimmed() == VERSION_MODEL_NAME) {
|
||||
|
||||
QJsonObject fwitem = item.value("fw").toObject();
|
||||
if(fwitem.contains("version"))
|
||||
{
|
||||
QString version = fwitem.value("version").toString().trimmed();
|
||||
//qInfo() << "VERSION CURRENT:" << currentVersion << "SERVER:" << version << __FUNCTION__;
|
||||
if(version != currentVersion) { //
|
||||
QMap<QString,QString> info;
|
||||
for(int j=0;j<fwitem.keys().size();j++) {
|
||||
QString key = fwitem.keys().at(j);
|
||||
info.insert(key,fwitem.value(key).toString());
|
||||
}
|
||||
emit updateFound(info);
|
||||
break;
|
||||
}
|
||||
} // @if(fwitem.contains("version"))
|
||||
}
|
||||
}
|
||||
#endif // 개발서버
|
||||
} // else
|
||||
}
|
||||
#else // Telebit?
|
||||
void FMVersionChecker::onFinished(QNetworkReply* reply)
|
||||
{
|
||||
if(reply->error())
|
||||
{
|
||||
#if (USER_LOGER)
|
||||
if(RMApp::instance()->userLog) {
|
||||
RMApp::instance()->appendLog("ERROR","VERSION_CHECK:" + reply->errorString());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else // 정상 수신
|
||||
{
|
||||
QString nv = reply->readAll(); // 데이터 불러오기
|
||||
if (nv.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
_checkedViewer = true;
|
||||
// 에러 처리 -> 이후 제거예정
|
||||
//nv = nv.replace("},\r\n]","}\r\n]");
|
||||
QJsonDocument doc = QJsonDocument::fromJson(nv.toUtf8());
|
||||
QJsonArray obj = doc.array();
|
||||
QString currentVersion = QString().sprintf("%d.%d.%d",RM_MODEL_VERSION_0,RM_MODEL_VERSION_1,RM_MODEL_VERSION_2);
|
||||
for(int i=0;i<obj.size();i++) {
|
||||
QJsonObject item = obj.at(i).toObject();
|
||||
|
||||
if(item.contains("name") && item.value("name").toString().trimmed() == VERSION_MODEL_NAME) {
|
||||
QString iv = item.value("version").toString().trimmed();
|
||||
|
||||
if(item.contains("version") && iv.compare(currentVersion) > 0)
|
||||
{
|
||||
QMap<QString,QString> info;
|
||||
for(int j=0;j<item.keys().size();j++) {
|
||||
QString key = item.keys().at(j);
|
||||
info.insert(key,item.value(key).toString());
|
||||
}
|
||||
emit updateFound(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // EMT/TELEBIT
|
||||
|
||||
|
||||
FMVersionDialog::FMVersionDialog(QMap<QString,QString> update, QWidget *parent) : QDialog(parent,Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint)
|
||||
{
|
||||
_info = update;
|
||||
setWindowTitle(FM_WSTR(L"업데이트 알림"));
|
||||
setFixedSize(420,220);
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
layout->setSpacing(15);
|
||||
setLayout(layout);
|
||||
|
||||
|
||||
// 새로운 버전의 소프트웨어를 사용할 수 있습니다.
|
||||
QLabel* t1 = new QLabel(this);
|
||||
t1->setText(FM_WSTR(L"새롭게 업데이트된 버전이 확인되었습니다."));
|
||||
layout->addWidget(t1);
|
||||
|
||||
QFont font = t1->font();
|
||||
font.setPixelSize(12);
|
||||
font.setFamily("Arial");
|
||||
font.setLetterSpacing(QFont::PercentageSpacing,108);
|
||||
font.setStyleStrategy(QFont::PreferAntialias);
|
||||
t1->setFont(font);
|
||||
|
||||
// 다운로드하려면 아래 URL을 클릭하십시오.
|
||||
QLabel* t2 = new QLabel(this);
|
||||
t2->setText(FM_WSTR(L"다운로드하려면 아래 URL을 클릭하십시오."));
|
||||
t2->setFont(font);
|
||||
layout->addWidget(t2);
|
||||
|
||||
QString currentVersionPrefix = FM_WSTR(L"현재 버전:");
|
||||
QString nextVersionPrefix = FM_WSTR(L"업데이트된 버전:");
|
||||
QString typeTitle = FM_WSTR(L"S/W");
|
||||
|
||||
QLabel* tt = new QLabel(this);
|
||||
tt->setFont(font);
|
||||
|
||||
tt->setText("<b>" + typeTitle + "</b>");
|
||||
tt->setFont(font);
|
||||
layout->addWidget(tt);
|
||||
|
||||
QLabel* versions = new QLabel(this);
|
||||
versions->setIndent(10);
|
||||
versions->setFont(font);
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
QString currentVersion = QString().sprintf("%d.%d.%d",RM_MODEL_VERSION_0,RM_MODEL_VERSION_1,RM_MODEL_VERSION_2);
|
||||
// → \xe2\x86\x92
|
||||
versions->setText(currentVersionPrefix + "\t<b>" + currentVersion + "</b>\t" + QString::fromUtf8("\xe2\x86\x92") + "\t" + nextVersionPrefix + "\t<b>" + _info.value("version") + "\t</b>");
|
||||
#else // RM_MODEL_EMT_KR
|
||||
QString currentVersion = QString().sprintf("%d.%d.%d",RM_MODEL_VERSION_0,RM_MODEL_VERSION_1,RM_MODEL_VERSION_2);
|
||||
versions->setText(currentVersionPrefix + "\t<b>" + currentVersion + "</b>\t" + QString::fromUtf8("\xe2\x86\x92") + "\t" + nextVersionPrefix + "\t<b>" + _info.value("version") + "\t</b>");
|
||||
#endif // RM_MODEL_EMT_KR
|
||||
layout->addWidget(versions);
|
||||
|
||||
|
||||
// LINK
|
||||
QLabel* urlLink = new QLabel(this);
|
||||
urlLink->setFont(font);
|
||||
|
||||
#if (RM_MODEL_EMT_KR)
|
||||
// _info.value("url") 는 무시 각 모델별 다운로드 페이지로 이동
|
||||
QString url = NM5000_URL;
|
||||
if (CFG::info.model == NM5000) { // NM5000
|
||||
// url = NM5000_URL;
|
||||
} else if (CFG::info.model == NP5000) { // NP5000
|
||||
url =NP5000_URL;
|
||||
} else if (CFG::info.model == MIRROR5) { // MIRROR5
|
||||
url =MIRROR5_URL;
|
||||
} else if (CFG::info.model == PRO5) { // PRO5
|
||||
url =PRO5_URL;
|
||||
}
|
||||
#else // EMT_KR
|
||||
QString url = _info.value("url");
|
||||
#endif // RM_MODEL_EMT_KR
|
||||
|
||||
|
||||
urlLink->setIndent(10);
|
||||
// _info.value("url")
|
||||
urlLink->setText("<a href=\"" + url + "\">" + FM_WSTR(L"다운로드 페이지로 이동") + "</a>");
|
||||
urlLink->setTextFormat(Qt::RichText);
|
||||
urlLink->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
urlLink->setOpenExternalLinks(true);
|
||||
QFont font2 = urlLink->font();
|
||||
font2.setFamily("Arial");
|
||||
font2.setPixelSize(14);
|
||||
urlLink->setFont(font2);
|
||||
|
||||
layout->addWidget(urlLink);
|
||||
|
||||
// Close
|
||||
QWidget* buttonWidget = new QWidget(this);
|
||||
buttonWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
|
||||
layout->addWidget(buttonWidget);
|
||||
QHBoxLayout* bl = new QHBoxLayout(buttonWidget);
|
||||
bl->setAlignment(Qt::AlignBottom | Qt::AlignRight);
|
||||
QPushButton* closeButton = new QPushButton(buttonWidget);
|
||||
closeButton->setFixedWidth(100);
|
||||
closeButton->setFont(font);
|
||||
closeButton->setText(FM_WSTR(L"닫기"));
|
||||
connect(closeButton,&QPushButton::clicked,[=]() {
|
||||
reject();
|
||||
});
|
||||
bl->addWidget(closeButton);
|
||||
}
|
||||
|
||||
|
||||
#endif // #if (USE_VERSION_CHECK)
|
||||
50
project/fm_viewer/module/fm_version_checker.h
Normal file
50
project/fm_viewer/module/fm_version_checker.h
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
#ifndef FM_VERSION_CHECKER_H
|
||||
#define FM_VERSION_CHECKER_H
|
||||
#if (USE_VERSION_CHECK)
|
||||
|
||||
#include <QObject>
|
||||
#include <QtCore>
|
||||
#include <QDialog>
|
||||
|
||||
class QNetworkReply;
|
||||
class FMVersionChecker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static FMVersionChecker* _instance;
|
||||
explicit FMVersionChecker(QObject *parent = nullptr);
|
||||
void start();
|
||||
static FMVersionChecker* instance()
|
||||
{
|
||||
if(_instance == NULL)
|
||||
{
|
||||
_instance = new FMVersionChecker();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
private:
|
||||
bool _checkedViewer;
|
||||
|
||||
signals:
|
||||
void updateFound(QMap<QString,QString>); // 업데이트 정보 발견
|
||||
|
||||
public slots:
|
||||
void onFinished(QNetworkReply* reply);
|
||||
};
|
||||
|
||||
class FMVersionDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FMVersionDialog(QMap<QString,QString> update, QWidget *parent = nullptr);
|
||||
private:
|
||||
QMap<QString,QString> _info;
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
|
||||
#endif // #if (USE_VERSION_CHECK)
|
||||
#endif // FM_VERSION_CHECKER_H
|
||||
231
project/fm_viewer/module/rm_crypt.cpp
Normal file
231
project/fm_viewer/module/rm_crypt.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
#include "rm_crypt.h"
|
||||
|
||||
#if (RM_MODEL_TB4000 || RM_MODEL_TB5000)
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QtDebug>
|
||||
#include <QtGlobal>
|
||||
#include <QDateTime>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDataStream>
|
||||
|
||||
RMCrypt::RMCrypt():
|
||||
m_key(0),
|
||||
m_compressionMode(CompressionAuto),
|
||||
m_protectionMode(ProtectionChecksum),
|
||||
m_lastError(ErrorNoError)
|
||||
{
|
||||
qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
|
||||
}
|
||||
|
||||
RMCrypt::RMCrypt(quint64 key):
|
||||
m_key(key),
|
||||
m_compressionMode(CompressionAuto),
|
||||
m_protectionMode(ProtectionChecksum),
|
||||
m_lastError(ErrorNoError)
|
||||
{
|
||||
qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
|
||||
splitKey();
|
||||
}
|
||||
|
||||
void RMCrypt::setKey(quint64 key)
|
||||
{
|
||||
m_key = key;
|
||||
splitKey();
|
||||
}
|
||||
|
||||
void RMCrypt::splitKey()
|
||||
{
|
||||
m_keyParts.clear();
|
||||
m_keyParts.resize(8);
|
||||
for (int i=0;i<8;i++) {
|
||||
quint64 part = m_key;
|
||||
for (int j=i; j>0; j--)
|
||||
part = part >> 8;
|
||||
part = part & 0xff;
|
||||
m_keyParts[i] = static_cast<char>(part);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray RMCrypt::encryptToByteArray(const QString& plaintext)
|
||||
{
|
||||
QByteArray plaintextArray = plaintext.toUtf8();
|
||||
return encryptToByteArray(plaintextArray);
|
||||
}
|
||||
|
||||
QByteArray RMCrypt::encryptToByteArray(QByteArray plaintext)
|
||||
{
|
||||
if (m_keyParts.isEmpty()) {
|
||||
qWarning() << "No key set.";
|
||||
m_lastError = ErrorNoKeySet;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
|
||||
QByteArray ba = plaintext;
|
||||
|
||||
CryptoFlags flags = CryptoFlagNone;
|
||||
if (m_compressionMode == CompressionAlways) {
|
||||
ba = qCompress(ba, 9); //maximum compression
|
||||
flags |= CryptoFlagCompression;
|
||||
} else if (m_compressionMode == CompressionAuto) {
|
||||
QByteArray compressed = qCompress(ba, 9);
|
||||
if (compressed.count() < ba.count()) {
|
||||
ba = compressed;
|
||||
flags |= CryptoFlagCompression;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray integrityProtection;
|
||||
if (m_protectionMode == ProtectionChecksum) {
|
||||
flags |= CryptoFlagChecksum;
|
||||
QDataStream s(&integrityProtection, QIODevice::WriteOnly);
|
||||
s << qChecksum(ba.constData(), ba.length());
|
||||
} else if (m_protectionMode == ProtectionHash) {
|
||||
flags |= CryptoFlagHash;
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
hash.addData(ba);
|
||||
|
||||
integrityProtection += hash.result();
|
||||
}
|
||||
|
||||
//prepend a random char to the string
|
||||
char randomChar = char(qrand() & 0xFF);
|
||||
ba = randomChar + integrityProtection + ba;
|
||||
|
||||
int pos(0);
|
||||
char lastChar(0);
|
||||
|
||||
int cnt = ba.count();
|
||||
|
||||
while (pos < cnt) {
|
||||
ba[pos] = ba.at(pos) ^ m_keyParts.at(pos % 8) ^ lastChar;
|
||||
lastChar = ba.at(pos);
|
||||
++pos;
|
||||
}
|
||||
|
||||
QByteArray resultArray;
|
||||
resultArray.append(char(0x03)); //version for future updates to algorithm
|
||||
resultArray.append(char(flags)); //encryption flags
|
||||
resultArray.append(ba);
|
||||
|
||||
m_lastError = ErrorNoError;
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
QString RMCrypt::encryptToString(const QString& plaintext)
|
||||
{
|
||||
QByteArray plaintextArray = plaintext.toUtf8();
|
||||
QByteArray cypher = encryptToByteArray(plaintextArray);
|
||||
QString cypherString = QString::fromLatin1(cypher.toBase64());
|
||||
return cypherString;
|
||||
}
|
||||
|
||||
QString RMCrypt::encryptToString(QByteArray plaintext)
|
||||
{
|
||||
QByteArray cypher = encryptToByteArray(plaintext);
|
||||
QString cypherString = QString::fromLatin1(cypher.toBase64());
|
||||
return cypherString;
|
||||
}
|
||||
|
||||
QString RMCrypt::decryptToString(const QString &cyphertext)
|
||||
{
|
||||
QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1());
|
||||
QByteArray plaintextArray = decryptToByteArray(cyphertextArray);
|
||||
QString plaintext = QString::fromUtf8(plaintextArray, plaintextArray.size());
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
QString RMCrypt::decryptToString(QByteArray cypher)
|
||||
{
|
||||
QByteArray ba = decryptToByteArray(cypher);
|
||||
QString plaintext = QString::fromUtf8(ba, ba.size());
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
QByteArray RMCrypt::decryptToByteArray(const QString& cyphertext)
|
||||
{
|
||||
QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1());
|
||||
QByteArray ba = decryptToByteArray(cyphertextArray);
|
||||
|
||||
return ba;
|
||||
}
|
||||
|
||||
QByteArray RMCrypt::decryptToByteArray(QByteArray cypher)
|
||||
{
|
||||
if (m_keyParts.isEmpty()) {
|
||||
qWarning() << "No key set.";
|
||||
m_lastError = ErrorNoKeySet;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray ba = cypher;
|
||||
|
||||
if( cypher.count() < 3 )
|
||||
return QByteArray();
|
||||
|
||||
char version = ba.at(0);
|
||||
|
||||
if (version !=3) { //we only work with version 3
|
||||
m_lastError = ErrorUnknownVersion;
|
||||
qWarning() << "Invalid version or not a cyphertext.";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
CryptoFlags flags = CryptoFlags(ba.at(1));
|
||||
|
||||
ba = ba.mid(2);
|
||||
int pos(0);
|
||||
int cnt(ba.count());
|
||||
char lastChar = 0;
|
||||
|
||||
while (pos < cnt) {
|
||||
char currentChar = ba[pos];
|
||||
ba[pos] = ba.at(pos) ^ lastChar ^ m_keyParts.at(pos % 8);
|
||||
lastChar = currentChar;
|
||||
++pos;
|
||||
}
|
||||
|
||||
ba = ba.mid(1); //chop off the random number at the start
|
||||
|
||||
bool integrityOk(true);
|
||||
if (flags.testFlag(CryptoFlagChecksum)) {
|
||||
if (ba.length() < 2) {
|
||||
m_lastError = ErrorIntegrityFailed;
|
||||
return QByteArray();
|
||||
}
|
||||
quint16 storedChecksum;
|
||||
{
|
||||
QDataStream s(&ba, QIODevice::ReadOnly);
|
||||
s >> storedChecksum;
|
||||
}
|
||||
ba = ba.mid(2);
|
||||
quint16 checksum = qChecksum(ba.constData(), ba.length());
|
||||
integrityOk = (checksum == storedChecksum);
|
||||
} else if (flags.testFlag(CryptoFlagHash)) {
|
||||
if (ba.length() < 20) {
|
||||
m_lastError = ErrorIntegrityFailed;
|
||||
return QByteArray();
|
||||
}
|
||||
QByteArray storedHash = ba.left(20);
|
||||
ba = ba.mid(20);
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
hash.addData(ba);
|
||||
integrityOk = (hash.result() == storedHash);
|
||||
}
|
||||
|
||||
if (!integrityOk) {
|
||||
m_lastError = ErrorIntegrityFailed;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
if (flags.testFlag(CryptoFlagCompression))
|
||||
ba = qUncompress(ba);
|
||||
|
||||
m_lastError = ErrorNoError;
|
||||
return ba;
|
||||
}
|
||||
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_TELEBIT)
|
||||
184
project/fm_viewer/module/rm_crypt.h
Normal file
184
project/fm_viewer/module/rm_crypt.h
Normal file
@@ -0,0 +1,184 @@
|
||||
#ifndef RM_CRYPT_H
|
||||
#define RM_CRYPT_H
|
||||
|
||||
|
||||
// 일단 Telebit 만 사용
|
||||
#if (RM_MODEL_TB4000 || RM_MODEL_TB5000)
|
||||
|
||||
#include "rm_include.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QFlags>
|
||||
|
||||
|
||||
class RMCrypt
|
||||
{
|
||||
public:
|
||||
/**
|
||||
CompressionMode describes if compression will be applied to the data to be
|
||||
encrypted.
|
||||
*/
|
||||
enum CompressionMode {
|
||||
CompressionAuto, /*!< Only apply compression if that results in a shorter plaintext. */
|
||||
CompressionAlways, /*!< Always apply compression. Note that for short inputs, a compression may result in longer data */
|
||||
CompressionNever /*!< Never apply compression. */
|
||||
};
|
||||
/**
|
||||
IntegrityProtectionMode describes measures taken to make it possible to detect problems with the data
|
||||
or wrong decryption keys.
|
||||
|
||||
Measures involve adding a checksum or a cryptograhpic hash to the data to be encrypted. This
|
||||
increases the length of the resulting cypertext, but makes it possible to check if the plaintext
|
||||
appears to be valid after decryption.
|
||||
*/
|
||||
enum IntegrityProtectionMode {
|
||||
ProtectionNone, /*!< The integerity of the encrypted data is not protected. It is not really possible to detect a wrong key, for instance. */
|
||||
ProtectionChecksum,/*!< A simple checksum is used to verify that the data is in order. If not, an empty string is returned. */
|
||||
ProtectionHash /*!< A cryptographic hash is used to verify the integrity of the data. This method produces a much stronger, but longer check */
|
||||
};
|
||||
/**
|
||||
Error describes the type of error that occured.
|
||||
*/
|
||||
enum Error {
|
||||
ErrorNoError, /*!< No error occurred. */
|
||||
ErrorNoKeySet, /*!< No key was set. You can not encrypt or decrypt without a valid key. */
|
||||
ErrorUnknownVersion, /*!< The version of this data is unknown, or the data is otherwise not valid. */
|
||||
ErrorIntegrityFailed, /*!< The integrity check of the data failed. Perhaps the wrong key was used. */
|
||||
};
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
|
||||
Constructs a SimpleCrypt instance without a valid key set on it.
|
||||
*/
|
||||
RMCrypt();
|
||||
/**
|
||||
Constructor.
|
||||
|
||||
Constructs a SimpleCrypt instance and initializes it with the given @arg key.
|
||||
*/
|
||||
explicit RMCrypt(quint64 key);
|
||||
|
||||
/**
|
||||
(Re-) initializes the key with the given @arg key.
|
||||
*/
|
||||
void setKey(quint64 key);
|
||||
/**
|
||||
Returns true if SimpleCrypt has been initialized with a key.
|
||||
*/
|
||||
bool hasKey() const {return !m_keyParts.isEmpty();}
|
||||
|
||||
/**
|
||||
Sets the compression mode to use when encrypting data. The default mode is Auto.
|
||||
|
||||
Note that decryption is not influenced by this mode, as the decryption recognizes
|
||||
what mode was used when encrypting.
|
||||
*/
|
||||
void setCompressionMode(CompressionMode mode) {m_compressionMode = mode;}
|
||||
/**
|
||||
Returns the CompressionMode that is currently in use.
|
||||
*/
|
||||
CompressionMode compressionMode() const {return m_compressionMode;}
|
||||
|
||||
/**
|
||||
Sets the integrity mode to use when encrypting data. The default mode is Checksum.
|
||||
|
||||
Note that decryption is not influenced by this mode, as the decryption recognizes
|
||||
what mode was used when encrypting.
|
||||
*/
|
||||
void setIntegrityProtectionMode(IntegrityProtectionMode mode) {m_protectionMode = mode;}
|
||||
/**
|
||||
Returns the IntegrityProtectionMode that is currently in use.
|
||||
*/
|
||||
IntegrityProtectionMode integrityProtectionMode() const {return m_protectionMode;}
|
||||
|
||||
/**
|
||||
Returns the last error that occurred.
|
||||
*/
|
||||
Error lastError() const {return m_lastError;}
|
||||
|
||||
/**
|
||||
Encrypts the @arg plaintext string with the key the class was initialized with, and returns
|
||||
a cyphertext the result. The result is a base64 encoded version of the binary array that is the
|
||||
actual result of the string, so it can be stored easily in a text format.
|
||||
*/
|
||||
QString encryptToString(const QString& plaintext) ;
|
||||
/**
|
||||
Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns
|
||||
a cyphertext the result. The result is a base64 encoded version of the binary array that is the
|
||||
actual result of the encryption, so it can be stored easily in a text format.
|
||||
*/
|
||||
QString encryptToString(QByteArray plaintext) ;
|
||||
/**
|
||||
Encrypts the @arg plaintext string with the key the class was initialized with, and returns
|
||||
a binary cyphertext in a QByteArray the result.
|
||||
|
||||
This method returns a byte array, that is useable for storing a binary format. If you need
|
||||
a string you can store in a text file, use encryptToString() instead.
|
||||
*/
|
||||
QByteArray encryptToByteArray(const QString& plaintext) ;
|
||||
/**
|
||||
Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns
|
||||
a binary cyphertext in a QByteArray the result.
|
||||
|
||||
This method returns a byte array, that is useable for storing a binary format. If you need
|
||||
a string you can store in a text file, use encryptToString() instead.
|
||||
*/
|
||||
QByteArray encryptToByteArray(QByteArray plaintext) ;
|
||||
|
||||
/**
|
||||
Decrypts a cyphertext string encrypted with this class with the set key back to the
|
||||
plain text version.
|
||||
|
||||
If an error occured, such as non-matching keys between encryption and decryption,
|
||||
an empty string or a string containing nonsense may be returned.
|
||||
*/
|
||||
QString decryptToString(const QString& cyphertext) ;
|
||||
/**
|
||||
Decrypts a cyphertext string encrypted with this class with the set key back to the
|
||||
plain text version.
|
||||
|
||||
If an error occured, such as non-matching keys between encryption and decryption,
|
||||
an empty string or a string containing nonsense may be returned.
|
||||
*/
|
||||
QByteArray decryptToByteArray(const QString& cyphertext) ;
|
||||
/**
|
||||
Decrypts a cyphertext binary encrypted with this class with the set key back to the
|
||||
plain text version.
|
||||
|
||||
If an error occured, such as non-matching keys between encryption and decryption,
|
||||
an empty string or a string containing nonsense may be returned.
|
||||
*/
|
||||
QString decryptToString(QByteArray cypher) ;
|
||||
/**
|
||||
Decrypts a cyphertext binary encrypted with this class with the set key back to the
|
||||
plain text version.
|
||||
|
||||
If an error occured, such as non-matching keys between encryption and decryption,
|
||||
an empty string or a string containing nonsense may be returned.
|
||||
*/
|
||||
QByteArray decryptToByteArray(QByteArray cypher) ;
|
||||
|
||||
//enum to describe options that have been used for the encryption. Currently only one, but
|
||||
//that only leaves room for future extensions like adding a cryptographic hash...
|
||||
enum CryptoFlag{CryptoFlagNone = 0,
|
||||
CryptoFlagCompression = 0x01,
|
||||
CryptoFlagChecksum = 0x02,
|
||||
CryptoFlagHash = 0x04
|
||||
};
|
||||
Q_DECLARE_FLAGS(CryptoFlags, CryptoFlag);
|
||||
private:
|
||||
|
||||
void splitKey();
|
||||
|
||||
quint64 m_key;
|
||||
QVector<char> m_keyParts;
|
||||
CompressionMode m_compressionMode;
|
||||
IntegrityProtectionMode m_protectionMode;
|
||||
Error m_lastError;
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(RMCrypt::CryptoFlags)
|
||||
#endif // #if (RM_MODEL == RM_MODEL_TYPE_TELEBIT)
|
||||
#endif // RM_CRYPT_H
|
||||
Reference in New Issue
Block a user