반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

지난번 글에 getDecodedStream 까지 분석 했습니다.

그 글 올린지 일주일이 지났네요.
회사에서 다른 일을 하느라 이 부분 분석을 못했는데요.
그 일이 어느정도 마무리 됐으니 다시 마저 분석에 들어가야 겠습니다.


지난번 다루다 끝났던 getDecodedStream 함수를 보면요.$key값이  ASCIIHexDecode, ASCII85Decode 그리고 FlateDecode 냐에 따라서 실행하는 함수가 달랐습니다.

제가 테스트 하는 PDF 문서는 FlateDecode 를 사용하더라구요.


그러면 

            if ($key == "FlateDecode"){
                $_stream = decodeFlate($_stream);
                echo $_stream . "<p>";
                }

가 실행이 될 텐데요.


그 결과값을 미리 브라우저에 찍어 봤습니다.





뭐 이런게 찍히네요.

지금까지 쪼개고 쪼개고 쪼갠 값은 $_stream 의 값을 해당 함수에 넣고 돌려서 얻은 결과가 위 데이터입니다.

사람이 볼 수 있는 데이터가 되려면 아직 멀어보이네요.

그러면 decodeFlate($_stream) 을 살펴 보겠습니다.


function decodeFlate($input) {
    return @gzuncompress($input);
}



뭐 이 함수는 아주 간단합니다. 다른 decodeAsciiHex($_stream) 이나 decodeAscii85($_stream) 은 그래도 뭔가 로직이 있는데 이 함수는 달랑 @gzuncompress() 메소드만 사용했네요.

이 메소드를 알아보겠습니다.

gzuncompress() 메소드의 PHP 매뉴얼을 보면 This function uncompress a compressed string. 라고 돼 있습니다. 그러니까 이 함수는 압축된 string 을 압축해제 하는 함수라고 합니다.

지금까지 작업한 $_stream 을 압축해제하면 저 위에 있는 화면 같은 데이터가 추출 되는군요.


<?php
$compressed   
gzcompress('Compress me'9);
$uncompressed gzuncompress($compressed);
echo 
$uncompressed;
?>


위 코드를 실행 해 보세요. 그러면 Compress me 그대로 출력 될 겁니다. 압축했다가 다시 압축을 풀었으니까요.

그럼 이제 어디로 가야 될까요? 1주일이 지나서 감이 멀어졌는데. 일단 getDecodedStream 함수에서 일을 처리하고 return 하는 부분까지 했으니까 이 함수를 호출했던 pdf2text() 함수로 다시 가야겠죠.


$data = getDecodedStream($stream, $options);


이 부분이었습니다. 저 $data 변수에는 아까 브라우저에 출력했던 그 이상한 데이터가 담겨져 있을 겁니다. $_stream 의 압축을 푼 데이터죠.

그 다음 소스는 아래 내용입니다.


            if (strlen($data)) {
                if (preg_match_all("#BT(.*)ET#ismU", $data, $textContainers)) {
                    $textContainers = @$textContainers[1];
                    getDirtyTexts($texts, $textContainers);

                } else
                    getCharTransformations($transformations, $data);
            }


strlen 함수는 C언어에서도 똑같이 쓰는 것 같은데요. 문자열의 길이를 구하는 함수입니다.

그러니까 strlen($data) 는 $data 의 길이를 구하는거고 0 이면 데이터가 없다는 겂니다. 그러면 PHP는 0 을 false 로 취급하니까 이 if 문을 처리하지 않고 건너 뛸 겁니다.

$data 에 값이 있다면 그것이 길던 짧던 상관 안하고 if 문 안의 코드를 실행합니다.

그 다음은 다시 정규식 표현을 사용하는 preg_match_all 함수가 나오네요.


$data를 BT, ET 등으로 구분해서 $textContainers 에 넣는 것 같습니다.

BT, ET 는 아까 뽑았던 이상한 데이터들에 많이 있습니다. 잘은 모르겠지만 그냥 통박을 굴려보면 Begin Text, End Text 의 준말이 아닐까 생각되네요.

그 다음에 @가 나오는데요. 이건 PHP 에서 에러 관련해서 처리하도록 하는 부호입니다.


<?php
/* Intentional file error */
$my_file = @file ('non_existent_file') or
    die (
"Failed opening file: error was '$php_errormsg'");

// this works for any expression, not just functions:
$value = @$cache[$key];
// will not issue a notice if the index $key doesn't exist.

?>


위에 관련 예제가 있습니다.

그 다음에는 getDirtyTexts($texts, $textContainers); 가 나옵니다.


새로운 함수 호출인데요. 두번째 인자는 방금 뽑아낸 $textContainers 변수를 전달하고 첫번째 인자는 pdf2text 초반에 만들어 뒀던 배열변수네요.

이 변수에 아직 아무 값도 안 담겼던 것 같은데...


그럼 이 호출된 함수를 볼까요?

function getDirtyTexts(&$texts, $textContainers) {
    for ($j = 0; $j < count($textContainers); $j++) {
        if (preg_match_all("#\[(.*)\]\s*TJ#ismU", $textContainers[$j], $parts))
            $texts = array_merge($texts, @$parts[1]);
        elseif(preg_match_all("#Td\s*(\(.*\))\s*Tj#ismU", $textContainers[$j], $parts))
            $texts = array_merge($texts, @$parts[1]);
    }
}


짧은 함수네요.

$textContainers 의 수만큼 for 문을 돌리는데 다시 preg_match_all 를 사용해서 $textContainers 파편들을 '#\[(.*)\]\s*TJ#ismU' 이 정규식 형식에 맞게 구분을 해서 $parts 에 집어넜습니다.


아까 받았던 $texts 에는 이 값들을 계속 차곡차곡 쌓아놓네요.

array_merge() 함수를 사용해서인데요. 이 함수는 한개 이상의 배열을 합하는 함수입니다.

elseif 문 안에도 똑 같은 일을 하죠. 다만 구분하는 정규표현식이 다를 뿐이죠.

즉 이 함수는 BT, ET 별로 쪼갠 값을 다시 위 정규표현식에 맞게 쪼개서 $texts 에 담는 함수입니다.


그 다음은 다시 pdf2text 함수로 돌아가야 되는데요.

BT,ET 로 나누지 않을 경우는 getCharTransformations 함수를 사용하네요.

이 함수부터는 다음 글에서 다룰께요.

마무리 하면서 getDirtyTexts($texts, $textContainers); 바로 밑에 아래 코드를 추가해 봤습니다.


                    for ($k = 0; $k < count($texts); $k++) {
                        echo $texts[$k] . "<br>";
                    }


바로 지금까지 만든 $texts 내용을 찍어 본 건데요.

아래 내용입니다.



이제 조금 사람이 알아볼 수 있는 글들이 나타나기 시작했습니다.


(W)-36(e)7(e)7(k )46(o)7(f) 에는 Week of  가 있죠?

그 중간에 숫자는 뭔지 잘 모르겠지만요. 빈괄호 ()는 space 일까요?


(Oct)-11(o)5(ber )10(1)4( ) 는 October 1 하고 빈괄호가 있네요.

이제 뭔가 보이기 시작합니다.

그럼 다음 시간에는 이 데이터를 마저 decode 해 보겠습니다.





반응형