#include <stdio.h>
#include <string.h> // strncpy
#include <stdlib.h> //exit
#include <ctype.h> // isspace
#include <stdint.h> // uint32_t
#include <math.h> // round
#include <string> //std::string
#include <vector> //std::vector
//#define BUF_SIZE 15 // 512 bype
//#define BUF_SIZE 512 // 512 bype
//#define BUF_SIZE 1024 // 1KB
//#define BUF_SIZE 1024 * 1024 // 1MB
#define BUF_SIZE 1024 * 1024 * 8 // 8MB
//#define BUF_SIZE 1024 * 1024 *16 // 16MB
#define LINE_SIZE 1024 * 2
#define NAME_SIZE 128
//#define IS_PRINT true
#define IS_PRINT false
#define READ_MODE 0 // 0=fread only, 1=read_data()関数のみ, それ以上=read_data() & 解析
typedef enum __TYPE {
TYPE_x,
TYPE_y
} TYPE;
//--------------------------------------------------------------------------------
typedef struct __tag_qq_db {
char qq_name[NAME_SIZE];
} t_qq_db;
typedef struct __tag_elem_db {
TYPE type;
unsigned int no;
unsigned int num_line_count;
t_qq_db qq_db;
std::vector<double> numbers;
} t_elem_db;
typedef struct __tag_section_db {
char name[NAME_SIZE];
unsigned int num_1;
unsigned int num_2;
unsigned int text_line_count;
std::vector<std::string> texts;
} t_section_db;
typedef struct __tag_read_db {
char header_name[NAME_SIZE];
unsigned int mag;
} t_read_db;
//--------------------------------------------------------------------------------
struct CCC {
FILE *fp;
unsigned char real_data[BUF_SIZE+1];
unsigned char* data;
unsigned char* temp_data;
t_section_db* p_current_section_db;
t_elem_db* p_current_elem_db;
t_read_db read_db;
bool initialize();
bool read(char* file_path);
size_t read_data();
bool get_header();
bool get_section_name();
bool get_section_index();
bool get_text();
bool get_elem_index();
bool get_elem_qq();
bool get_elem_x(unsigned int i);
bool get_elem_y(unsigned int i);
};
//--------------------------------------------------------------------------------
bool CCC::initialize(){
real_data[BUF_SIZE] = '\x00'; //最後はかならずNULLになるようにセット
data = real_data;
return true;
}
size_t CCC::read_data(){
size_t size = 0;
if( *data == '\x00' ){
size = fread( &real_data, sizeof(real_data[0]), BUF_SIZE, fp);
data = real_data;
// 終端処理。最大値で取得されてなければそこを末尾にする
if( size != BUF_SIZE ) data[size] = '\x00';
// 取得bufの最後尾が改行でなければfpを改行まで戻す
if( data[size-1] != '\x0a' ){
int newline_index = -2;
for(; data[size+newline_index] != '\x0a'; --newline_index);
fseek(fp,newline_index+1,SEEK_CUR);
// bufの最後の改行の次にx00(null)を入れてそれ以降をカット
data[size+newline_index+1] = '\x00';
}
}
return size;
}
// 32=空白
// 0a=改行
// 00=null
bool CCC::get_section_name(){
read_data();
temp_data = data;
for(; *++data != '\x0a'; );
memcpy(p_current_section_db->name, temp_data, data-temp_data);
p_current_section_db->name[data-temp_data] = '\x00';
++data;
IS_PRINT == true && printf("%s\n", p_current_section_db->name);
return true;
}
bool CCC::get_section_index(){
read_data();
t_section_db section_db;
//数値グループ数を取得
auto func1 = [&](unsigned int* num) {
unsigned int n = 0;
do {
unsigned char ch = (unsigned char)(*data++ - '0');
if (ch <= 9) {
n = n * 10 + ch;
} else {
break;
}
} while (true);
*num = n;
};
func1(&p_current_section_db->num_1);
func1(&p_current_section_db->num_2);
func1(&p_current_section_db->text_line_count);
if( p_current_section_db->num_1 != p_current_section_db->num_2 ){
printf("num_1, num_2の数が違う!!解析する!! %d %d\n", p_current_section_db->num_1, p_current_section_db->num_2);
printf("%s\n", data);
exit(1);
}
if( IS_PRINT == false ){
// 日付を捨てる
for(; *data++ != '\x0a'; );
}else{
printf("%d %d %d ", p_current_section_db->num_1, p_current_section_db->num_2, p_current_section_db->text_line_count);
printf("%c", data[0]);
for(; *data++ != '\x0a'; ){
printf("%c", data[0]);
}
}
return true;
}
bool CCC::get_text(){
read_data();
temp_data = data;
for(; *++data != '\x0a'; );
char line[LINE_SIZE];
memcpy(line, temp_data, data-temp_data);
line[data-temp_data] = '\x00';
IS_PRINT == true && printf("%s\n", line);
++data;
return true;
}
bool CCC::get_elem_index(){
read_data();
//数値グループ数を取得
auto func1 = [&](unsigned int* num) {
unsigned int n = 0;
do {
unsigned char ch = (unsigned char)(*data++ - '0');
if (ch <= 9) {
n = n * 10 + ch;
} else {
break;
}
} while (true);
*num = n;
};
// 数値グループ取得開始
// 78=x, 79=y
if( *data == '\x78' ){
p_current_elem_db->type = TYPE_x;
}else if ( *data == '\x79' ){
p_current_elem_db->type = TYPE_y;
}else{
printf("## ERROR 102 ##\n");
printf("%s\n", data);
exit(1);
}
data+=2;
func1(&p_current_elem_db->no);
func1(&p_current_elem_db->num_line_count);
IS_PRINT == true && printf("%c %d %d\n", p_current_elem_db->type == TYPE_x ? 'x' : 'y', p_current_elem_db->no, p_current_elem_db->num_line_count);
return true;
}
bool CCC::get_elem_qq(){
read_data();
// 51=Q,
if( *data == '\x51' ){
// テストなのでとりあえずQQ行はスキップ
if( IS_PRINT == false ){
for(; *data++ != '\x0a'; );
}else{
printf("%c", data[0]);
for(; *data++ != '\x0a'; ){
printf("%c", data[0]);
}
}
}else if( *data == '\x2d' || *data == '\x30' || *data == '\x31' || *data == '\x32' || *data == '\x33' || *data == '\x34' || *data == '\x35' || *data == '\x36' || *data == '\x37' || *data == '\x38' || *data == '\x39' || *data == '\x00'){
// 2d=マイナス記号(-), 30~39=数字, 00=NULL, の時はスルー
}else{
printf("????\n");
printf("%02x\n", *data);
exit(1);
}
return true;
}
bool CCC::get_elem_x(unsigned int i){
read_data();
//係数掛けで数値取得
// auto func2 = [&](double* num) {
auto func2 = [&](unsigned int i) {
uint64_t n = 0;
bool is_minus = false;
do {
// 2d=マイナス記号(-)
if( *data == '\x2d' ){
++data;
is_minus = true;
}
unsigned char ch = (unsigned char)(*data++ - '0');
if (ch <= 9) {
n = n * 10 + ch;
} else {
break;
}
} while (true);
double num;
if( is_minus == false ){
num = (double)n / (double)read_db.mag;
}else{
num = -(double)n / (double)read_db.mag;
}
IS_PRINT == true && printf("%ld", lround(num*read_db.mag));
};
func2(i); IS_PRINT == true && printf(" ");
func2(i+1); IS_PRINT == true && printf(" ");
func2(i+2); IS_PRINT == true && printf(" ");
func2(i+3); IS_PRINT == true && printf("\n");
return true;
}
bool CCC::get_elem_y(unsigned int i){
read_data();
//係数掛けで数値取得
// auto func2 = [&](double* num) {
auto func2 = [&](unsigned int i) {
uint64_t n = 0;
bool is_minus = false;
do {
// 2d=マイナス記号(-)
if( *data == '\x2d' ){
++data;
is_minus = true;
}
unsigned char ch = (unsigned char)(*data++ - '0');
if (ch <= 9) {
n = n * 10 + ch;
} else {
break;
}
} while (true);
double num;
if( is_minus == false ){
num = (double)n / (double)read_db.mag;
}else{
num = -(double)n / (double)read_db.mag;
}
IS_PRINT == true && printf("%ld", lround(num*read_db.mag));
};
func2(i); IS_PRINT == true && printf(" ");
func2(i+1); IS_PRINT == true && printf("\n");
return true;
}
bool CCC::read(char file_path[]){
if((fp=fopen(file_path, "rb"))==NULL){
printf("ファイルを開けません。%s",file_path);
return 0;
}
// テスト用。
if( READ_MODE == 0 ){
// freadだけだとどれくらいの速度?
size_t size;
do{
if((size = fread( data, sizeof(data[0]), BUF_SIZE, fp)) == 0){
break;
}
if( size != BUF_SIZE ) data[size] = '\x00';
IS_PRINT == true && printf("%s", data);
} while(size == BUF_SIZE);
return true;
}else if( READ_MODE == 1 ){
// read_data()だけだとどれくらいの速度?
while( true ){
size_t size = read_data();
IS_PRINT == true && printf("%s", data);
for(; *++data != '\x00'; );
if( feof( fp ) && *data == '\x00' ) { break; }
}
return true;
}
// ファイルコピー
while( true ){
t_section_db section_db;
p_current_section_db = §ion_db;
get_section_name();
get_section_index();
for(unsigned int i=0; i<p_current_section_db->text_line_count; ++i){
get_text();
}
for(unsigned int i=0; i<p_current_section_db->num_1; ++i){
t_elem_db elem_db;
p_current_elem_db = &elem_db;
get_elem_index();
get_elem_qq();
switch( p_current_elem_db->type ){
case TYPE_x:
// 要素数を最初に広げる
p_current_elem_db->numbers.resize(p_current_elem_db->num_line_count*4);
for(unsigned int i=0; i<p_current_elem_db->num_line_count; ++i){
get_elem_x(i);
}
break;
case TYPE_y:
p_current_elem_db->numbers.resize(p_current_elem_db->num_line_count*2);
for(unsigned int i=0; i<p_current_elem_db->num_line_count; ++i){
get_elem_y(i);
}
break;
default:
printf("## ERROR 101 ##\n");
printf("%s\n", data);
exit(1);
}
}
if( feof( fp ) && *data == '\x00' ) { break; }
}
fclose( fp );
return 0;
}
int main(void){
char file_path[] = "./aaa_13gb";
CCC ccc;
ccc.initialize();
ccc.read(file_path);
return 0;
}