# HW03 參考答案
## 3.1 Bible
Credit: 41247039S 韓O劭 (modified)
:::spoiler hw0301.c
```c=
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
int32_t inputString(char *str) {
if (fgets(str, F_SIZE, stdin) == NULL) {
if (fgetc(stdin) == EOF) {
printf("myfile: EOF detected\n");
} else {
perror("myfile: input error");
}
return 1;
}
if (str[strlen(str) - 1] == '\n') {
str[strlen(str) - 1] = '\0';
}
return 0;
}
int32_t openFile(FILE **file, char *fileName, char *mode) {
*file = fopen(fileName, mode);
if (*file == NULL) {
char err[F_SIZE] = {0};
snprintf(err, F_SIZE, "myfile: '%s' error", fileName);
perror(err);
return 1;
}
return 0;
}
void closeFile(FILE *file) {
if (file == NULL) {
return;
}
fclose(file);
}
int32_t searchText(FILE *file, char *search) {
if (file == NULL || search == NULL) {
printf("mybible: Error input\n");
return 1;
}
Bible bible = {NULL, 0};
BibleText temp = { 0, 0, {0}, {0} };
while (readBibleText(file, &temp) == 0) {
if (hasSearchText(temp.text, search)) {
addBibleText(&bible, &temp);
}
}
printBibleText(&bible);
freeBible(&bible);
return 0;
}
int32_t readBibleText(FILE *file, BibleText *text) {
if (feof(file)) {
return 0;
}
text->chapter = 0;
text->verse = 0;
text->text[0] = 0;
text->id[0] = 0;
char format[] = "{\"chapter\":%d,\"verse\":%d,\"text\":\"%[^\"]\",\"translation_id\":\"%*[^\"]\",\"book_id\":\"%[^\"]\",\"book_name\":\"%*[^\"]\"}";
int32_t fs = fscanf(file, format, &(text->chapter), &(text->verse), &(text->text), &(text->id));
if (fs != 4) {
return 1;
}
fgetc(file);
return 0;
}
int32_t addBibleText(Bible *bible, BibleText *text) {
int32_t idx = bible->size;
bible->size++;
if (idx == 0) {
bible->text = (BibleText *) calloc(bible->size, sizeof(BibleText));
} else {
bible->text = (BibleText *) reallocarray(bible->text, bible->size, sizeof(BibleText));
}
bible->text[idx].verse = text->verse;
bible->text[idx].chapter = text->chapter;
strcpy(bible->text[idx].text, text->text);
strcpy(bible->text[idx].id, text->id);
return 1;
}
bool hasSearchText(char *text, char *search) {
size_t i = 0;
while (i < strlen(text)) {
if (!isSameChar(text[i], search[0])) {
i++;
continue;
}
size_t k = 0;
while (k < strlen(search)) {
if (i + k >= strlen(text) || !isSameChar(text[i+k], search[k])) {
break;
}
k++;
}
if (k == strlen(search)) {
return true;
}
i += k;
}
return false;
}
bool isSameChar(char a, char b) {
if (a >= 'A' && a <= 'Z') {
a += 'a' - 'A';
}
if (b >= 'A' && b <= 'Z') {
b += 'a' - 'A';
}
return (a == b);
}
void printBibleText(Bible *bible) {
printf("Found %d time(s)\n", bible->size);
if (bible->size == 0) {
return;
}
for (int32_t i = 0; i < bible->size; i++) {
BibleText *tmp = &(bible->text[i]);
printf("%d. %s %d:%d %s\n", i+1, tmp->id, tmp->chapter, tmp->verse, tmp->text);
}
}
void freeBible(Bible *bible) {
if (bible->size == 0) {
return;
}
free(bible->text);
bible->text = NULL;
return;
}
int main() {
FILE *file = NULL;
char fileName[] = "bible.txt";
char search[F_SIZE] = {0};
if (openFile(&file, fileName, "r")) {
return 1;
}
printf("Please enter the search target: ");
if (inputString(search)) {
return 1;
}
if (searchText(file, search)) {
printf("Search text error\n");
return 1;
}
return 0;
}
```
:::
## 3.2 Function Tracer
Credit: 41247027S 陳O羽
:::spoiler hw0302.c
```c=
#include <stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<getopt.h>
#include<unistd.h>
#include<string.h>
struct option long_option[] = {
{"help",0,NULL,'h'},
{"include",1,NULL,'i'},
{"function",1,NULL,'f'},
{"linum",0,NULL,'l'},
{"code",0,NULL,'c'},
{0,0,0,0}
};
typedef struct{
int32_t line;
char text[1000];
}FuncPos;
int32_t checktype(char *str){
if(strstr(str,"size_t")!=NULL||strstr(str,"void")!=NULL||strstr(str,"int")!=NULL||strstr(str,"short")!=NULL||strstr(str,"long")!=NULL||strstr(str,"float")!=NULL||strstr(str,"double")!=NULL||strstr(str,"char")!=NULL)
return 1;
else
return 0;
}
int32_t checkchar(char *str){
if((*str == '_'||(*str>='a'&&*str<='z')||(*str>='A'&&*str<='Z')||(*str>='0'&&*str<='9')))
return 1;
else
return 0;
}
int32_t FindPositionOfStr(char *str,char word){
for(int32_t i=0;str[i]!='\0';i++){
if(str[i] == word)
return i;
}
}
int32_t FindFunc(char *func,FILE* pFile,FuncPos funcPos[]){
int32_t line = 0,cnt=0,anno_status=0;
char str[1000];
while(!feof(pFile)){
line++;
fgets(str,1000,pFile);
char *tmp,*anno;
if((anno = strstr(str,"*/"))!=NULL){
if((tmp = strstr(str,func))!=NULL){
if(strlen(tmp)<strlen(anno)){
tmp--;
if(!checkchar(tmp)){
tmp += strlen(func) +1;
if(!checkchar(tmp)){
funcPos[cnt].line = line;
strcpy(funcPos[cnt].text,str);
cnt++;
}
}
}
}
anno_status =0;
continue;
}
if(anno_status==1)
continue;
if((anno = strstr(str,"//"))!=NULL){
if((tmp = strstr(str,func))!=NULL){
if(strlen(tmp)>strlen(anno)){
tmp--;
if(!checkchar(tmp)){
tmp += strlen(func) +1;
if(!checkchar(tmp)){
funcPos[cnt].line = line;
strcpy(funcPos[cnt].text,str);
cnt++;
}
}
}
}
}
else if((anno = strstr(str,"/*"))!=NULL){
if((tmp = strstr(str,func))!=NULL){
if(strlen(tmp)>strlen(anno)){
tmp--;
if(!checkchar(tmp)){
tmp += strlen(func) +1;
if(!checkchar(tmp)){
funcPos[cnt].line = line;
strcpy(funcPos[cnt].text,str);
cnt++;
}
}
}
}
anno_status =1;
}
else if((tmp = strstr(str,func))!=NULL){
tmp--;
if(!checkchar(tmp)){
tmp += strlen(func) +1;
if(!checkchar(tmp)){
funcPos[cnt].line = line;
strcpy(funcPos[cnt].text,str);
cnt++;
}
}
}
}
return cnt;
}
int main(int argc, char *argv[]){
int32_t func=0,include=0;
for(int i=1;i<argc;i++){
if((strcmp(argv[i],"-f")==0&&strstr(argv[i],"-f")!=NULL)||(strcmp(argv[i],"--function")==0&&strstr(argv[i],"--function")!=NULL))
func = 1;
else if((strcmp(argv[i],"-i")==0&&strstr(argv[i],"-i")!=NULL)||(strcmp(argv[i],"--include")==0&&strstr(argv[i],"--include")!=NULL))
include = 1;
}
if(func&&include){
printf("Wrong input!\n");
return 0;
}
int32_t option=0,opt_i=0,opt_f=0,opt_h=0,opt_l=0,opt_c=0,index=1;
char header[100],function[100];
while((option = getopt_long(argc,argv,"i:f:hlc",long_option,NULL))!=-1){
if(option == 'i'){
opt_i = 1;
strcpy(header,optarg);
if(!strstr(argv[index],optarg))
index++;
if(*(argv[index+1])!='-'){
int32_t check=0;
for(int i=index+1;i<argc;i++){
if(*(argv[i])=='-')
check=1;
}
if(check){
printf("Wrong Input!\n");
return 0;
}
}
}
else if(option == 'f'){
opt_f = 1;
strcpy(function,optarg);
if(!strstr(argv[index],optarg))
index++;
if(*(argv[index+1])!='-'){
int32_t check=0;
for(int i=index+1;i<argc;i++){
if(*(argv[i])=='-')
check=1;
}
if(check){
printf("Wrong Input!\n");
return 0;
}
}
}
else if(option == 'h'){
if(*(argv[index+1])!='-'){
int32_t check=0;
for(int i=index+1;i<argc;i++){
if(*(argv[i])=='-')
check=1;
}
if(check){
printf("Wrong Input!\n");
return 0;
}
}
opt_h=1;
}
else if(option == 'l'){
if(*(argv[index+1])!='-'){
int32_t check=0;
for(int i=index+1;i<argc;i++){
if(*(argv[i])=='-')
check=1;
}
if(check){
printf("Wrong Input!\n");
return 0;
}
}
opt_l=1;
}
else if(option == 'c'){
if(*(argv[index+1])!='-'){
int32_t check=0;
for(int i=index+1;i<argc;i++){
if(*(argv[i])=='-')
check=1;
}
if(check){
printf("Wrong Input!\n");
return 0;
}
}
opt_c=1;
}
else if(option == '?'){
printf("Unknown option: %c\n", optopt);
return 0;
}
index++;
}
if(opt_h){
printf("Usage: hw0302 [options] ... [files] ...\n -f, --function=func Trace the func usage in [Files].\n -i, --include=File Trace all functions listed in the header file in [\n Files].\n -l, --linum Display the line number.\n -c, --code Display the code.\n -h, --help Display this information and exit.\n\n-F and -I are exclusive and must be at least one.\n");
return 0;
}
else if(opt_f==0&&opt_i==0){
printf("Wrong input!\n");
return 0;
}
if(opt_f){
printf("%s:\n",function);
while(index<argc){
FuncPos funcPos[1000];
int32_t line = 0,cnt=0;
char cfile[100];
FILE *cFile;
strcpy(cfile,argv[index]);
if((cFile = fopen(cfile,"rw"))==NULL){
perror("Could not open the file");
index++;
continue;
}
cnt = FindFunc(function,cFile,funcPos);
printf(" %s (count: %d)\n",cfile,cnt);
if(opt_l&&opt_c){
for(int32_t i=0;i<cnt;i++)
printf(" line %d: %s",funcPos[i].line,funcPos[i].text);
}
else if(opt_l){
for(int32_t i=0;i<cnt;i++)
printf(" line %d\n",funcPos[i].line);
}
else if(opt_c){
for(int32_t i=0;i<cnt;i++)
printf("%s",funcPos[i].text);
}
index++;
fclose(cFile);
}
}
else if(opt_i){
FILE *hFile,*cFile;
if((hFile = fopen(header,"rw"))==NULL){
perror("Could not open the file");
return 0;
}
char cfile[100],str[1000];
while(!feof(hFile)){
FuncPos funcPos[1000];
int32_t cnt =0;
fgets(str,1000,hFile);
if(checktype(str)){
char *tmp;
if((tmp = strstr(str,"("))!=NULL){
while(!checkchar(tmp))
tmp--;
int32_t leng=0;
while(checkchar(tmp)){
leng++;
tmp--;
}
char *funcName;
funcName = calloc(leng+1,sizeof(char));
funcName[leng] = '\0';
tmp++;
for(int i=0;i<leng;i++,tmp++)
funcName[i] = *tmp;
printf("%s:\n",funcName);
for(int32_t i=index;i<argc;i++){
strcpy(cfile,argv[i]);
if((cFile = fopen(cfile,"rw"))==NULL){
perror("Could not open the file");
continue;
}
cFile = fopen(cfile,"rw");
cnt = FindFunc(funcName,cFile,funcPos);
printf(" %s (count: %d)\n",cfile,cnt);
if(opt_l&&opt_c){
for(int32_t i=0;i<cnt;i++)
printf(" line %d:%s",funcPos[i].line,funcPos[i].text);
}
else if(opt_l){
for(int32_t i=0;i<cnt;i++)
printf(" line %d\n",funcPos[i].line);
}
else if(opt_c){
for(int32_t i=0;i<cnt;i++)
printf("%s",funcPos[i].text);
}
fclose(cFile);
}
}
}
}
}
return 0;
}
```
## 3.3 Image Steganography
## 3.4 Game Cheater
:::spoiler 41171216H 石O軒
```c=
#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
struct Item {
uint8_t status; // 狀態值,40=裝備中、00=持有中、80=無物品
uint8_t itemId; // 物品編號
};
//總共有80byte
typedef struct _Character {
uint8_t XX; // X座標
uint8_t YY; // Y座標
uint8_t Z1; // 人物圖形
uint8_t Z2; // 人物圖形方向
uint8_t Z3; // 人物圖形跑步動作
uint8_t AA; // 動作狀態
uint8_t BB; // 陣營
uint8_t FA; // 肖像編號
uint16_t NN; // 人物姓名,假設名字最長不超過15個字符
struct Item IT[8]; // 物品列表
uint8_t magic[5]; // 法術列表
uint8_t RA; // 種族編號
uint8_t CL; // 職業編號
uint8_t LV; // 等級
uint8_t A_plus; // AP增強狀態
uint8_t D_plus; // DP增強狀態
uint8_t H_plus; // HIT/EV增強狀態
uint8_t sub_H; // 中毒狀態
uint8_t XA; // 麻痺狀態
uint8_t XM; // 封咒狀態
uint8_t space_1[15]; //空15格
uint16_t MT; // 力量
uint16_t DF; // 耐力
uint8_t MV; // 移動力
uint8_t EX; // 經驗值
uint8_t space_2; //空1格
uint16_t DX; // 速度
uint16_t H1; // 目前生命值
uint16_t H2; // 最大生命值
uint16_t M1; // 目前法力值
uint16_t M2; // 最大法力值
uint16_t AP; // 目前總攻擊力
uint16_t DP; // 目前總防禦力
uint16_t HT; // 命中率
uint16_t EV; // 閃避率
}__attribute__ ((__packed__)) character;
//印出角色
void print_character(int32_t character_id);
//印出道具
int32_t print_item(int32_t item_id);
//印出可改數值
void print_change();
//清空螢幕
void clearScreen(){
printf("\033[2J\033[1;1H");
}
int main(int argc,char *argv[]){
//如果只有輸入1個 就顯示使用方式
if(argc==1){
printf("Usage: sudo ./hw0304 pid addr\n");
return 0;
}
//ps aux | grep dosbox 可以抓pid
//home/seanshih/hw3/dosgame/fd2
//把pid address存下來
uint64_t address;
if(argc==3){
int32_t pid=-1;
sscanf(argv[1],"%d",&pid);
if(pid==-1){
printf("error: wrong pid.\n");
return 0;
}
address=strtoull(argv[2],NULL,16);
}
else{
printf("Usage: sudo ./hw0304 pid addr\n");
return 0;
}
//先抓檔案名稱
char fileName[1000]={0};
strcpy(fileName,"/proc/");
strcat(fileName,argv[1]);
strcat(fileName,"/mem");
//printf("%s\n",fileName);
//printf("%ld\n",address);
printf("資料讀取中....");
//////重要線索 角色前面int32_t=7685
///fopen
//開啟檔案
FILE *pfile=NULL;
if((pfile=fopen(fileName,"rb+"))==NULL){
printf("file is not open!\n");
return 0;
}
while(1){
//設定檔案大小
uint64_t file_size=16*1024*1024;
//創一個角色列表
int32_t character_list[100];
//初始化
for(int32_t i=0;i<100;i++){
character_list[i]=-1;
}
//有幾個角色
int32_t all_character_size=0;
//開始抓位置
uint64_t start;
int32_t search_id=7685;
int32_t search;
FILE *now_pos=pfile;
for(uint64_t i=0;i<file_size;i++){
//搜尋到最後了
if(i+79>=file_size){
break;
}
fseek(now_pos,address+i,SEEK_SET);
fread(&search,sizeof(int32_t),1,now_pos);
if(search==search_id){
start=i+address+4;
//開始把角色抓下來
while(1){
character temp;
fread(&temp,sizeof(character),1,now_pos);
//printf("(%d,%d)\n",temp.XX,temp.YY);
//printf("BB=%d\n",temp.BB);
//如果是敵方就不抓角色
if(temp.BB==1 || temp.BB==2){
character_list[all_character_size]=temp.FA;
all_character_size++;
}
else{
break;
}
}
break;
}
}
if(all_character_size==0){
clearScreen();
printf("現在沒有可更改角色!\n");
break;
}
/////開始改狀態/////
char clear;
//開始界面
clearScreen();
printf("歡迎來到炎龍騎士團2 修改器!\n");
//選擇角色
int32_t choose_character=-1;
int32_t end=0;
printf("下面是可選擇的角色:\n");
for(int32_t j=0;j<20;j++){
int32_t check_in_i=0;
for(int32_t i=0;i<all_character_size;i++){
if(i*20+j>=all_character_size){
break;
}
check_in_i=1;
printf("%2d.",i*20+j+1);
print_character(character_list[i*20+j]);
}
if(check_in_i==0){
break;
}
printf("\n");
}
printf("請輸入要改的角色編號,如要結束請輸入0: ");
scanf("%d",&choose_character);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新選
if(choose_character<0 || choose_character>all_character_size){
printf("沒有這個角色!\n");
continue;
}
//如果是0就結束
if(choose_character==0){
break;
}
//開始改資料
while(1){
//讀取角色資料 //刷新
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
character now_character;
fread(&now_character,sizeof(character),1,now_pos);
//printf("(%d,%d)\n",now_character.XX,now_character.YY);
int32_t choose_change;
//選擇要改什麼資料
printf("下面是可改變的數值:\n");
print_change();
printf("請選擇要改的數值(1-8),如要結束請輸入0,如要重新選擇角色請輸入-1: ");
scanf("%d",&choose_change);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重選
if(choose_change<-1 || choose_change>8){
printf("沒有這個選項!\n");
continue;
}
//如果是0就結束
if(choose_change==0){
end=1;
break;
}
//如果是-1就回上頁
if(choose_change==-1){
clearScreen();
printf("資料讀取中....");
break;
}
//開始處理資料
//HP
if(choose_change==1){
while(1){
int32_t now_HP;
printf("請輸入HP要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_HP);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_HP<-1 || now_HP>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_HP==-1){
clearScreen();
break;
}
//改H1
now_character.H1=now_HP;
//改H2
now_character.H2=now_HP;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//MP
if(choose_change==2){
while(1){
int32_t now_MP;
printf("請輸入MP要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_MP);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_MP<-1 || now_MP>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_MP==-1){
clearScreen();
break;
}
//改M1
now_character.M1=now_MP;
//改M2
now_character.M2=now_MP;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//MT
if(choose_change==3){
while(1){
int32_t now_MT;
printf("請輸入MT要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_MT);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_MT<-1 || now_MT>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_MT==-1){
clearScreen();
break;
}
//改MT
now_character.MT=now_MT;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//DF
if(choose_change==4){
while(1){
int32_t now_DF;
printf("請輸入DF要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_DF);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_DF<-1 || now_DF>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_DF==-1){
clearScreen();
break;
}
//改DF
now_character.DF=now_DF;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//MV
if(choose_change==5){
while(1){
int32_t now_MV;
printf("請輸入MV要改成多少(0-255)(最好25以內),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_MV);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_MV<-1 || now_MV>255){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_MV==-1){
clearScreen();
break;
}
//改MV
now_character.MV=now_MV;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//EX
if(choose_change==6){
while(1){
int32_t now_EX;
printf("請輸入EX要改成多少(0-255),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_EX);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_EX<-1 || now_EX>255){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_EX==-1){
clearScreen();
break;
}
//改EX
now_character.EX=now_EX;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//DX
if(choose_change==7){
while(1){
int32_t now_DX;
printf("請輸入DX要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_DX);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_DX<-1 || now_DX>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_DX==-1){
clearScreen();
break;
}
//改DX
now_character.DX=now_DX;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//道具
if(choose_change==8){
int32_t change_page=1;
while(1){
//秀出道具 //先選道具
printf("第%d頁\n",change_page);
for(int32_t j=0;j<15;j++){
int32_t check_in_i=0;
for(int32_t i=0;i<60;i++){
if(i*15+j+60*(change_page-1)>=60*change_page){
break;
}
printf("%3d.",i*15+j+60*(change_page-1));
check_in_i=print_item(i*15+j+60*(change_page-1));
if(check_in_i==0){
printf("\033[0;31m無\033[m ");
}
}
printf("\n");
}
int32_t now_item;
printf("請輸入要替換的物品編號,上一頁請輸入-3 ,下一頁請輸入-2,如要重新選擇數值請輸入-1: ");
scanf("%d",&now_item);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//回上頁
if(now_item==-3){
if(change_page==1){
clearScreen();
printf("沒有上一頁了!\n");
}
else{
clearScreen();
change_page--;
}
continue;
}
//下一頁
if(now_item==-2){
if(change_page==4){
clearScreen();
printf("沒有下一頁了!\n");
}
else{
clearScreen();
change_page++;
}
continue;
}
//如果是-1就回上頁
if(now_item==-1){
clearScreen();
break;
}
//如果輸出錯誤就重新輸入
if((now_item<-3 || now_item>214) || (now_item>=108 && now_item<=122) || (now_item>=125 && now_item<=126) ){
printf("輸入沒有代表物品或指令!\n");
continue;
}
//要換哪一格
while(1){
int32_t which;
printf("你要將\" ");
print_item(now_item);
printf("\"替換成哪一格呢?\n");
printf("現在背包狀態:\n");
for(int32_t j=0;j<8;j++){
if(now_character.IT[j].status==128){
printf("%d.\033[0;31m無\033[m\n",j+1);
}
else{
printf("%d.",j+1);
print_item(now_character.IT[j].itemId);
printf("\n");
}
}
printf("請輸入要替換的背包位置編號,如要重新選擇物品請輸入-1: ");
scanf("%d",&which);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果是-1就回上頁
if(which==-1){
clearScreen();
break;
}
//如果輸出錯誤就重新輸入
if(which<1 || which>8){
printf("沒有這一格!\n");
continue;
}
now_character.IT[which-1].status=0;
now_character.IT[which-1].itemId=now_item;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
break;
}
printf("已儲存更改!\n");
break;
}
}
}
if(end==1){
break;
}
}
//結束
printf("再見!\n");
fclose(pfile);
return 0;
}
void print_character(int32_t character_id){
switch(character_id){
case 0:
printf("索爾 ");
break;
case 1:
printf("哈諾 ");
break;
case 2:
printf("鐵諾 ");
break;
case 3:
printf("哈瓦特 ");
break;
case 4:
printf("亞雷斯 ");
break;
case 5:
printf("洛娜 ");
break;
case 6:
printf("萊汀 ");
break;
case 7:
printf("蘭斯洛特 ");
break;
case 8:
printf("希莉亞 ");
break;
case 9:
printf("悠妮 ");
break;
case 10:
printf("瑪琳 ");
break;
case 11:
printf("索菲亞 ");
break;
case 12:
printf("凱麗 ");
break;
case 13:
printf("貝克威 ");
break;
case 14:
printf("珊 ");
break;
case 15:
printf("賽可邦勒 ");
break;
case 16:
printf("凱拉斯 ");
break;
case 17:
printf("米亞斯多德 ");
break;
case 18:
printf("蜜蒂 ");
break;
case 19:
printf("羅德曼 ");
break;
case 20:
printf("莎拉 ");
break;
case 21:
printf("約拿 ");
break;
case 22:
printf("卡里斯 ");
break;
case 23:
printf("羅蘭 ");
break;
case 24:
printf("希爾法 ");
break;
case 25:
printf("謝多 ");
break;
case 26:
printf("聖寇拉斯 ");
break;
case 27:
printf("巴拿羅西亞 ");
break;
case 28:
printf("達克賽 ");
break;
case 29:
printf("亞奇梅吉 ");
break;
case 30:
printf("蓋亞 ");
break;
case 31:
printf("渥德 ");
break;
case 32:
printf("索爾(劍聖) ");
break;
case 33:
printf("哈諾(聖戰士) ");
break;
case 34:
printf("鐵諾(劍聖) ");
break;
case 35:
printf("哈瓦特(聖戰士) ");
break;
case 36:
printf("亞雷斯(聖戰士) ");
break;
case 37:
printf("洛娜(聖戰士) ");
break;
case 38:
printf("萊汀(聖戰士) ");
break;
case 40:
printf("希莉亞(狙擊手) ");
break;
case 41:
printf("悠妮(大法師) ");
break;
case 42:
printf("瑪琳(祭司) ");
break;
case 43:
printf("索菲亞(祭司) ");
break;
case 44:
printf("凱麗(鬥士) ");
break;
case 45:
printf("貝克威(狙擊手) ");
break;
case 46:
printf("珊(大法師) ");
break;
case 47:
printf("賽可邦勒(鬥士) ");
break;
case 49:
printf("米亞斯多德(龍劍士)");
break;
case 50:
printf("索爾(英雄) ");
break;
case 51:
printf("哈諾(魔戰士) ");
break;
case 52:
printf("悠妮(召喚師) ");
break;
case 53:
printf("哈瓦特(魔戰士) ");
break;
case 54:
printf("亞雷斯(龍騎士) ");
break;
case 55:
printf("洛娜(龍騎士) ");
break;
case 56:
printf("萊汀(龍騎士) ");
break;
case 58:
printf("希莉亞(神射手) ");
break;
case 59:
printf("悠妮(聖者) ");
break;
case 60:
printf("瑪琳(聖者) ");
break;
case 61:
printf("索菲亞(聖者) ");
break;
case 62:
printf("凱麗(武聖) ");
break;
case 63:
printf("貝克威(神射手) ");
break;
case 64:
printf("珊(聖者) ");
break;
case 65:
printf("賽可邦勒(武聖) ");
break;
default:
return;
}
return;
}
int32_t print_item(int32_t item_id){
switch(item_id){
case 0:
printf("短劍 ");
return 1;
case 1:
printf("闊劍 ");
return 1;
case 2:
printf("長劍 ");
return 1;
case 3:
printf("巨劍 ");
return 1;
case 4:
printf("黑暗劍 ");
return 1;
case 5:
printf("戰士劍 ");
return 1;
case 6:
printf("巨魔劍 ");
return 1;
case 7:
printf("斬鐵劍 ");
return 1;
case 8:
printf("流水劍 ");
return 1;
case 9:
printf("大地之劍 ");
return 1;
case 10:
printf("龍神劍 ");
return 1;
case 11:
printf("炎龍劍 ");
return 1;
case 12:
printf("小刀 ");
return 1;
case 13:
printf("匕首 ");
return 1;
case 14:
printf("淬毒刀 ");
return 1;
case 15:
printf("盜賊匕首 ");
return 1;
case 16:
printf("暗殺刀 ");
return 1;
case 17:
printf("護手刀 ");
return 1;
case 18:
printf("忍者刀 ");
return 1;
case 19:
printf("地獄刀 ");
return 1;
case 20:
printf("刺矛 ");
return 1;
case 21:
printf("騎槍 ");
return 1;
case 22:
printf("長戟 ");
return 1;
case 23:
printf("先鋒矛 ");
return 1;
case 24:
printf("斬馬刀 ");
return 1;
case 25:
printf("惡魔之矛 ");
return 1;
case 26:
printf("黃金之戟 ");
return 1;
case 27:
printf("龍之槍 ");
return 1;
case 28:
printf("破魔槍 ");
return 1;
case 29:
printf("戰神戟 ");
return 1;
case 30:
printf("聖之槍 ");
return 1;
case 31:
printf("巨神戟 ");
return 1;
case 32:
printf("手斧 ");
return 1;
case 33:
printf("迴旋斧 ");
return 1;
case 34:
printf("戰斧 ");
return 1;
case 35:
printf("戰鎚 ");
return 1;
case 36:
printf("巨斧 ");
return 1;
case 37:
printf("血之斧 ");
return 1;
case 38:
printf("閃電鎚 ");
return 1;
case 39:
printf("狂暴之斧 ");
return 1;
case 40:
printf("光之斧 ");
return 1;
case 41:
printf("力量之斧 ");
return 1;
case 42:
printf("大地之鎚 ");
return 1;
case 43:
printf("魔神斧 ");
return 1;
case 44:
printf("短弓 ");
return 1;
case 45:
printf("長弓 ");
return 1;
case 46:
printf("黑暗弓 ");
return 1;
case 47:
printf("巨弓 ");
return 1;
case 48:
printf("精靈弓 ");
return 1;
case 49:
printf("狙擊弓 ");
return 1;
case 50:
printf("封魔弓 ");
return 1;
case 51:
printf("風神弓 ");
return 1;
case 52:
printf("長棍 ");
return 1;
case 53:
printf("釘頭鎚 ");
return 1;
case 54:
printf("巨鎚 ");
return 1;
case 55:
printf("槤枷 ");
return 1;
case 56:
printf("魔法杖 ");
return 1;
case 57:
printf("封咒杖 ");
return 1;
case 58:
printf("力之杖 ");
return 1;
case 59:
printf("黑暗杖 ");
return 1;
case 60:
printf("龍之杖 ");
return 1;
case 61:
printf("光之杖 ");
return 1;
case 62:
printf("鐵指套 ");
return 1;
case 63:
printf("鐵爪 ");
return 1;
case 64:
printf("皇帝指環 ");
return 1;
case 65:
printf("毒爪 ");
return 1;
case 66:
printf("殭屍爪 ");
return 1;
case 67:
printf("碎岩爪 ");
return 1;
case 68:
printf("金鋼指環 ");
return 1;
case 69:
printf("裂刃爪 ");
return 1;
case 70:
printf("巨神指環 ");
return 1;
case 71:
printf("魔龍爪 ");
return 1;
case 72:
printf("威力手臂 ");
return 1;
case 73:
printf("金鋼手臂 ");
return 1;
case 74:
printf("雷神手臂 ");
return 1;
case 75:
printf("衝擊手臂 ");
return 1;
case 76:
printf("光束劍 ");
return 1;
case 77:
printf("狙擊槍 ");
return 1;
case 78:
printf("光束槍 ");
return 1;
case 79:
printf("光束砲 ");
return 1;
case 80:
printf("拳頭 ");
return 1;
case 81:
printf("利爪 ");
return 1;
case 82:
printf("觸手 ");
return 1;
case 83:
printf("巨岩手臂 ");
return 1;
case 84:
printf("激水砲 ");
return 1;
case 85:
printf("風牙斬 ");
return 1;
case 86:
printf("魔燄波 ");
return 1;
case 87:
printf("空雷震 ");
return 1;
case 88:
printf("聖者之戒 ");
return 1;
case 89:
printf("勇者徽章 ");
return 1;
case 90:
printf("精靈契印 ");
return 1;
case 91:
printf("領悟之書 ");
return 1;
case 92:
printf("心眼之書 ");
return 1;
case 93:
printf("白金徽章 ");
return 1;
case 94:
printf("生命之實 ");
return 1;
case 95:
printf("魔力水晶 ");
return 1;
case 96:
printf("風精之羽 ");
return 1;
case 97:
printf("十字弓 ");
return 1;
case 98:
printf("水晶弓 ");
return 1;
case 99:
printf("雷神鞭 ");
return 1;
case 100:
printf("天空之鑰 ");
return 1;
case 101:
printf("傳送法杖 ");
return 1;
case 102:
printf("修理套件 ");
return 1;
case 103:
printf("火焰 ");
return 1;
case 104:
printf("火神弓 ");
return 1;
case 105:
printf("鬥神指環 ");
return 1;
case 106:
printf("冰焰 ");
return 1;
case 107:
printf("黑暗波 ");
return 1;
case 123:
printf("巨岩鎧 ");
return 1;
case 124:
printf("魔神甲 ");
return 1;
case 127:
printf("魔岩鎧 ");
return 1;
case 128:
printf("布衣 ");
return 1;
case 129:
printf("旅行裝 ");
return 1;
case 130:
printf("精靈披風 ");
return 1;
case 131:
printf("元素護體 ");
return 1;
case 132:
printf("皮甲 ");
return 1;
case 133:
printf("硬皮甲 ");
return 1;
case 134:
printf("夜行裝 ");
return 1;
case 135:
printf("魔法皮甲 ");
return 1;
case 136:
printf("盜賊之衣 ");
return 1;
case 137:
printf("忍者裝 ");
return 1;
case 138:
printf("潛行服 ");
return 1;
case 139:
printf("神祕裝 ");
return 1;
case 140:
printf("暗殺服 ");
return 1;
case 141:
printf("黑暗之衣 ");
return 1;
case 142:
printf("惡魔皮甲 ");
return 1;
case 143:
printf("雷神服 ");
return 1;
case 144:
printf("環狀甲 ");
return 1;
case 145:
printf("鎖子甲 ");
return 1;
case 146:
printf("鱗甲 ");
return 1;
case 147:
printf("連環鋼甲 ");
return 1;
case 148:
printf("合金鎖甲 ");
return 1;
case 149:
printf("魔法鱗甲 ");
return 1;
case 150:
printf("血環甲 ");
return 1;
case 151:
printf("金鋼鎖甲 ");
return 1;
case 152:
printf("黑暗鱗甲 ");
return 1;
case 153:
printf("力量鎖甲 ");
return 1;
case 154:
printf("惡魔鱗甲 ");
return 1;
case 155:
printf("龍鱗甲 ");
return 1;
case 156:
printf("鎧甲 ");
return 1;
case 157:
printf("銀鎧甲 ");
return 1;
case 158:
printf("魔法鎧甲 ");
return 1;
case 159:
printf("重鎧甲 ");
return 1;
case 160:
printf("地獄鎧甲 ");
return 1;
case 161:
printf("聖鎧甲 ");
return 1;
case 162:
printf("大地鎧甲 ");
return 1;
case 163:
printf("龍神鎧甲 ");
return 1;
case 164:
printf("長袍 ");
return 1;
case 165:
printf("法師袍 ");
return 1;
case 166:
printf("僧侶袍 ");
return 1;
case 167:
printf("祭師袍 ");
return 1;
case 168:
printf("聖者袍 ");
return 1;
case 169:
printf("霧之袍 ");
return 1;
case 170:
printf("黑暗之袍 ");
return 1;
case 171:
printf("天之袍 ");
return 1;
case 172:
printf("武道服 ");
return 1;
case 173:
printf("武鬥裝 ");
return 1;
case 174:
printf("鬥士服 ");
return 1;
case 175:
printf("武者鎧甲 ");
return 1;
case 176:
printf("妖魔鬥服 ");
return 1;
case 177:
printf("武神鬥服 ");
return 1;
case 178:
printf("戰鬥裝甲 ");
return 1;
case 179:
printf("突擊裝甲 ");
return 1;
case 180:
printf("重裝甲 ");
return 1;
case 181:
printf("特殊裝甲 ");
return 1;
case 182:
printf("硬皮 ");
return 1;
case 183:
printf("青色硬皮 ");
return 1;
case 184:
printf("龍鱗 ");
return 1;
case 185:
printf("勒皮 ");
return 1;
case 186:
printf("虛無護甲 ");
return 1;
case 187:
printf("王袍 ");
return 1;
case 188:
printf("鬥士護甲 ");
return 1;
case 189:
printf("地之袍 ");
return 1;
case 190:
printf("水之袍 ");
return 1;
case 191:
printf("大地裝甲 ");
return 1;
case 192:
printf("草藥 ");
return 1;
case 193:
printf("回復劑 ");
return 1;
case 194:
printf("再生藥 ");
return 1;
case 195:
printf("神聖之水 ");
return 1;
case 196:
printf("解毒劑 ");
return 1;
case 197:
printf("退麻藥 ");
return 1;
case 198:
printf("力量藥水 ");
return 1;
case 199:
printf("耐力藥水 ");
return 1;
case 200:
printf("速度藥水 ");
return 1;
case 201:
printf("綠寶石 ");
return 1;
case 202:
printf("紅寶石 ");
return 1;
case 203:
printf("藍寶石 ");
return 1;
case 204:
printf("鑽石 ");
return 1;
case 205:
printf("飛龍卵 ");
return 1;
case 206:
printf("魔法水 ");
return 1;
case 207:
printf("水晶粒 ");
return 1;
case 208:
printf("控制中樞 ");
return 1;
case 209:
printf("黃金徽章 ");
return 1;
case 210:
printf("星之眼 ");
return 1;
case 211:
printf("光之眼 ");
return 1;
case 212:
printf("暗之眼 ");
return 1;
case 213:
printf("冰之眼 ");
return 1;
case 214:
printf("火之眼 ");
return 1;
default:
return 0;
}
return 0;
}
//印出可改數值
void print_change(){
printf("1.HP\n");
printf("2.MP\n");
printf("3.MT\n");
printf("4.DF\n");
printf("5.MV\n");
printf("6.EX\n");
printf("7.DX\n");
printf("8.item\n");
return;
}
```
:::
## 3.3 Image Steganography
:::spoiler 41171216H 石O軒
```c=
#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include<string.h>
#include<getopt.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
struct _BMP_header
{
char bm[2];
uint32_t size;
uint32_t reserve;
uint32_t offset;
uint32_t header_size;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bpp;
uint32_t compression;
uint32_t bitmap_size;
uint32_t hres;
uint32_t vres;
uint32_t used;
uint32_t important;
}__attribute__ ((__packed__));
typedef struct _BMP_header BMP_header;
//建立選項列表
struct option long_options[]={
{"write",0,NULL,'w'},
{"extract",0,NULL,'e'},
{"bits",1,NULL,'b'},
{0,0,0,0},
};
//一格像素
typedef struct _pixel{
uint8_t blue;
uint8_t green;
uint8_t red;
}__attribute__ ((__packed__)) pixel;
//抓bit
int32_t get_bit(uint8_t byte,int32_t n){
return (byte>>n) & 1;
}
int main(int argc,char *argv[]){
int32_t active_w=0;
int32_t active_e=0;
int32_t active_b=0;
for(int32_t i=0;i<argc;i++){
//擋一開始就輸入檔案
if((strncmp(argv[i],"-",1)!=0) && i==1){
printf("error.\n");
return 0;
}
//擋中間錯誤輸入 w e
if(((strncmp(argv[i],"-w",2)==0)||(strncmp(argv[i],"-e",2)==0)||(strcmp(argv[i],"--write")==0)||(strcmp(argv[i],"--extract")==0)) && (i+2<argc)){
//如果下一個不是
if((strncmp(argv[i+1],"-",1)!=0)){
//如果後面有"-"是錯誤
for(int32_t j=i+2;j<argc;j++){
if((strncmp(argv[j],"-",1)==0)){
printf("error.\n");
return 0;
}
}
}
}
//擋中間錯誤輸入 b
if((strncmp(argv[i],"-b",2)==0) && (i+3<argc)){
//有黏東西
if(strlen(argv[i])>2 && (i+2<argc)){
//如果第2個不是"-"
if((strncmp(argv[i+1],"-",1)!=0)){
//如果後面有"-"是錯誤
for(int32_t j=i+2;j<argc;j++){
if((strncmp(argv[j],"-",1)==0)){
printf("error.\n");
return 0;
}
}
}
}
//沒黏東西
else if(strlen(argv[i])==2 && (i+3<argc)){
//如果第2個不是"-"
if((strncmp(argv[i+2],"-",1)!=0)){
//如果後面有"-"是錯誤
for(int32_t j=i+3;j<argc;j++){
if((strncmp(argv[j],"-",1)==0)){
printf("error.\n");
return 0;
}
}
}
}
}
//擋中間錯誤輸入 bits
if(strncmp(argv[i],"--bits",6)==0){
//有黏東西
if(strlen(argv[i])>6 && (i+2<argc)){
//如果第2個不是"-"
if((strncmp(argv[i+1],"-",1)!=0)){
//如果後面有"-"是錯誤
for(int32_t j=i+2;j<argc;j++){
if((strncmp(argv[j],"-",1)==0)){
printf("error.\n");
return 0;
}
}
}
}
//沒黏東西
else if(strlen(argv[i])==6 && (i+3<argc)){
//如果第2個不是"-"
if((strncmp(argv[i+2],"-",1)!=0)){
//如果後面有"-"是錯誤
for(int32_t j=i+3;j<argc;j++){
if((strncmp(argv[j],"-",1)==0)){
printf("error.\n");
return 0;
}
}
}
}
}
}
int32_t now_option=0;
int32_t catch_bits=-1;
//抓選項
while((now_option=getopt_long(argc,argv,"web:",long_options,NULL))!=-1){
switch(now_option){
case 'w':
active_w=1;
break;
case 'e':
active_e=1;
break;
case 'b':
if(strlen(optarg)>1){
printf("error.\n");
return 0;
}
sscanf(optarg,"%d",&catch_bits);
if(catch_bits<1 || catch_bits>8){
printf("error.\n");
return 0;
}
else{
active_b=1;
}
break;
case '?':
printf("error.\n");
return 0;
break;
default:
printf("error.\n");
return 0;
break;
}
}
//printf("catch_bits=%d\n",catch_bits);
if(active_b==0){
catch_bits=1;
}
//w和 e不能同時出現
if(active_w==0 && active_e==0){
printf("error.\n");
return 0;
}
//w和 e不能同時出現
if(active_w==1 && active_e==1){
printf("error: w and e can't appear at the same time.\n");
return 0;
}
//抓完選項後只能剩下兩個
if(argc-optind<2){
printf("error:no file or no secret data.\n");
return 0;
}
if(argc-optind>2){
printf("error:unkown data.\n");
return 0;
}
//抓bmp檔案名稱
char bmp_name[1000]={0};
strcpy(bmp_name,argv[optind]);
//printf("%s\n",bmp_name);
//檢查副檔名
if(bmp_name[0]==0){
printf("error!\n");
return 0;
}
char *vicename;
if((vicename=strrchr(bmp_name,'.'))==NULL){
printf("error!\n");
return 0;
}
if(strcmp(vicename,".bmp")!=0){
printf("error!\n");
return 0;
}
//抓secret data檔案名稱
char secret_data_name[1000]={0};
strcpy(secret_data_name,argv[optind+1]);
//開啟bmp檔案
FILE *pfile=NULL;
if((pfile=fopen(bmp_name,"rb+"))==NULL){
printf("file is not open!\n");
return 0;
}
//讀取header
BMP_header header;
fread(&header,sizeof(header),1,pfile);
//檢查magic
if(header.bm[0]!='B' || header.bm[1]!='M'){
printf("file is not bmp!\n");
return 0;
}
//設一個pixel_array
pixel pixel_array[header.width * header.height];
fread(pixel_array,sizeof(pixel),header.height * header.width,pfile);
uint32_t one_block_size=1;
//一區塊大小是2^bits
for(int32_t i=0;i<catch_bits;i++){
one_block_size*=2;
}
////////////////如果寫入被觸發(-w)////////////////////
if(active_w==1){
//開啟secret data檔案
FILE *secret_pfile=NULL;
if((secret_pfile=fopen(secret_data_name,"rb"))==NULL){
printf("file is not open!\n");
return 0;
}
//抓secret_data的size
int32_t fd=0;
fd=open(secret_data_name,O_RDONLY);
//如果沒開啟檔案
if(fd==-1){
printf("file is not open!\n");
return 0;
}
struct stat file_stat;
fstat(fd,&file_stat);
header.reserve=file_stat.st_size;
close(fd);
//printf("header.reserve=%d\n",header.reserve);
//開始抓檔案存進去
uint8_t now_byte;
uint8_t now_block=0;
uint8_t now_size=0;
uint8_t now_color=1;
uint64_t now_pixel=0;
//做一個用來清零的遮罩
uint32_t mask=255-one_block_size+1;
while(feof(secret_pfile)==0){
//檢查如果secret_data到底了 把now_block後面補零直接存入
if(fread(&now_byte,1,1,secret_pfile)!=1){
//printf("now_block%d\n",now_block);
//如果剛好存完就跳出
if(now_size==0){
break;
}
//假如剩下1 擴展到catch bit需要的大小 假如是3 那就變100
else if(now_size>0 && now_size<catch_bits){
//printf("now_block%d\n",now_block);
for(int32_t i=0;i<catch_bits-now_size;i++){
now_block*=2;
}
//printf("now_block%d\n",now_block);
//add b
if(now_color==1){
//清零指定位數blue
pixel_array[now_pixel].blue=pixel_array[now_pixel].blue & mask;
//加入數值blue
pixel_array[now_pixel].blue+=now_block;
}
//add g
if(now_color==2){
//清零指定位數blue
pixel_array[now_pixel].green=pixel_array[now_pixel].green & mask;
//加入數值blue
pixel_array[now_pixel].green+=now_block;
}
//add r
if(now_color==3){
//清零指定位數blue
pixel_array[now_pixel].red=pixel_array[now_pixel].red & mask;
//加入數值blue
pixel_array[now_pixel].red+=now_block;
}
}
break;
}
for(int32_t i=7;i>=0;i--){
int32_t now_bit;
//抓bit
now_bit=get_bit(now_byte,i);
now_size++;
if(now_size>1){
now_block*=2;
}
now_block+=now_bit;
if(now_size==catch_bits){
//printf("now_block=%d\n",now_block);
//檢查now_pixel有沒有到底了
if(now_pixel==((header.width*header.height))){
printf("error: the secret data is larger than the cover BMP’s hiding capacity.\n");
fclose(secret_pfile);
fclose(pfile);
return 0;
}
//add b
if(now_color==1){
//清零指定位數blue
//printf("b_o=%d\n",pixel_array[now_pixel].blue);
pixel_array[now_pixel].blue=pixel_array[now_pixel].blue & mask;
//printf("now_pixel%d\n",now_pixel);
//加入數值blue
pixel_array[now_pixel].blue+=now_block;
//printf("b=%d\n",pixel_array[now_pixel].blue);
}
//add g
if(now_color==2){
//清零指定位數green
//printf("g_o=%d\n",pixel_array[now_pixel].green);
pixel_array[now_pixel].green=pixel_array[now_pixel].green & mask;
//加入數值green
pixel_array[now_pixel].green+=now_block;
//printf("g=%d\n",pixel_array[now_pixel].green);
}
//add r
if(now_color==3){
//清零指定位數red
//printf("r_o=%d\n",pixel_array[now_pixel].red);
pixel_array[now_pixel].red=pixel_array[now_pixel].red & mask;
//加入數值red
pixel_array[now_pixel].red+=now_block;
//printf("r=%d\n",pixel_array[now_pixel].red);
}
now_size=0;
now_block=0;
now_color++;
if(now_color==4){
now_color=1;
now_pixel++;
}
}
}
}
//開始寫入檔案
fseek(pfile,0,SEEK_SET);
fwrite(&header,sizeof(header),1,pfile);
fwrite(pixel_array,sizeof(pixel),header.height * header.width,pfile);
fclose(secret_pfile);
fclose(pfile);
}
////////////////如果提取被觸發(-e)////////////////////
if(active_e==1){
if(header.reserve==0){
printf("error: this file don't have secret_data!\n");
return 0;
}
//開啟secret data檔案
FILE *secret_pfile=NULL;
if((secret_pfile=fopen(secret_data_name,"wb"))==NULL){
printf("file is not open!\n");
return 0;
}
uint8_t now_byte;
uint8_t now_block=0;
uint8_t now_size=0;
uint8_t now_color=1;
uint64_t now_pixel=0;
uint32_t extract_now_size=0;
while(1){
//先抓圖檔裡面的byte
//讀取完了
if(now_pixel==(header.width*header.height)){
break;
}
//從pixel裡面的blue抓
if(now_color==1){
now_byte=pixel_array[now_pixel].blue;
}
//從pixel裡面的green抓
if(now_color==2){
now_byte=pixel_array[now_pixel].green;
}
//從pixel裡面的red抓
if(now_color==3){
now_byte=pixel_array[now_pixel].red;
}
now_color++;
if(now_color==4){
now_color=1;
now_pixel++;
}
for(int32_t i=catch_bits-1;i>=0;i--){
int32_t now_bit;
//抓bit
now_bit=get_bit(now_byte,i);
now_size++;
if(now_size>1){
now_block*=2;
}
now_block+=now_bit;
//如果抓了8個bit
if(now_size==8){
fwrite(&now_block,1,1,secret_pfile);
//printf("now_block=%d",now_block);
now_size=0;
now_block=0;
extract_now_size++;
}
//如果抓完了
if(extract_now_size==header.reserve){
//關閉檔案
fclose(secret_pfile);
fclose(pfile);
return 0;
}
}
}
}
}
```
:::
## 3.4 Game Cheater
:::spoiler 41171216H 石O軒
```c=
#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
struct Item {
uint8_t status; // 狀態值,40=裝備中、00=持有中、80=無物品
uint8_t itemId; // 物品編號
};
//總共有80byte
typedef struct _Character {
uint8_t XX; // X座標
uint8_t YY; // Y座標
uint8_t Z1; // 人物圖形
uint8_t Z2; // 人物圖形方向
uint8_t Z3; // 人物圖形跑步動作
uint8_t AA; // 動作狀態
uint8_t BB; // 陣營
uint8_t FA; // 肖像編號
uint16_t NN; // 人物姓名,假設名字最長不超過15個字符
struct Item IT[8]; // 物品列表
uint8_t magic[5]; // 法術列表
uint8_t RA; // 種族編號
uint8_t CL; // 職業編號
uint8_t LV; // 等級
uint8_t A_plus; // AP增強狀態
uint8_t D_plus; // DP增強狀態
uint8_t H_plus; // HIT/EV增強狀態
uint8_t sub_H; // 中毒狀態
uint8_t XA; // 麻痺狀態
uint8_t XM; // 封咒狀態
uint8_t space_1[15]; //空15格
uint16_t MT; // 力量
uint16_t DF; // 耐力
uint8_t MV; // 移動力
uint8_t EX; // 經驗值
uint8_t space_2; //空1格
uint16_t DX; // 速度
uint16_t H1; // 目前生命值
uint16_t H2; // 最大生命值
uint16_t M1; // 目前法力值
uint16_t M2; // 最大法力值
uint16_t AP; // 目前總攻擊力
uint16_t DP; // 目前總防禦力
uint16_t HT; // 命中率
uint16_t EV; // 閃避率
}__attribute__ ((__packed__)) character;
//印出角色
void print_character(int32_t character_id);
//印出道具
int32_t print_item(int32_t item_id);
//印出可改數值
void print_change();
//清空螢幕
void clearScreen(){
printf("\033[2J\033[1;1H");
}
int main(int argc,char *argv[]){
//如果只有輸入1個 就顯示使用方式
if(argc==1){
printf("Usage: sudo ./hw0304 pid addr\n");
return 0;
}
//ps aux | grep dosbox 可以抓pid
//home/seanshih/hw3/dosgame/fd2
//把pid address存下來
uint64_t address;
if(argc==3){
int32_t pid=-1;
sscanf(argv[1],"%d",&pid);
if(pid==-1){
printf("error: wrong pid.\n");
return 0;
}
address=strtoull(argv[2],NULL,16);
}
else{
printf("Usage: sudo ./hw0304 pid addr\n");
return 0;
}
//先抓檔案名稱
char fileName[1000]={0};
strcpy(fileName,"/proc/");
strcat(fileName,argv[1]);
strcat(fileName,"/mem");
//printf("%s\n",fileName);
//printf("%ld\n",address);
printf("資料讀取中....");
//////重要線索 角色前面int32_t=7685
///fopen
//開啟檔案
FILE *pfile=NULL;
if((pfile=fopen(fileName,"rb+"))==NULL){
printf("file is not open!\n");
return 0;
}
while(1){
//設定檔案大小
uint64_t file_size=16*1024*1024;
//創一個角色列表
int32_t character_list[100];
//初始化
for(int32_t i=0;i<100;i++){
character_list[i]=-1;
}
//有幾個角色
int32_t all_character_size=0;
//開始抓位置
uint64_t start;
int32_t search_id=7685;
int32_t search;
FILE *now_pos=pfile;
for(uint64_t i=0;i<file_size;i++){
//搜尋到最後了
if(i+79>=file_size){
break;
}
fseek(now_pos,address+i,SEEK_SET);
fread(&search,sizeof(int32_t),1,now_pos);
if(search==search_id){
start=i+address+4;
//開始把角色抓下來
while(1){
character temp;
fread(&temp,sizeof(character),1,now_pos);
//printf("(%d,%d)\n",temp.XX,temp.YY);
//printf("BB=%d\n",temp.BB);
//如果是敵方就不抓角色
if(temp.BB==1 || temp.BB==2){
character_list[all_character_size]=temp.FA;
all_character_size++;
}
else{
break;
}
}
break;
}
}
if(all_character_size==0){
clearScreen();
printf("現在沒有可更改角色!\n");
break;
}
/////開始改狀態/////
char clear;
//開始界面
clearScreen();
printf("歡迎來到炎龍騎士團2 修改器!\n");
//選擇角色
int32_t choose_character=-1;
int32_t end=0;
printf("下面是可選擇的角色:\n");
for(int32_t j=0;j<20;j++){
int32_t check_in_i=0;
for(int32_t i=0;i<all_character_size;i++){
if(i*20+j>=all_character_size){
break;
}
check_in_i=1;
printf("%2d.",i*20+j+1);
print_character(character_list[i*20+j]);
}
if(check_in_i==0){
break;
}
printf("\n");
}
printf("請輸入要改的角色編號,如要結束請輸入0: ");
scanf("%d",&choose_character);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新選
if(choose_character<0 || choose_character>all_character_size){
printf("沒有這個角色!\n");
continue;
}
//如果是0就結束
if(choose_character==0){
break;
}
//開始改資料
while(1){
//讀取角色資料 //刷新
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
character now_character;
fread(&now_character,sizeof(character),1,now_pos);
//printf("(%d,%d)\n",now_character.XX,now_character.YY);
int32_t choose_change;
//選擇要改什麼資料
printf("下面是可改變的數值:\n");
print_change();
printf("請選擇要改的數值(1-8),如要結束請輸入0,如要重新選擇角色請輸入-1: ");
scanf("%d",&choose_change);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重選
if(choose_change<-1 || choose_change>8){
printf("沒有這個選項!\n");
continue;
}
//如果是0就結束
if(choose_change==0){
end=1;
break;
}
//如果是-1就回上頁
if(choose_change==-1){
clearScreen();
printf("資料讀取中....");
break;
}
//開始處理資料
//HP
if(choose_change==1){
while(1){
int32_t now_HP;
printf("請輸入HP要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_HP);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_HP<-1 || now_HP>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_HP==-1){
clearScreen();
break;
}
//改H1
now_character.H1=now_HP;
//改H2
now_character.H2=now_HP;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//MP
if(choose_change==2){
while(1){
int32_t now_MP;
printf("請輸入MP要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_MP);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_MP<-1 || now_MP>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_MP==-1){
clearScreen();
break;
}
//改M1
now_character.M1=now_MP;
//改M2
now_character.M2=now_MP;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//MT
if(choose_change==3){
while(1){
int32_t now_MT;
printf("請輸入MT要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_MT);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_MT<-1 || now_MT>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_MT==-1){
clearScreen();
break;
}
//改MT
now_character.MT=now_MT;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//DF
if(choose_change==4){
while(1){
int32_t now_DF;
printf("請輸入DF要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_DF);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_DF<-1 || now_DF>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_DF==-1){
clearScreen();
break;
}
//改DF
now_character.DF=now_DF;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//MV
if(choose_change==5){
while(1){
int32_t now_MV;
printf("請輸入MV要改成多少(0-255)(最好25以內),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_MV);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_MV<-1 || now_MV>255){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_MV==-1){
clearScreen();
break;
}
//改MV
now_character.MV=now_MV;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//EX
if(choose_change==6){
while(1){
int32_t now_EX;
printf("請輸入EX要改成多少(0-255),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_EX);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_EX<-1 || now_EX>255){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_EX==-1){
clearScreen();
break;
}
//改EX
now_character.EX=now_EX;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//DX
if(choose_change==7){
while(1){
int32_t now_DX;
printf("請輸入DX要改成多少(0-65535),如要重新選擇數值請輸入-1: ");
scanf("%d",&now_DX);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果輸出錯誤就重新輸入
if(now_DX<-1 || now_DX>65535){
printf("超出範圍!\n");
continue;
}
//如果是-1就回上頁
if(now_DX==-1){
clearScreen();
break;
}
//改DX
now_character.DX=now_DX;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
printf("已儲存更改!\n");
break;
}
}
//道具
if(choose_change==8){
int32_t change_page=1;
while(1){
//秀出道具 //先選道具
printf("第%d頁\n",change_page);
for(int32_t j=0;j<15;j++){
int32_t check_in_i=0;
for(int32_t i=0;i<60;i++){
if(i*15+j+60*(change_page-1)>=60*change_page){
break;
}
printf("%3d.",i*15+j+60*(change_page-1));
check_in_i=print_item(i*15+j+60*(change_page-1));
if(check_in_i==0){
printf("\033[0;31m無\033[m ");
}
}
printf("\n");
}
int32_t now_item;
printf("請輸入要替換的物品編號,上一頁請輸入-3 ,下一頁請輸入-2,如要重新選擇數值請輸入-1: ");
scanf("%d",&now_item);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//回上頁
if(now_item==-3){
if(change_page==1){
clearScreen();
printf("沒有上一頁了!\n");
}
else{
clearScreen();
change_page--;
}
continue;
}
//下一頁
if(now_item==-2){
if(change_page==4){
clearScreen();
printf("沒有下一頁了!\n");
}
else{
clearScreen();
change_page++;
}
continue;
}
//如果是-1就回上頁
if(now_item==-1){
clearScreen();
break;
}
//如果輸出錯誤就重新輸入
if((now_item<-3 || now_item>214) || (now_item>=108 && now_item<=122) || (now_item>=125 && now_item<=126) ){
printf("輸入沒有代表物品或指令!\n");
continue;
}
//要換哪一格
while(1){
int32_t which;
printf("你要將\" ");
print_item(now_item);
printf("\"替換成哪一格呢?\n");
printf("現在背包狀態:\n");
for(int32_t j=0;j<8;j++){
if(now_character.IT[j].status==128){
printf("%d.\033[0;31m無\033[m\n",j+1);
}
else{
printf("%d.",j+1);
print_item(now_character.IT[j].itemId);
printf("\n");
}
}
printf("請輸入要替換的背包位置編號,如要重新選擇物品請輸入-1: ");
scanf("%d",&which);
//清除緩存區
while((clear=getchar())!='\n' && clear!=EOF);
clearScreen();
//如果是-1就回上頁
if(which==-1){
clearScreen();
break;
}
//如果輸出錯誤就重新輸入
if(which<1 || which>8){
printf("沒有這一格!\n");
continue;
}
now_character.IT[which-1].status=0;
now_character.IT[which-1].itemId=now_item;
fseek(now_pos,start+((choose_character-1)*80),SEEK_SET);
fwrite(&now_character,sizeof(character),1,now_pos);
break;
}
printf("已儲存更改!\n");
break;
}
}
}
if(end==1){
break;
}
}
//結束
printf("再見!\n");
fclose(pfile);
return 0;
}
void print_character(int32_t character_id){
switch(character_id){
case 0:
printf("索爾 ");
break;
case 1:
printf("哈諾 ");
break;
case 2:
printf("鐵諾 ");
break;
case 3:
printf("哈瓦特 ");
break;
case 4:
printf("亞雷斯 ");
break;
case 5:
printf("洛娜 ");
break;
case 6:
printf("萊汀 ");
break;
case 7:
printf("蘭斯洛特 ");
break;
case 8:
printf("希莉亞 ");
break;
case 9:
printf("悠妮 ");
break;
case 10:
printf("瑪琳 ");
break;
case 11:
printf("索菲亞 ");
break;
case 12:
printf("凱麗 ");
break;
case 13:
printf("貝克威 ");
break;
case 14:
printf("珊 ");
break;
case 15:
printf("賽可邦勒 ");
break;
case 16:
printf("凱拉斯 ");
break;
case 17:
printf("米亞斯多德 ");
break;
case 18:
printf("蜜蒂 ");
break;
case 19:
printf("羅德曼 ");
break;
case 20:
printf("莎拉 ");
break;
case 21:
printf("約拿 ");
break;
case 22:
printf("卡里斯 ");
break;
case 23:
printf("羅蘭 ");
break;
case 24:
printf("希爾法 ");
break;
case 25:
printf("謝多 ");
break;
case 26:
printf("聖寇拉斯 ");
break;
case 27:
printf("巴拿羅西亞 ");
break;
case 28:
printf("達克賽 ");
break;
case 29:
printf("亞奇梅吉 ");
break;
case 30:
printf("蓋亞 ");
break;
case 31:
printf("渥德 ");
break;
case 32:
printf("索爾(劍聖) ");
break;
case 33:
printf("哈諾(聖戰士) ");
break;
case 34:
printf("鐵諾(劍聖) ");
break;
case 35:
printf("哈瓦特(聖戰士) ");
break;
case 36:
printf("亞雷斯(聖戰士) ");
break;
case 37:
printf("洛娜(聖戰士) ");
break;
case 38:
printf("萊汀(聖戰士) ");
break;
case 40:
printf("希莉亞(狙擊手) ");
break;
case 41:
printf("悠妮(大法師) ");
break;
case 42:
printf("瑪琳(祭司) ");
break;
case 43:
printf("索菲亞(祭司) ");
break;
case 44:
printf("凱麗(鬥士) ");
break;
case 45:
printf("貝克威(狙擊手) ");
break;
case 46:
printf("珊(大法師) ");
break;
case 47:
printf("賽可邦勒(鬥士) ");
break;
case 49:
printf("米亞斯多德(龍劍士)");
break;
case 50:
printf("索爾(英雄) ");
break;
case 51:
printf("哈諾(魔戰士) ");
break;
case 52:
printf("悠妮(召喚師) ");
break;
case 53:
printf("哈瓦特(魔戰士) ");
break;
case 54:
printf("亞雷斯(龍騎士) ");
break;
case 55:
printf("洛娜(龍騎士) ");
break;
case 56:
printf("萊汀(龍騎士) ");
break;
case 58:
printf("希莉亞(神射手) ");
break;
case 59:
printf("悠妮(聖者) ");
break;
case 60:
printf("瑪琳(聖者) ");
break;
case 61:
printf("索菲亞(聖者) ");
break;
case 62:
printf("凱麗(武聖) ");
break;
case 63:
printf("貝克威(神射手) ");
break;
case 64:
printf("珊(聖者) ");
break;
case 65:
printf("賽可邦勒(武聖) ");
break;
default:
return;
}
return;
}
int32_t print_item(int32_t item_id){
switch(item_id){
case 0:
printf("短劍 ");
return 1;
case 1:
printf("闊劍 ");
return 1;
case 2:
printf("長劍 ");
return 1;
case 3:
printf("巨劍 ");
return 1;
case 4:
printf("黑暗劍 ");
return 1;
case 5:
printf("戰士劍 ");
return 1;
case 6:
printf("巨魔劍 ");
return 1;
case 7:
printf("斬鐵劍 ");
return 1;
case 8:
printf("流水劍 ");
return 1;
case 9:
printf("大地之劍 ");
return 1;
case 10:
printf("龍神劍 ");
return 1;
case 11:
printf("炎龍劍 ");
return 1;
case 12:
printf("小刀 ");
return 1;
case 13:
printf("匕首 ");
return 1;
case 14:
printf("淬毒刀 ");
return 1;
case 15:
printf("盜賊匕首 ");
return 1;
case 16:
printf("暗殺刀 ");
return 1;
case 17:
printf("護手刀 ");
return 1;
case 18:
printf("忍者刀 ");
return 1;
case 19:
printf("地獄刀 ");
return 1;
case 20:
printf("刺矛 ");
return 1;
case 21:
printf("騎槍 ");
return 1;
case 22:
printf("長戟 ");
return 1;
case 23:
printf("先鋒矛 ");
return 1;
case 24:
printf("斬馬刀 ");
return 1;
case 25:
printf("惡魔之矛 ");
return 1;
case 26:
printf("黃金之戟 ");
return 1;
case 27:
printf("龍之槍 ");
return 1;
case 28:
printf("破魔槍 ");
return 1;
case 29:
printf("戰神戟 ");
return 1;
case 30:
printf("聖之槍 ");
return 1;
case 31:
printf("巨神戟 ");
return 1;
case 32:
printf("手斧 ");
return 1;
case 33:
printf("迴旋斧 ");
return 1;
case 34:
printf("戰斧 ");
return 1;
case 35:
printf("戰鎚 ");
return 1;
case 36:
printf("巨斧 ");
return 1;
case 37:
printf("血之斧 ");
return 1;
case 38:
printf("閃電鎚 ");
return 1;
case 39:
printf("狂暴之斧 ");
return 1;
case 40:
printf("光之斧 ");
return 1;
case 41:
printf("力量之斧 ");
return 1;
case 42:
printf("大地之鎚 ");
return 1;
case 43:
printf("魔神斧 ");
return 1;
case 44:
printf("短弓 ");
return 1;
case 45:
printf("長弓 ");
return 1;
case 46:
printf("黑暗弓 ");
return 1;
case 47:
printf("巨弓 ");
return 1;
case 48:
printf("精靈弓 ");
return 1;
case 49:
printf("狙擊弓 ");
return 1;
case 50:
printf("封魔弓 ");
return 1;
case 51:
printf("風神弓 ");
return 1;
case 52:
printf("長棍 ");
return 1;
case 53:
printf("釘頭鎚 ");
return 1;
case 54:
printf("巨鎚 ");
return 1;
case 55:
printf("槤枷 ");
return 1;
case 56:
printf("魔法杖 ");
return 1;
case 57:
printf("封咒杖 ");
return 1;
case 58:
printf("力之杖 ");
return 1;
case 59:
printf("黑暗杖 ");
return 1;
case 60:
printf("龍之杖 ");
return 1;
case 61:
printf("光之杖 ");
return 1;
case 62:
printf("鐵指套 ");
return 1;
case 63:
printf("鐵爪 ");
return 1;
case 64:
printf("皇帝指環 ");
return 1;
case 65:
printf("毒爪 ");
return 1;
case 66:
printf("殭屍爪 ");
return 1;
case 67:
printf("碎岩爪 ");
return 1;
case 68:
printf("金鋼指環 ");
return 1;
case 69:
printf("裂刃爪 ");
return 1;
case 70:
printf("巨神指環 ");
return 1;
case 71:
printf("魔龍爪 ");
return 1;
case 72:
printf("威力手臂 ");
return 1;
case 73:
printf("金鋼手臂 ");
return 1;
case 74:
printf("雷神手臂 ");
return 1;
case 75:
printf("衝擊手臂 ");
return 1;
case 76:
printf("光束劍 ");
return 1;
case 77:
printf("狙擊槍 ");
return 1;
case 78:
printf("光束槍 ");
return 1;
case 79:
printf("光束砲 ");
return 1;
case 80:
printf("拳頭 ");
return 1;
case 81:
printf("利爪 ");
return 1;
case 82:
printf("觸手 ");
return 1;
case 83:
printf("巨岩手臂 ");
return 1;
case 84:
printf("激水砲 ");
return 1;
case 85:
printf("風牙斬 ");
return 1;
case 86:
printf("魔燄波 ");
return 1;
case 87:
printf("空雷震 ");
return 1;
case 88:
printf("聖者之戒 ");
return 1;
case 89:
printf("勇者徽章 ");
return 1;
case 90:
printf("精靈契印 ");
return 1;
case 91:
printf("領悟之書 ");
return 1;
case 92:
printf("心眼之書 ");
return 1;
case 93:
printf("白金徽章 ");
return 1;
case 94:
printf("生命之實 ");
return 1;
case 95:
printf("魔力水晶 ");
return 1;
case 96:
printf("風精之羽 ");
return 1;
case 97:
printf("十字弓 ");
return 1;
case 98:
printf("水晶弓 ");
return 1;
case 99:
printf("雷神鞭 ");
return 1;
case 100:
printf("天空之鑰 ");
return 1;
case 101:
printf("傳送法杖 ");
return 1;
case 102:
printf("修理套件 ");
return 1;
case 103:
printf("火焰 ");
return 1;
case 104:
printf("火神弓 ");
return 1;
case 105:
printf("鬥神指環 ");
return 1;
case 106:
printf("冰焰 ");
return 1;
case 107:
printf("黑暗波 ");
return 1;
case 123:
printf("巨岩鎧 ");
return 1;
case 124:
printf("魔神甲 ");
return 1;
case 127:
printf("魔岩鎧 ");
return 1;
case 128:
printf("布衣 ");
return 1;
case 129:
printf("旅行裝 ");
return 1;
case 130:
printf("精靈披風 ");
return 1;
case 131:
printf("元素護體 ");
return 1;
case 132:
printf("皮甲 ");
return 1;
case 133:
printf("硬皮甲 ");
return 1;
case 134:
printf("夜行裝 ");
return 1;
case 135:
printf("魔法皮甲 ");
return 1;
case 136:
printf("盜賊之衣 ");
return 1;
case 137:
printf("忍者裝 ");
return 1;
case 138:
printf("潛行服 ");
return 1;
case 139:
printf("神祕裝 ");
return 1;
case 140:
printf("暗殺服 ");
return 1;
case 141:
printf("黑暗之衣 ");
return 1;
case 142:
printf("惡魔皮甲 ");
return 1;
case 143:
printf("雷神服 ");
return 1;
case 144:
printf("環狀甲 ");
return 1;
case 145:
printf("鎖子甲 ");
return 1;
case 146:
printf("鱗甲 ");
return 1;
case 147:
printf("連環鋼甲 ");
return 1;
case 148:
printf("合金鎖甲 ");
return 1;
case 149:
printf("魔法鱗甲 ");
return 1;
case 150:
printf("血環甲 ");
return 1;
case 151:
printf("金鋼鎖甲 ");
return 1;
case 152:
printf("黑暗鱗甲 ");
return 1;
case 153:
printf("力量鎖甲 ");
return 1;
case 154:
printf("惡魔鱗甲 ");
return 1;
case 155:
printf("龍鱗甲 ");
return 1;
case 156:
printf("鎧甲 ");
return 1;
case 157:
printf("銀鎧甲 ");
return 1;
case 158:
printf("魔法鎧甲 ");
return 1;
case 159:
printf("重鎧甲 ");
return 1;
case 160:
printf("地獄鎧甲 ");
return 1;
case 161:
printf("聖鎧甲 ");
return 1;
case 162:
printf("大地鎧甲 ");
return 1;
case 163:
printf("龍神鎧甲 ");
return 1;
case 164:
printf("長袍 ");
return 1;
case 165:
printf("法師袍 ");
return 1;
case 166:
printf("僧侶袍 ");
return 1;
case 167:
printf("祭師袍 ");
return 1;
case 168:
printf("聖者袍 ");
return 1;
case 169:
printf("霧之袍 ");
return 1;
case 170:
printf("黑暗之袍 ");
return 1;
case 171:
printf("天之袍 ");
return 1;
case 172:
printf("武道服 ");
return 1;
case 173:
printf("武鬥裝 ");
return 1;
case 174:
printf("鬥士服 ");
return 1;
case 175:
printf("武者鎧甲 ");
return 1;
case 176:
printf("妖魔鬥服 ");
return 1;
case 177:
printf("武神鬥服 ");
return 1;
case 178:
printf("戰鬥裝甲 ");
return 1;
case 179:
printf("突擊裝甲 ");
return 1;
case 180:
printf("重裝甲 ");
return 1;
case 181:
printf("特殊裝甲 ");
return 1;
case 182:
printf("硬皮 ");
return 1;
case 183:
printf("青色硬皮 ");
return 1;
case 184:
printf("龍鱗 ");
return 1;
case 185:
printf("勒皮 ");
return 1;
case 186:
printf("虛無護甲 ");
return 1;
case 187:
printf("王袍 ");
return 1;
case 188:
printf("鬥士護甲 ");
return 1;
case 189:
printf("地之袍 ");
return 1;
case 190:
printf("水之袍 ");
return 1;
case 191:
printf("大地裝甲 ");
return 1;
case 192:
printf("草藥 ");
return 1;
case 193:
printf("回復劑 ");
return 1;
case 194:
printf("再生藥 ");
return 1;
case 195:
printf("神聖之水 ");
return 1;
case 196:
printf("解毒劑 ");
return 1;
case 197:
printf("退麻藥 ");
return 1;
case 198:
printf("力量藥水 ");
return 1;
case 199:
printf("耐力藥水 ");
return 1;
case 200:
printf("速度藥水 ");
return 1;
case 201:
printf("綠寶石 ");
return 1;
case 202:
printf("紅寶石 ");
return 1;
case 203:
printf("藍寶石 ");
return 1;
case 204:
printf("鑽石 ");
return 1;
case 205:
printf("飛龍卵 ");
return 1;
case 206:
printf("魔法水 ");
return 1;
case 207:
printf("水晶粒 ");
return 1;
case 208:
printf("控制中樞 ");
return 1;
case 209:
printf("黃金徽章 ");
return 1;
case 210:
printf("星之眼 ");
return 1;
case 211:
printf("光之眼 ");
return 1;
case 212:
printf("暗之眼 ");
return 1;
case 213:
printf("冰之眼 ");
return 1;
case 214:
printf("火之眼 ");
return 1;
default:
return 0;
}
return 0;
}
//印出可改數值
void print_change(){
printf("1.HP\n");
printf("2.MP\n");
printf("3.MT\n");
printf("4.DF\n");
printf("5.MV\n");
printf("6.EX\n");
printf("7.DX\n");
printf("8.item\n");
return;
}
```
:::
## 3.5 RGB Line Chart
:::spoiler 41247027S 陳O羽
```c
#include <stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<getopt.h>
#include<unistd.h>
#include<string.h>
struct option long_option[] = {
{"input",1,NULL,'i'},
{"output",1,NULL,'o'},
{"width",1,NULL,'w'},
{"height",1,NULL,'h'},
{"line",0,NULL,'l'},
{"help",0,NULL,'H'},
{0,0,0,0}
};
struct _sBmpHeader
{
char bm[2];
uint32_t size;
uint32_t reserve;
uint32_t offset;
uint32_t header_size;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bpp;
uint32_t compression;
uint32_t bitmap_size;
uint32_t hres;
uint32_t vres;
uint32_t used;
uint32_t important;
}__attribute__ ((__packed__));
typedef struct _sBmpHeader sBmpHeader;
void draw(int32_t position,int32_t radius,int32_t width,uint8_t *bmp_map,uint32_t maxi){
double color = 255.0/radius;
for(int32_t i=radius-1;i>=0;i--){
for(int32_t j=0;j<=i;j++){
if(position+3*j+width*(radius-1-i)<maxi&&position+3*j+width*(radius-1-i)>=0){
if(*(bmp_map+position+3*j+width*(radius-1-i))<color*(i+1-j))
*(bmp_map+position+3*j+width*(radius-1-i)) = color*(i+1-j);
}
if(position-3*j+width*(radius-1-i)<maxi&&position-3*j+width*(radius-1-i)>=0){
if(*(bmp_map+position-3*j+width*(radius-1-i))<color*(i+1-j))
*(bmp_map+position-3*j+width*(radius-1-i)) = color*(i+1-j);
}
if(position+3*j-width*(radius-1-i)<maxi&&position+3*j-width*(radius-1-i)>=0){
if(*(bmp_map+position+3*j-width*(radius-1-i))<color*(i+1-j))
*(bmp_map+position+3*j-width*(radius-1-i)) = color*(i+1-j);
}
if(position-3*j-width*(radius-1-i)<maxi&&position-3*j-width*(radius-1-i)>=0){
if(*(bmp_map+position-3*j-width*(radius-1-i))<color*(i+1-j))
*(bmp_map+position-3*j-width*(radius-1-i)) = color*(i+1-j);
}
}
}
}
int main(int argc, char *argv[]){
int32_t width,height,radius,option=0,opt_h=0,check=0;
char input[100],output[100];
while((option = getopt_long(argc,argv,"i:o:w:h:l:H",long_option,NULL))!=-1){
if(option == 'i'){
check++;
strcpy(input,optarg);
}
else if(option == 'o'){
check++;
strcpy(output,optarg);
}
else if(option == 'w'){
check++;
width = atoi(optarg);
}
else if(option == 'h'){
check++;
height = atoi(optarg);
}
else if(option == 'l'){
check++;
radius = atoi(optarg);
}
else if(option == 'H'){
opt_h = 1;
}
}
if(opt_h){
printf("Usage: hw0302 [options]\n -i, --input, mandatory: input file path\n -o, --output, mandatory: output file path\n -w, --width, mandatory: output bmp file width\n -h, --height, mandatory: output bmp file height\n -l, --line, mandatory: the radius of line\n -H, --help, option: show help message\n");
return 0;
}
if(check!=5){
printf("Wrong input!\n");
return 0;
}
FILE *IFile,*OFile;
if((IFile = fopen(input,"rb"))==NULL){
printf("Can't Not Open\n");
return 0;
}
if((OFile = fopen(output,"wb"))==NULL){
printf("Can't Not Open\n");
return 0;
}
sBmpHeader input_header,output_header;
fread(&input_header,sizeof(input_header),1,IFile);
uint64_t Blue[256]={0},Red[256]={0},Green[256]={0},maxi=0;
int32_t bytes_per_pixel = input_header.bpp / 8; // 每个像素占用的字节数
int32_t alignment_bytes = (4 - ((input_header.width * bytes_per_pixel) % 4)) % 4; // 行字节数对齐所需的填充字节数
fseek(IFile,input_header.offset,SEEK_SET);
for (int32_t i = 0; i < input_header.height; i++) {
for (int32_t j = 0; j < input_header.width; j++) {
for (int32_t k = 0; k < 3; k++) {
uint8_t num;
fread(&num, sizeof(uint8_t), 1, IFile);
// 根据颜色分量的顺序来选择对应的数组递增
if (k == 0) {
Blue[num]++;
if (Blue[num] > maxi)
maxi = Blue[num];
} else if (k == 1) {
Green[num]++;
if (Green[num] > maxi)
maxi = Green[num];
} else if (k == 2) {
Red[num]++;
if (Red[num] > maxi)
maxi = Red[num];
}
}
}
fseek(IFile, alignment_bytes, SEEK_CUR);
}
int tmp2 = (width*3)%4;
if(tmp2>0)
tmp2 = 4 - tmp2;
strcpy(output_header.bm,"BM");
output_header.offset = 54;
output_header.header_size = 40;
output_header.reserve = 0;
output_header.bpp = 24;
output_header.width= width;
output_header.height = height;
output_header.planes=1;
output_header.important = 0;
output_header.bitmap_size = width * height * 3 + height * tmp2;
output_header.size = output_header.bitmap_size + output_header.offset;
output_header.compression = 0;
output_header.hres =0;
output_header.vres =0;
output_header.important=0;
output_header.used = 0;
fwrite(&output_header,sizeof(output_header),1,OFile);
uint8_t *bmp_map;
bmp_map =calloc(output_header.bitmap_size,sizeof(uint8_t));
memset(bmp_map,0,output_header.bitmap_size);
double vertical = (double)height/(double)maxi,horizontal = (double)width/255.0;
//Blue
for(int32_t i=1;i<256;i++){
if(Blue[i-1]>=Blue[i]){
double slope = (double)(vertical*(Blue[i-1]-Blue[i]))/(double)(horizontal);//((int32_t)((i)*horizontal)-(int32_t)((i-1)*horizontal)); (int32_t)(vertical*Blue[i-1])-(int32_t)(vertical*Blue[i])
int32_t cnt_height=0;
for(int32_t j=0;j<=(horizontal);j++){
if((int32_t)j*slope-cnt_height==0){
draw((int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Blue[i-1]-cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
else{
for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){
draw((int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Blue[i-1]-(cnt_height+k)))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
}
cnt_height=j*slope;
}
}
else if(Blue[i-1]<Blue[i]){
double slope = (double)(vertical*(Blue[i]-Blue[i-1]))/(horizontal);
int32_t cnt_height=0;
for(int32_t j=0;j<=(horizontal);j++){
if((int32_t)j*slope-cnt_height==0){
draw((int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Blue[i-1]+cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
else{
for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){
draw((int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Blue[i-1]+cnt_height+k))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
}
cnt_height=j*slope;
}
}
}
//Green
for(int32_t i=1;i<256;i++){
if(Green[i-1]>=Green[i]){
double slope = (double)(vertical*(Green[i-1]-Green[i]))/(double)(horizontal);
int32_t cnt_height=0;
for(int32_t j=0;j<=(horizontal);j++){
if((int32_t)j*slope-cnt_height==0){
draw(1+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Green[i-1]-cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
else{
for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){
draw(1+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Green[i-1]-(cnt_height+k)))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
}
cnt_height=j*slope;
}
}
else if(Green[i-1]<Green[i]){
double slope = (double)(vertical*(Green[i]-Green[i-1]))/(horizontal);
int32_t cnt_height=0;
for(int32_t j=0;j<=(horizontal);j++){
if((int32_t)j*slope-cnt_height==0){
draw(1+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Green[i-1]+cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
else{
for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){
draw(1+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Green[i-1]+cnt_height+k))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
}
cnt_height=j*slope;
}
}
}
//Red
for(int32_t i=1;i<256;i++){
if(Red[i-1]>=Red[i]){
double slope = (double)(vertical*(Red[i-1]-Red[i]))/(double)(horizontal);//((int32_t)((i)*horizontal)-(int32_t)((i-1)*horizontal)); (int32_t)(vertical*Blue[i-1])-(int32_t)(vertical*Blue[i])
int32_t cnt_height=0;
for(int32_t j=0;j<=(horizontal);j++){
if((int32_t)j*slope-cnt_height==0){
draw(2+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Red[i-1]-cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
else{
for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){
draw(2+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Red[i-1]-(cnt_height+k)))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
}
cnt_height=j*slope;
}
}
else if(Red[i-1]<Red[i]){
double slope = (double)(vertical*(Red[i]-Red[i-1]))/(horizontal);
int32_t cnt_height=0;
for(int32_t j=0;j<=(horizontal);j++){
if((int32_t)j*slope-cnt_height==0){
draw(2+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Red[i-1]+cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
else{
for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){
draw(2+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Red[i-1]+cnt_height+k))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size);
}
}
cnt_height=j*slope;
}
}
}
fwrite(bmp_map,sizeof(uint8_t),output_header.bitmap_size,OFile);
fclose(IFile);
fclose(OFile);
return 0;
}
```
:::
## 3.6 Bonus: ncurses
不提供範例解答,但可以看看其他人是如何把相關內容寫成部落格的:
https://shengyu7697.github.io/cpp-ncurses/