Files
fmviewer3/project/fm_viewer/data/an6000_decode.cpp
2026-02-21 17:11:31 +09:00

374 lines
9.8 KiB
C++

#include "an6000_decode.h"
#if (RM_MODEL == RM_MODEL_TYPE_AN6000)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
volatile unsigned long size;
volatile char type[4];
} BoxHeader_t;
typedef struct _BoxAddress_t {
fpos_t addr;
unsigned long size;
} BoxAddress_t;
/**
* @brief Convert the Byte-order(32bit) <for little-endian environment>
*
* @param[in] val target value
*
* @return convert value
*/
unsigned long convertEndian_32(unsigned long val)
{
unsigned long result = 0;
unsigned char *p1 = (unsigned char *)&val;
unsigned char *p2 = (unsigned char *)&result;
p2[0] = p1[3];
p2[1] = p1[2];
p2[2] = p1[1];
p2[3] = p1[0];
return result;
}
/**
* @brief [DEBUG] Box data analysis
*
* @param[in] fp target file pointer
* @param[in] level analysis depth
* @param[in] parentSize parent box size
*/
void BoxAnalysis(FILE *fp, int level, size_t parentSize)
{
BoxHeader_t boxHead, childBoxHead;
char typeDesc[8] = {0};
size_t readSize;
int i;
int isNotAscii;
char *pbuf = NULL;
fpos_t pos;
while (1) {
// read box header
readSize = fread(&boxHead, 1, sizeof(BoxHeader_t), fp);
if ((feof(fp) != 0) || (readSize == 0)) {
break;
}
boxHead.size = convertEndian_32(boxHead.size);
strncpy(typeDesc, (const char *)&boxHead.type[0], 4);
if (boxHead.size == 0) {
break;
}
fgetpos(fp, &pos);
printf("[%08X] ", (unsigned long)(pos - sizeof(BoxHeader_t)));
for (i = 0; i < level; i++) {
printf(" ");
}
printf("%s[%d]\n", typeDesc, boxHead.size);
if (parentSize != (size_t)-1) {
parentSize -= boxHead.size;
}
// check child box exist
readSize = fread(&childBoxHead, 1, sizeof(BoxHeader_t), fp);
childBoxHead.size = convertEndian_32(childBoxHead.size);
isNotAscii = 0;
for (i = 0; i < 4; i++) {
if ((childBoxHead.type[i] < 'a') || (childBoxHead.type[i] > 'z')) {
++isNotAscii;
break;
}
}
fseek(fp, -(long)sizeof(BoxHeader_t), SEEK_CUR);
if ((boxHead.size > childBoxHead.size) && (isNotAscii == 0)) {
// child box exist
BoxAnalysis(fp, level + 1, boxHead.size - sizeof(BoxHeader_t));
}
else {
// child box not exist
pbuf = (char *)malloc(boxHead.size - sizeof(BoxHeader_t));
fread(pbuf, 1, boxHead.size - sizeof(BoxHeader_t), fp);
free(pbuf);
}
// check of continue the child box loop
if (parentSize == 0) {
break;
}
// terminal box
if (strncmp((const char *)boxHead.type, "FWVR", 4) == 0) {
break;
}
}
if (parentSize == (size_t)-1) {
fseek(fp, 0, SEEK_SET);
}
}
/**
* @brief Get the crypt target box information
*
* @param[in] fp target file pointer
* @param[out] buf target box information
* @param[in] bufSize number of \a buf buffer
* @param[in] level analysis depth
* @param[in] parentSize parent box size
*
* @return number of available target box information
*/
static bool gFound_stsz = false;
static bool gFount_udat = false;
size_t GetCryptTarget(FILE *fp, BoxAddress_t *buf, size_t bufSize, int level, size_t parentSize)
{
size_t buf_num = 0;
BoxHeader_t boxHead = {0,};
BoxHeader_t childBoxHead = {0,};
size_t readSize = 0;
int isNotAscii = 0;
int i = 0;
//char *pbuf = NULL;
fpos_t pos = 0;
if (bufSize == 0) {
return 0;
}
while (1) {
// read box header
readSize = fread(&boxHead, 1, sizeof(BoxHeader_t), fp);
if (readSize == 0) {
break;
}
boxHead.size = convertEndian_32(boxHead.size);
if (boxHead.size == 0) {
break;
}
if (parentSize != (size_t)-1) {
parentSize -= boxHead.size;
}
// check crypt target box
if (((strncmp((const char *)boxHead.type, "stsz", 4) == 0) && (gFound_stsz == false) )
|| (strncmp((const char *)boxHead.type, "udat", 4) == 0) && (gFount_udat == false)){
fgetpos(fp, &pos);
buf[buf_num].addr = pos - sizeof(BoxHeader_t);
buf[buf_num].size = boxHead.size;
fseek(fp, boxHead.size - sizeof(BoxHeader_t), SEEK_CUR);
if(strncmp((const char *)boxHead.type, "stsz", 4) == 0)
{
gFound_stsz = true;
}
else if(strncmp((const char *)boxHead.type, "udat", 4) == 0)
{
gFount_udat = true;
}
if (++buf_num == bufSize) {
return buf_num;
}
}
else {
// Existence check of child box
readSize = fread(&childBoxHead, 1, sizeof(BoxHeader_t), fp);
fseek(fp, -(long)sizeof(BoxHeader_t), SEEK_CUR);
childBoxHead.size = convertEndian_32(childBoxHead.size);
isNotAscii = 0;
for (i = 0; i < 4; i++) {
if ((childBoxHead.type[i] < 'a') || (childBoxHead.type[i] > 'z')) {
++isNotAscii;
break;
}
}
if ((boxHead.size > childBoxHead.size) && (isNotAscii == 0)) {
// child box is exist
buf_num += GetCryptTarget(fp, &buf[buf_num], bufSize - buf_num, level + 1, boxHead.size - sizeof(BoxHeader_t));
if (buf_num == bufSize) {
return buf_num;
}
}
else {
// child box is not exist
fseek(fp, boxHead.size - sizeof(BoxHeader_t), SEEK_CUR);
}
}
// check of continue the child box loop
if (parentSize == 0) {
break;
}
// terminal box
if (strncmp((const char *)boxHead.type, "FWVR", 4) == 0) {
break;
}
}
return buf_num;
}
/**
* @brief Encrypt MP4 File
*
* @param[in] filename target file name
*
* @retval 0 successful
* @retval non-zero failed
*/
int encrypt_an6000(const wchar_t *filename)
{
FILE *fp = NULL;
BoxAddress_t tgtInfo[8];
size_t infoSize, i, x;
char *pbuf;
char key = 0x19;
char preData, enc;
memset(tgtInfo, 0, sizeof(tgtInfo));
infoSize = sizeof(tgtInfo) / sizeof(BoxAddress_t);
fp = _wfopen(filename,L"r+b");
//fp = fopen(filename, "r+b");
if (fp == NULL) {
return -1;
}
fseek(fp, 0, SEEK_SET);
// Analysis box information
//BoxAnalysis(fp, 0, (size_t)-1);
infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1);
for (i = 0; i < infoSize; i++) {
pbuf = (char*)malloc(tgtInfo[i].size);
// read the target data
fsetpos(fp, &tgtInfo[i].addr);
fread(pbuf, 1, tgtInfo[i].size, fp);
// data encrypt
preData = 0;
for (x = 8; x < tgtInfo[i].size; x++) {
enc = ((~pbuf[x]) ^ preData) ^ key;
preData = pbuf[x];
pbuf[x] = enc;
}
// over-write the target data
fsetpos(fp, &tgtInfo[i].addr);
fwrite(pbuf, 1, tgtInfo[i].size, fp);
free(pbuf);
}
fclose(fp);
return 0;
}
/**
* @brief Decrypt MP4 File
*
* @param[in] filename target file name
*
* @retval 0 successful
* @retval non-zero failed
*/
int decrypt_an6000(const wchar_t *filename)
{
gFound_stsz = false;
gFount_udat = false;
FILE *fp = NULL;
BoxAddress_t tgtInfo[8] = {0,};
size_t infoSize, i, x;
char *pbuf = NULL;
char key = 0x19;
char preData = 0;
memset(tgtInfo, 0, sizeof(_BoxAddress_t) * 8);
infoSize = sizeof(tgtInfo) / sizeof(_BoxAddress_t);
// filePathCH2.toStdWString().c_str()
fp = _wfopen(filename,L"r+b");
//fp = fopen(filename, "r+b");
if (fp == NULL) {
return -1;
}
fseek(fp, 0, SEEK_SET);
// Analysis box information
infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1);
for (i = 0; i < infoSize; i++) {
pbuf = (char*)malloc(tgtInfo[i].size);
// read the target data
fsetpos(fp, &tgtInfo[i].addr);
fread(pbuf, 1, tgtInfo[i].size, fp);
// data decrypt
preData = 0;
for (x = 8; x < tgtInfo[i].size; x++) {
pbuf[x] = ~((pbuf[x] ^ key) ^ preData);
preData = pbuf[x];
}
// over-write the target data
fsetpos(fp, &tgtInfo[i].addr);
fwrite(pbuf, 1, tgtInfo[i].size, fp);
free(pbuf);
}
fclose(fp);
return 0;
}
bool is_encrypted_an6000(const wchar_t *filename)
{
gFound_stsz = false;
gFount_udat = false;
FILE *fp = NULL;
BoxAddress_t tgtInfo[8] = {0,};
size_t infoSize, i, x;
memset(tgtInfo, 0, sizeof(_BoxAddress_t) * 8);
infoSize = sizeof(tgtInfo) / sizeof(_BoxAddress_t);
fp = _wfopen(filename,L"r+b");
if (fp == NULL) {
return false;
}
fseek(fp, 0, SEEK_SET);
infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1);
char buffer[16] = {0,};
for (i = 0; i < infoSize; i++) {
// read the target data
tgtInfo[i].addr += 4;
fsetpos(fp, &tgtInfo[i].addr);
fread(buffer, 1, 16, fp);
if(buffer[0] == 's' && buffer[1] =='t' && buffer[2] =='s' && buffer[3] =='z') {
bool enc = (buffer[4] != 0 || buffer[5] != 0 || buffer[6] != 0 || buffer[7] != 0);
fclose(fp);
return enc;//(buffer[4] != 0 || buffer[5] != 0 || buffer[6] != 0 || buffer[7] != 0);
}
//printf("%c:%c:%c:%c\n",buffer[0],buffer[1],buffer[2],buffer[3]);
//printf("%02X:%02X:%02X:%02X %02X:%02X:%02X:%02X\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7]);
}
fclose(fp);
return true;
}
#endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)