앗시바 글쓰다 날려먹었군...

주제는 ToHeart2 .PAK 파일 분해기

근데 저 pak 파일이라는게 좀 지나치게 단순한 포맷이라

프로그램에 뭐가 있을거란 기대는 금지

작성동기

엊저녁 할일이 없었다

라이센스

이 프로그램을 다운받으면 호빵님의 노예가 되는 라이센스.txt

라고 하고싶지만 제작사(나 말고) 사정상 GPL임...

판매가격

매달 님 통장 혹은 부모님 통장에서 통신사로 나가고 있으니 신경쓸거 없음

소스코드 공개 여부

필요한 사람 댓글남기면 택배로 보내줌

...농담이고 머 원한다면 주겠지만(아니 줘야되지만) 전혀 가치 없는 물건이라...

도움주신 분

뭔 배짱으로 월급을 받는지 알 도리 없는 리프사의 어떤 프로그래머

사용법

예제> th2_unpack grp.pak

하면 grp.pak의 모든 파일이 해체돼서 나옴

압축돼있던 놈은 압축 풀려서 나옴

기존에 같은이름 파일이 있으면 묻지도 따지지도 않고 덮어씌움

예외, 오류처리 일절 없음 쪼금 있음

인자로 넘긴 파일이 투하트의 .pak 파일이 아니면 무슨일이 벌어질진 나도 모름 안풀림

테스트용 출력문을 안제거해서 시끄러움

실행하려고 할때 나도 모르는 어떤 dll등을 요구할수도 있으니

그런 상황이 만에하나 발생할경우 댓글로 신고 바람

사용중 이상발생시

책임안짐 배째

실행환경

win7 64비트에서 테스트됐으나 32비트 실행파일임

제일 중요한 다운경로

http://hoppang.net/pds/th2_unpack.exe

안받아지면 쫌 기둘

변형된(압축된도 아니고..) PAK 파일 풀기 기능 추가한 patch1 버전 새로 올림

버그 급 수정한 patch2 버전 올림..

마지막으로

링크 한줄로 끝낼려고 했는데 어째 말이 많아졌다

아참 같은 엔진 쓰는 겜은 다 풀릴듯.. 장담은 못함
크리에이티브 커먼즈 라이센스
Creative Commons License
2010/02/17 10:17 2010/02/17 10:17
Posted by 호빵
윈도우즈는 WaitForSingleObject() API 함수를 이용하면 아주 간단히 끝낼 수 있지만, 맥을 비롯한 POSIX 쪽으로 넘어가면 상황이 좀 더 복잡해진다. 기본적으로 유닉스는 stdin을 통해 비동기 입출력을 할 수 없기 때문이다.

하지만 기본적으로 안 된다는 거지, 불가능하다는 소린 아니다.
여기 도움이 될 만한 링크가 하나 있다.

Non-blocking user input in loop without ncurses.

이 글을 참고하면 앞 포스팅에서 말했던 nonblocking 입력을 구현해 낼 수 있지만, 윈도우즈에서와 다른 점이 하나 있다. echo가 없어지지 않는다는 점이다. 이 문제는 termios 설정 과정에서 플래그를 조금만 조작해 주면 해결할 수 있다.

/**
 @a http://cc.byexamples.com/20070408/non-blocking-user-input-in-loop-without-ncurses/
 
 with few modification.
 */

#include<sys/time.h>  // sys time.h
#include<sys/types.h> // sys types.h
#include<termios.h> // termios.h
#include<unistd.h> // unistd.h
#include<cstdio> // C라면 그냥 stdio.h로 바꿔 주면 된다..

#define NB_ENABLE 0
#define NB_DISABLE 1

void nonblock(int state)  
{
    struct termios ttystate;

    // 터미널 상태를 읽어온다.
    // STDIN_FILENO = fileno(stdin) (정수형이다) 
    tcgetattr(STDIN_FILENO, &ttystate);  

    if (state==NB_ENABLE)  
    {
        //turn off canonical mode  
        ttystate.c_lflag &= ~ICANON;
        // 에코를 끄는 방법은 간단하다
        ttystate.c_lflag &= ~ECHO;
        // 최소로 읽어올 글자수를 정함
        ttystate.c_cc[VMIN] = 1;  
    }  
    else if (state==NB_DISABLE)  
    {
        // Canonical 모드를 다시 사용한다
        ttystate.c_lflag |= ICANON;  
        // 에코도 복구해줘야 한다... ㅡㅡ
        ttystate.c_lflag |= ECHO;
    }  
    // 지정한 옵션대로 터미널을 설정한다.
    tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
}  

int kbhit()  
{  
    struct timeval tv;  
    fd_set fds;  
    tv.tv_sec = 0;  
    tv.tv_usec = 0;  
    FD_ZERO(&fds);  
    FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0  
    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);  
    return FD_ISSET(STDIN_FILENO, &fds);  
}

int main()
{
    char c;  
    int i=0;  

    nonblock(NB_ENABLE);  
    while(!i)  
    {  
        usleep(1);
        i=kbhit();
        if (i!=0)
        {
            c=fgetc(stdin);
            if (c=='q')
                i=1;
            else
                i=0;
        }
    }
    printf("\n you hit %c. \n",c);  
    nonblock(NB_DISABLE);

    return 0; 
}

이건 여담인데.. BSD 계열의 개선된 폴링 메커니즘인 kqueue는 애초에 stdin, tty 등 콘솔 장치와 연계되지가 않고, poll의 경우는 타이거에서 stdin과 연계가 안되는 '버그'가 있다. 결국 select 뿐이다...

확인은 안해봤지만 위 코드는 아마 POSIX 표준을 만족하는 운영체제에서는 다 실행될 것으로 본다.

이건 여담 2인데, 사파리에선 텍스트큐브 위지윅 편집기가 동작하지 않는 것 같다.


에코 관련해서 버그가 있다. 손좀 봐야겠다.

크리에이티브 커먼즈 라이센스
Creative Commons License
2010/01/29 17:51 2010/01/29 17:51
Posted by 호빵

아.. nonblocking을 한글로 뭐라고 표현해야 될지 모르겠다.

대충 풀어서 쓰자면 입력을 요구하되, 기다리지는 않는다는 뜻이다. 무슨 소린가 하면, C로 프로그래밍을 조금이라도 해본 사람은 알 것이다. gets 같은 함수로 입력받기를 기다린다고 하자. 그럼 이 gets는 실제로 입력이 들어올 때까지 끝나지 않는다.

gets(first);
printf("첫 번째 입력이 들어왔습니다. ?\n");
gets(second);

first 입력을 완료하기 전까지 2번 줄의 printf는 결코 실행되지 않으며, 따라서 second 입력도 받을 수 없다. gets는 사용자가 입력을 완료할 때까지 끝나지 않는 것이다. 이것이 Blocking 입력이다.

반대로 Nonblocking은, 입력이 들어왔는지 조사는 하지만 입력이 있건 없건 진행된다. 넌블럭킹 입력 같은 경우는 프로그래밍 초보자가 다룰 주제가 아니기 때문에 교양 수준으로 배운 사람들이라면 생전 처음 듣는 소리일 것이다. 넌블럭킹 입력의 쓰임을 가상코드로 표현해보면 대충 이렇다.

// 입력이 있든 없든 이 함수는 결과값을 즉시 반환한다(고 치자)
input = check_if_input_exists(stdin); 

if(input == true) printf("요태카지 날 미앵한고야?\n");
else /* input == false */ printf("논 자유에 모미 아냐 요태카지 그래와코 아페로도 개속\n");

즉 넌블럭킹 입력은 (지나치게 단순화한 것이긴 하지만) 입력이 반드시 있다고 가정하는 것이 아니라, 입력이 있을 수도 없을 수도 있는 경우에 쓸 수 있는 놈이다. 혹은 입력이 언젠가는 있겠지만, 그거 무한정 기다리고 있을 만큼 한가하지 않다면, 언젠가 들어올 입력을 기다리는 동안 다른 일을 하고 있어야 마땅하다.

넌블럭킹과 블럭킹의 차이를 이해하기 가장 쉬운 예가 게임이다. 턴제 전략게임 - 중에 가장 유명한 - 바둑을 두고 있다고 치자. 바둑은 블럭킹의 예를 들기에 가장 적합한 케이스다. 내가 돌을 두기 전까지는 결코 상대방 차례가 오지 않기 때문이다(물론 시간제한 없는 룰일 경우다). 반대로 내 차례라는 것이 애당초 없는 스타크래프트는 넌블럭킹의 예를 들기에 (사실 조금은 부적합하지만) 좋다.

아무튼 잡설은 그만하고..


그런데 블럭킹 입력과 달리 넌블럭킹 입력은 운영체제에 몹시 의존적이다. 코드 하나 짜 놓고 이리저리 돌려쓰기를 좋아하는 나 같은 사람에게는 몹시도 슬픈 얘기다.


그러니까 안짜도 될 코드 짜서 짜증이 났다 그 소리다.

/**
    윈도우즈에서 Nonblocking 입력을 몹시 하고 싶어서 만들었다.
    
    @author hoppang at gmail dot com
    @date 2010-01-27
    @version 9999
    @a http://hoppang.net
 */

#include<cstdio>
#include<windows.h>

int main()
{
    int count = 0;
    DWORD result, how_many_read;
    INPUT_RECORD input;
    HANDLE stdin_handle;
    // stdin의 윈도우식 핸들을 구한다.
    stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
    // 각 
    bool shift_state = false, alt_state = false, ctrl_state = false;
    // 자 루프를 돌자
    for(;;){
        /*
            WaitForSingleObject는 키보드 입력에만 쓰이는 놈은 아니다.
            자세한 것은 MSDN을 찾아보고.. 아무튼 여기서는 유닉스의 select를
            대체할 수 있다.
            두 번째 인자(시간)가 0일 경우 입력 버퍼에 아무것도 없어도
            입력을 기다리지 않고 즉시 리턴한다. (non-blocking)
         */
        result = WaitForSingleObject(stdin_handle, 0);
        /*
            들어온 입력이 있을 경우 WAIT_OBJECT_0이 반환된다.
            인터넷에서 어쩌다 본 문서에는 '모든 종류의' 이벤트를 감지할 수 있다고 했으나,
            실제 돌려본 바 그렇지는 않은 듯함. 키보드 입력만 받는다.
         */
        if(result == WAIT_OBJECT_0) {
            /* 입력 버퍼에서 입력을 읽어들인다.
             param 1 [in]    이름 보면 모르나
             param 2 [out]    받아들인 입력 정보가 저장될 구조체
             param 3 [in]    인자 2에 넘겨진 구조체가 몇 개인가.
             param 4 [out]    읽어들인 입력 정보가 총 몇 개인가. 문제가 없다면 인자 3과 같다.
             */
            ReadConsoleInput(stdin_handle, &input, 1, &how_many_read);
            /*
                조금 귀찮은 부분이다.
             */
            switch(input.Event.KeyEvent.wVirtualKeyCode) {
                case VK_ESCAPE:
                    return 1;
                case VK_SHIFT:
                    shift_state = input.Event.KeyEvent.bKeyDown;
                    break;
                case VK_MENU: // alt
                    alt_state = input.Event.KeyEvent.bKeyDown;
                    break;
                case VK_CONTROL:
                    ctrl_state = input.Event.KeyEvent.bKeyDown;
                    break;
                default:
                    if(input.Event.KeyEvent.bKeyDown == TRUE) {
                        printf("\ninput %x %s%s%s, how_many_read = %x\n",
                            input.Event.KeyEvent.wVirtualKeyCode,
                            shift_state ? "[shift]" : "",
                            alt_state ? "[alt]" : "", 
                            ctrl_state ? "[ctrl]" : "", how_many_read);
                    }
            }
        }
        // 입력이 없을 경우. 사실 이건 없어도 상관없는데
        // 프로그램이 멎어 있지 않다는 것을 보여주려고 집어넣었다.
        else printf("\r%10d", count++);
    }
    
    return 0;
}



크리에이티브 커먼즈 라이센스
Creative Commons License
2010/01/27 18:15 2010/01/27 18:15
Posted by 호빵

고민끝

삽질일기 2010/01/11 03:50

class Arm_vm
{
// 이상 생략
    std::map<uint32_t, std::tr1::function<uint32_t, (Arm_vm*, bool, uint32_t)> handler;
// 이하 생략
};

Arm_vm::Arm_vm()
{
// 기타 생략
    handler[1] = &Arm_vm::handler_1;
    handler[2] = &Arm_vm::handler_2;

    handler[3] = &Arm_vm::handler_3;

    handler[4] = &Arm_vm::handler_4;
// 또 이하 생략

}

// 호출할 때
uint32_t ret = handler[3](this, true, 0x1000);
// handler가 불리는 위치가 클래스 내가 아니라면 this를 적당히 바꿔줘야겠지


크리에이티브 커먼즈 라이센스
Creative Commons License
2010/01/11 03:50 2010/01/11 03:50
Posted by 호빵

고민중

삽질일기 2010/01/09 17:29

C에서는 어렵겠지만 C++에서 이름으로 변수를 만드는 건 어려운 일이 아니다.

std::map<std::string, int> variable_map;

void set_variable(const std::string& str, int value)
{
    variable_map[str] = value;
}

int get_variable(const std::string& str)
{
    return variable_map[str];
}

거의 꼼수 수준이긴 하지만. (느리기도 하겠고)

문제는, 지금 하고 싶은 것은 "a"라는 변수를 읽을 때마다 "handler_a" 라는 함수를 호출하고 싶다는 것이다. 앞의 handler_는 다 똑같다고 봤을 때, 결국 문제는 함수 이름으로 함수를 호출할 수 있느냐는 것이다.

C++을 버리면 간단하겠지만 그러지 않는 편이 좋으니까..

고민 답 나오면 추가함. :$

more..


크리에이티브 커먼즈 라이센스
Creative Commons License
2010/01/09 17:29 2010/01/09 17:29
Posted by 호빵

아.. 혼자 삽질했다.

    lua_State *L = lua_open();

이 단 한줄의 코드를 링크할때 제목과 같은 에러가 나는데,

물론 라이브러리 링크를 까먹을만큼 내가 나사 빠진 인간은 아니고..

이유는 간단했다. C++ 소스에서 헤더를 그냥 불러왔더니 저렇게 된 것이다.

extern "C" {
#include<lua.h>
#include<lauxlib.h>
#include<lualib.h>
}

상식있게 살자.

..이건 진짜 삽질일기로구만.

크리에이티브 커먼즈 라이센스
Creative Commons License
2009/12/25 20:55 2009/12/25 20:55
Posted by 호빵

아.. 워드프레스도 나름의 장점은 있긴한데
난 못써먹겠다.

그러므로 텍스트큐브로 귀환 ㄱ

아무튼,

JUnit이라는 것의 사용법을 a부터 z까지 전혀 친절하지 않게 대강대강 스샷첨부해서 올려놓도록 하것다

펼치기


크리에이티브 커먼즈 라이센스
Creative Commons License
2009/09/11 21:05 2009/09/11 21:05
Posted by 호빵

웬지 간단하면서도 헷갈리기 쉬운 개념이지만, 사실은 아주 단순하다.

배타적 OR은 논리회로에만 등장하는 말이 아니라, 실생활에도 아주 흔하게 쓰이는 개념이다.


포괄적 OR(inclusive OR)과 비교해보자.

포괄적 OR은 둘 중 아무거나라는 개념이다. 예를 들면 어떤 회의장에서

A형 카드나 B형 카드를 가지신 분은 입장하실 수 있습니다.

라고 했다고 치면, A형 카드나 B형 카드 둘 중 어느 하나라도 가진 사람은 입장할 수 있다.

물론 두 카드를 다 가지고 있다고 해도 입장엔 아무 문제 없다.


그러나 배타적 OR은 다르다. 둘 중 하나이다.

음식점에서

후식으로 커피, 쥬스 중 하나를 선택하실 수 있습니다. 어떤 것으로 드릴까요?

라고 한다면 손님은 둘 중 하나를 선택해야만 한다.

물론 후식을 먹지 않을 수도 있을 것이다. 하지만 둘 다는 안된다. 음식점에서 주지 않으니까.

그래서 Exclusive OR이다.


내가 헷갈려서 이런 글을 쓴다는 건 비밀이다.

크리에이티브 커먼즈 라이센스
Creative Commons License
2009/03/10 12:48 2009/03/10 12:48
Posted by 호빵
TAG , , ,

위키 설치

삽질일기 2008/09/16 15:16

http://hoppang.net/wiki

위키도 쓰고 블로그도 쓰는거지

비싼돈 주고 호스팅하는데.

크리에이티브 커먼즈 라이센스
Creative Commons License
2008/09/16 15:16 2008/09/16 15:16
Posted by 호빵

만들고 있는거 스샷만 한장 공개함

다 맹글면 공개함



사용자 삽입 이미지

크리에이티브 커먼즈 라이센스
Creative Commons License
2008/08/19 00:22 2008/08/19 00:22
Posted by 호빵