読者です 読者をやめる 読者になる 読者になる

Mac版Internet ExplorerのWebアーカイブを分解するAppleScript その2

前回はファイル形式について記述したので、今回はファイル展開方法について。

 

1.WAFファイルと同じ階層に新規フォルダを作成する。フォルダ名はWAFファイル名に「 waff folder」を追加したもの。

2.WAFファイルを読み込みながら、「url 」と「data」を取り出して別ファイルに書き出していく。この時のファイル名およびパスは、urlから取得してwaff folderからの相対パスにします。

3.トップページへのエイリアス・ファイルを作成する。

4.すべてのファイルの作成日をWAFファイルの作成日に変更する。

 

再現の難しいサイト

リンクがCGIで構築されているサイト。CGIは追跡していない。よって、ファイルがあってもリンク切れと認識されている可能があります。

例)http://www.hoge.co.jp/cgi-bin/common/hage.cgi?http://www.hoge.co.jp/news/200204/03/fuge.html

 

巨大なエイリアス・ファイルの問題

どうやら、OSX 10.7 Lion以降はエイリアスのファイルサイズが大きく、自分の環境では1.5MBまでになってます。WAFファイルが数十KBなのに、waff folder内は1MB越えなんてアホな状況です。気になる方は、エイリアスを削除してください。

 

使い方

下のスクリプトをドロップレットで保存して下さい。

それにWAFファイル(複数可)をドロップする。

 

waff folderの直下にあるエイリアス・ファイルを開けば、SafariなどでWebページが開きます。

 

waffspliter.scpt 

 

(*
waffを読み込み分解するスクリプト
入力ファイル(waff形式)と同じフォルダ階層に、拡張子なしの入力ファイル名と同じ名称のフォルダを
作成し、入力ファイル内のアーカイブを分解して書き出す。
*)

on
open theList
    
toControl(theList)
end
open

on
run
    
choose file with prompt "Webアーカイブ・ファイルを選んでください" without invisibles
    
toControl({result})
end
run

on
adding folder items to theFolder after receiving theList
    
toControl(theList)
end
adding folder items to

on
toControl(theList)
    repeat with
curItem in theList
        set
theFileInfo to info for curItem
        if (
folder of theFileInfo) is true then
            
--folder
        else
            try
                
--item
                
wafsplit(curItem) of me
            on error
                
display alert "異常発生" message POSIX path of curItem as warning
            end try
        end if
        
    end repeat
    
    
--処理終了の通知
    if (
count of theList) is 1 then
        
display notification name of (info for first item of theList) with title "End of work" sound name "beep"
    else
        set
msg to (count of theList) & " Files" as string
        
display notification msg with title "End of work" sound name "beep"
        
    end if
end
toControl


on
wafsplit(theFile)
    
    
--作業フォルダ名称の初期化
    set
theWorkFolder to ""
    
--最初のURL(ファイル)の初期化
    set
theFirstFile to ""
    set
typeList to {}
    
    
--WAFFの分解ループ
    set
fp1 to open for access theFile
    try
        set
fileSize to get eof fp1
        set
readSize to 0
        
        
--ファイルサイズの確認
        if
fileSize is less than 12 then
            
display alert "サイズ不正です" message POSIX path of theFile
            
close access fp1
            return
        end if
        
        
--ヘッダーのデータタイプを読む
        set
dataType to read fp1 for 4 as text
        set
readSize to readSize + 4
        
        
--ファイル形式の確認
        if
dataType is not ".WAF" then
            
display alert "処理対象外ファイルです" message POSIX path of theFile
            
close access fp1
            return
        end if
        
        
--ヘッダーのデータサイズを読む
        set
dataSize to read fp1 for 4 as integer
        set
readSize to readSize + 4
        
        
--ヘッダーのデータ内容を読む(dataSizeは8バイト減算)
        set
dataContents to read fp1 for dataSize - 8 as data
        set
readSize to readSize + dataSize - 8
        
        
log "debug dataType=" & dataType & " readSize=" & readSize & " fileSize=" & fileSize
        
        
--作業フォルダの作成
        set
theWorkFolder to makeWorkFolder(theFile) of me
        
        
        
        set
theUrl to ""
        
        repeat while
readSize is less than fileSize
            
            
            
--データタイプを読む
            set
dataType to read fp1 for 4 as text
            set
readSize to readSize + 4
            
            
--データサイズを読む
            set
dataSize to read fp1 for 4 as integer
            set
readSize to readSize + 4
            
            if
dataType is "mime" then
                
--データ内容を読む
                set
dataContents to read fp1 for dataSize as text
                set
readSize to readSize + dataSize
            else if
dataType is "url " then
                
--データ内容を読む
                set
dataContents to read fp1 for dataSize - 1 as text -- null除外
                set
readSize to readSize + dataSize
                set
theUrl to dataContents
                set
dataContents to read fp1 for 1 as text -- null分進める
            else if
dataType is "ntry" then
                
--データ内容を読む(dataNtryへ格納)
                set
dataContents to read fp1 for dataSize - 8 as data
                set
dataNtry1 to read fp1 for 4 as integer
                set
dataNtry2 to read fp1 for 4 as integer
                set
dataNtry to dataNtry1 - dataNtry2 - 128
                set
readSize to readSize + dataSize
            else if
dataType is "data" then
                
--データ内容を読む(dataNtryのサイズより)
                set
dataSize to dataNtry
                set
dataContents to read fp1 for dataSize as data
                set
readSize to readSize + dataSize
                
--ファイルを保存
                
log "debug theUrl=" & theUrl & " readSize=" & readSize
                if
theUrl is not "" then
                    set
theNewFile to saveFile(theWorkFolder, theUrl, dataContents)
                    
--最初のURLを記憶
                    if
theFirstFile is "" then
                        set
theFirstFile to theNewFile
                    end if
                    set
theUrl to ""
                else
                    
--データ構造がおかしい場合しか、ありえない。
                    
display alert "URLが見当たらない" message "POS=" & readSize as warning
                    
close access fp1
                    return
                    
                end if
            else if
dataType is "post" then
                
--データ内容を読む(XXXXを含む)
                set
dataContents to read fp1 for dataSize as data
                set
readSize to readSize + dataSize
                set
dataSize to 128
                set
dataContents to read fp1 for dataSize as text
                set
readSize to readSize + dataSize
            else
                set end of
typeList to dataType
                
--データ内容を読む
                set
dataContents to read fp1 for dataSize as data
                set
readSize to readSize + dataSize
            end if
            
            
log "debug unknown dataType=" & typeList as string
            
log "debug readSize=" & readSize & " fileSize=" & fileSize
        end repeat
    on error
errMsg number errNum
        
close access fp1
        
display alert errMsg & "code=" & errNum as warning
        
--        if errNum is -39 then
        
--            log "debug readSize=" & readSize & " fileSize=" & fileSize
        
--        end if
        error
errMsg number errNum
    end try
    
    
close access fp1
    
    
--閲覧開始用のエイリアス作成
    if
theFirstFile is not "" then
        
saveEntryShortcut(theWorkFolder, theFirstFile)
    end if
    
    
--ファイル日付の修正(全体)
    
setAllFileDate(theWorkFolder, theFile)
    
end
wafsplit


on
saveFile(theWorkFolder, theUrl, theData)
    
    
--URLをフルパスのファイル名に変換
    set
theFilename to filenameFromUrl(theUrl) of me
    
--作業フォルダの下にフルパスのフォルダを作成
    
do shell script "cd " & quoted form of POSIX path of theWorkFolder & " &&" & "mkdir -p " & "./`dirname " & quoted form of theFilename & "`"
    
    
--ファイル名に作業フォルダのパスを追加
    set
theNewFile to theWorkFolder & strings 2 thru end of replaceText(theFilename, "/", ":") as string
    
    
--ファイルが既にある場合、リターンする
    tell
application "Finder"
        set
theExists to exists file theNewFile
    end tell
    if
theExists is yes then
        return
    end if
    
    
--ファイルの書き込み
    set
fp to open for access theNewFile write permission yes
    try
        
write theData to fp as data
    on error
errMsg number errNum
        
close access fp
        
display alert errMsg & "code=" & errNum as warning
        error
errMsg number errNum
    end try
    
close access fp
    
    return
alias theNewFile
end
saveFile

on
filenameFromUrl(theUrl)
    
    set
pos to (offset of "://" in theUrl) + (length of "://")
    set
parmPos to (offset of "?" in theUrl)
    set
theFilename to text pos thru (parmPos - 1) of theUrl
    
--set theFilename to replaceText(theFilename, "/", "_") of me
    set
theFilename to "/" & theFilename
    
--ディレクトリの場合は、index.htmlを想定する
    if
theFilename ends with "/" then
        set
theFilename to theFilename & "index.html"
    end if
    
    return
theFilename
end
filenameFromUrl

on
makeWorkFolder(theFile)
    
    
--拡張子の取り出し
    set
fileInfo to info for theFile
    if
name extension of fileInfo is not missing value then
        set
theExtension to "." & name extension of fileInfo
    else
        set
theExtension to ""
    end if
    
--theFileによるフォルダ名作成
    set
theBaseFolder to do shell script "basename " & quoted form of POSIX path of theFile & " " & quoted form of theExtension
    if
theBaseFolder is "" then
        
display alert "フォルダ名の生成失敗" message POSIX path of theFile as warning
        return ""
    end if
    set
theBaseFolder to theBaseFolder & " waff folder"
    
    tell
application "Finder"
        set
theNewFolder to make new folder at alias ((theFile as string) & "::") with properties {name:theBaseFolder}
        set
theNewFolder to theNewFolder as string -- Finderのfile形式なのでstringに変換
    end tell
    
    
--作成日付の修正
    
setFileDate(theNewFolder as alias, theFile as alias)
    
    return
alias theNewFolder
end
makeWorkFolder

on
saveEntryShortcut(theWorkFolder, theEntryFile)
    
    set
fileInfo to info for theEntryFile
    
    
--theEntryFile に拡張子がなくTEXTファイルの時は、.htmlを追加。
    if
name extension of fileInfo is missing value then
        tell
application "Finder"
            set
name extension of file theEntryFile to "html"
        end tell
    end if
    
    tell
application "Finder"
        set
theNewFile to make new alias at folder theWorkFolder to theEntryFile with properties {name:name of fileInfo}
        set
theNewFile to theNewFile as string -- Finderのfile形式なのでstringに変換
    end tell
    
    return
alias theNewFile
end
saveEntryShortcut

(*ファイル日付の全体設定*)
on
setAllFileDate(theFolder, theSourceFile)
    set
theCommand1 to "x=`/Developer/Tools/GetFileInfo -d " & quoted form of POSIX path of theSourceFile & "`"
    set
theCommand2 to "cd " & quoted form of POSIX path of theFolder
    set
theCommand3 to "find . -print0 | xargs -0 /Developer/Tools/SetFile -d \"$x\""
    set
theCommand to theCommand1 & " && " & theCommand2 & " && " & theCommand3
    
do shell script theCommand
end
setAllFileDate

--定番関数
(*ファイル日付の設定*)
on
setFileDate(theFile, theSourceFile)
    set
theCommand to "x=`/Developer/Tools/GetFileInfo -d " & quoted form of POSIX path of theSourceFile & "` && " & "/Developer/Tools/SetFile -d \"$x\" " & quoted form of POSIX path of theFile
    
do shell script theCommand
end
setFileDate


(*文字列の置換*)
on
replaceText(theText, serchStr, replaceStr)
    set
tmp to AppleScript's text item delimiters
    set
AppleScript's text item delimiters to serchStr
    set
theList to every text item of theText
    set
AppleScript's text item delimiters to replaceStr
    set
theText to theList as string
    set
AppleScript's text item delimiters to tmp
    return
theText
end
replaceText


 

実行結果

f:id:tbboy:20140522050520p:plain

 

デバッグコードも入ってるけど、気にしない。

 

動作環境

OSX 10.9.2以降

Xcode(/Developer/Tools/)

 

実行環境

Finder 10.9.2/Apple/iMac10,1/OSX 10.9.2