お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"CAB形式のファイル圧縮・解凍"

この発言に対し以下のコメントが寄せられています
#00819 河邦 正 さん RE:CAB形式のファイル圧縮・解凍
#01338 河邦 正 さん RE:CAB形式のファイル圧縮・解凍

【タイトル】CAB 形式の書庫にファイルを圧縮・解凍する例です。  発言行数の制限をクリアするため、見苦しい部分があります。また、最低限 のコードしか含まれていません。本来は設定することが望ましい部分も一部が 省略されています。  このサンプルコードは C/C++用の SDK を読解する‘手がかり’として読ん でください。アプリケーションを構築・配布するためには、必ず SDK を読む ことをお勧めします。  でも肝心の SDK の URL が思い出せないので、どなたかコメントでフォロー していただけると助かります(^^;。   interface // ここから Interface部に書くコードです type // 使用する構造体などの定義 TERF = record erfOper, erfType: Integer; fError: BOOL; end; PERF = ^TERF; TCCAB = record cb, cbFolderThresh: ULONG; cbReserveCFHeader, cbReserveCFFolder, cbReserveCFData: UINT; iCab, iDisk, fFailOnIncompressible: Integer; setID: WORD; szDisk, szCab, szCabPath: array[0..255] of Char; end; PCCAB = ^TCCAB; TFDICABINETINFO = record cbCabinet: Longint; cFolders, cFiles, setID, iCabinet: WORD; fReserve, hasprev, hasnext: BOOL; end; TFDINOTIFICATIONTYPE = (fdintCABINET_INFO, fdintPARTIAL_FILE, fdintCOPY_FILE, fdintCLOSE_FILE_INFO, fdintNEXT_CABINET, fdintENUMERATE); PFDICABINETINFO = ^TFDICABINETINFO; TFDIERROR = (FDIERROR_NONE, FDIERROR_CABINET_NOT_FOUND, FDIERROR_NOT_A_CABINET, FDIERROR_UNKNOWN_CABINET_VERSION, FDIERROR_CORRUPT_CABINET, FDIERROR_ALLOC_FAIL, FDIERROR_BAD_COMPR_TYPE, FDIERROR_MDI_FAIL, FDIERROR_TARGET_FILE, FDIERROR_RESERVE_MISMATCH, FDIERROR_WRONG_CABINET, FDIERROR_USER_ABORT); TFDINOTIFICATION = record cb: Longint; psz1, psz2, psz3: PChar; pv: Pointer; hf: Integer; date, time, attribs, setID, iCabinet, iFolder: WORD; fdie: TFDIERROR; end; PFDINOTIFICATION = ^ TFDINOTIFICATION; // Cabinet.DLL から呼び出す関数の定義 function FCICreate(var erf:TERF; fnFiledest, fnAlloc, fnFree, fnOpen, fnRead, fnWrite, fnClose, fnSeek, fnDelete, fnfcigtf: Pointer; var ccab: TCCAB; pv: Pointer): THandle; cdecl; function FCIDestroy(THandle: THandle): BOOL; cdecl; function FCIAddFile(THandle:THandle; pszSourceFile, pszFileName:PChar; fExecute: BOOL; pfnfcignc, pfnfcis, pfnfcigoi: Pointer; typeCompress: WORD):BOOL; cdecl; function FCIFlushCabinet(THandle: THandle; fGetNextCab: BOOL; pfnfcignc, pfnfcis: Pointer): BOOL; cdecl; function FCIFlushFolder(fci: THandle; GetNextCab, pfnProgress: Pointer): BOOL; cdecl; function FDICreate(fnAlloc, fnFree, fnOpen, fnRead, fnWrite, fnClose, fnSeek: Pointer; cpuType: Integer; var erf: TERF): THandle; cdecl; function FDIDestroy(THandle: THandle): BOOL; cdecl; function FDIIsCabinet(THandle: THandle; hf: Integer; pfdici: PFDICABINETINFO): BOOL; cdecl; function FDICopy(THandle:THandle; pszCabinet:PChar; pszCabPath:PChar; flags: Integer; pfnfdin, pfnfdid: Pointer; pvUser: Pointer): BOOL; cdecl; implementation // ここから Implementation部に書くコードです // Cabinet.DLL から呼び出す関数の定義 const CAB_DLL = 'CABINET.DLL'; function FCICreate; external CAB_DLL name 'FCICreate'; function FCIDestroy; external CAB_DLL name 'FCIDestroy'; function FCIAddFile; external CAB_DLL name 'FCIAddFile'; function FCIFlushCabinet; external CAB_DLL name 'FCIFlushCabinet'; function FCIFlushFolder; external CAB_DLL name 'FCIFlushFolder'; function FDICreate; external CAB_DLL name 'FDICreate'; function FDIDestroy; external CAB_DLL name 'FDIDestroy'; function FDIIsCabinet; external CAB_DLL name 'FDIIsCabinet'; function FDICopy; external CAB_DLL name 'FDICopy'; // ここから、コンテキスト構築に用いるコールバック関数の例です function fnFilePlaced(var ccab:TCCAB; pszFile:PChar; cbFile:Longint; fContinuation: BOOL; pv: Pointer): THandle; cdecl; begin Result := 0; end; function fnAlloc(Size: ULONG): Pointer; cdecl; begin GetMem(Result, Size); end; procedure fnFree(memory: Pointer); cdecl; begin FreeMem(memory); end; function fnOpen(pszFile: PChar; oflag: Integer; pmode: Integer; err: PInteger; pv: Pointer): Integer; cdecl; const O_RDONLY = $0000; O_WRONLY = $0001; O_RDWR = $0002; O_CREAT = $0100; O_EXCL = $0400; var Style: UINT; os: OFSTRUCT; begin if(oflag and O_CREAT) <> 0 then Style := OF_CREATE else case(oflag and 3)of 0: Style := OF_Read; 1: Style := OF_Write; else Style := OF_ReadWrite; end; if(oflag and O_EXCL) <> 0 then Style := Style or OF_Share_Exclusive; Result := OpenFile(pszFile, os, Style); // 行数節約して旧APIを使用 end; function fnRead(hf:Integer; memory:Pointer; cb:UINT; err:PInteger; pv: Pointer): UINT; cdecl; begin Result := _lread(hf, memory, cb); end; function fnWrite(hf:Integer; memory:Pointer; cb:UINT; err:PInteger; pv: Pointer): UINT; cdecl; begin Result := _lwrite(hf, memory, cb); end; function fnClose(hf: Integer; err, pv: Pointer): Integer; cdecl; begin Result := _lclose(hf); end; function fnSeek(hf: Integer; dist: Longint; seektype: Integer; err: PInteger; pv: Pointer): Longint; cdecl; begin Result := _llseek(hf, dist, seektype); end; function fnDelete(pszFile: PChar; err: PInteger; pv: Pointer): Integer; cdecl; begin Result := Integer(DeleteFile(pszFile)); end; function fnFciGTF(pszTempName: PChar; cbTempName: Integer; pv: Pointer): BOOL; cdecl; var pPath: array[0..255]of Char; begin Result := (GetTempPath(sizeof(pPath), pPath) <> 0) and (GetTempFileName(pPath, 'cab', 0, pszTempName) <> 0); end; function fnGetNextCabinet(var ccab: TCCAB; cbPrevCab: ULONG; pv: Pointer): BOOL; cdecl; begin // この部分は手抜きです。ごめんなさい。 end; function fnStatus(typeStatus: UINT; cb1, cb2: ULONG; pv: Pointer): Longint; cdecl; begin // この部分は手抜きです。ごめんなさい。 end; function fnOpenInfo(pszName:PChar; var pDate:WORD; var pTime:WORD; var pAttrib: WORD; err: PInteger; pv: Pointer): Integer; cdecl; var os: OFSTRUCT; begin // 本来はここでファイルの属性なども取得します Result := OpenFile(pszName, os, OF_READ); end; // 簡単に利用するために2つの関数にまとめてみました // CabinetAddFiles :リスト中のファイルを CAB に圧縮します // CabinetExtractFile :CAB からファイルを解凍します procedure CabinetAddFiles(Cabinet: string; Files: TStrings); var fci: THandle; erf: TERF; ccab: TCCAB; i: Integer; begin ZeroMemory(@erf, sizeof(erf)); ZeroMemory(@ccab, sizeof(ccab)); with ccab do begin cb := $1000000; StrPCopy(szDisk, 'DISK1'); StrPCopy(szCab, PChar(ExtractFileName(Cabinet))); StrPCopy(szCabPath, PChar(ExtractFilePath(Cabinet))); end; // コンテキストの構築にコールバック関数を用います fci := FCICreate(erf, @fnFilePlaced, @fnAlloc, @fnFree, @fnOpen, @fnRead, @fnWrite, @fnClose, @fnSeek, @fnDelete, @fnFciGTF, ccab, nil); if fci <> 0 then try for i := 0 to Files.Count -1 do // ファイル名と別な名前を指定して格納することもできます // 圧縮形式は MS-ZIP にしています(最後の引数 1)。 if FCIAddFile(fci, PChar(Files[i]), PChar(Files[i]), FALSE, @fnGetNextCabinet, @fnStatus, @fnOpenInfo, 1) = FALSE then ShowMessage('ERROR: FCIAddFile'); if FCIFlushCabinet(fci, FALSE, @fnGetNextCabinet, @fnStatus) = FALSE then ShowMessage('ERROR: FCIFlushCabinet'); finally // 使用済みコンテキストの破棄 FCIDestroy(fci); end; end; procedure CabinetExtractFile(Cabinet, Item, ExtractName: string); function fnFDINotify(fdint: TFDINOTIFICATIONTYPE; pfdin: PFDINOTIFICATION): Integer; cdecl; var os: OFSTRUCT; begin case(fdint)of fdintCOPY_FILE: if CompareText(pfdin^.psz1, Item) = 0 then Result := OpenFile(PChar(ExtractName), os, OF_CREATE) else Result := 0; fdintCLOSE_FILE_INFO: begin // 本来はここでファイルの属性などを設定します _lclose(pfdin^.hf); pfdin^.cb := 1; // continue Result := 1; // こっちが continue の指定? end; else // できれば他の NotificationType にも応答する方が良いはず Result := 0; end; end; var fdi: THandle; erf: TERF; begin ZeroMemory(@erf, sizeof(erf)); // コンテキストの構築にコールバック関数を用います fdi := FDICreate(@fnAlloc, @fnFree, @fnOpen, @fnRead, @fnWrite, @fnClose, @fnSeek,-1, erf); if fdi <> 0 then try FDICopy(fdi, PChar(ExtractFileName(Cabinet)), PChar(ExtractFilePath(Cabinet)), 0, @fnFDINotify, nil, nil); finally // 使用済みコンテキストの破棄 FDIDestroy(fdi); end; end; // 以下はボタンのイベントハンドラに用いる例です。 // 2個のファイル(FCI.H & FDI.H)を TEST.CAB に圧縮します procedure TForm1.Button1Click(Sender: TObject); var Files: TStringList; begin Files := TStringList.Create; Files.Add('FCI.H'); Files.Add('FDI.H'); CabinetAddFiles('TEST.CAB', Files); Files.Free; end; // TEST.CAB から2個のファイル(FCI.H & FDI.H)を解凍します procedure TForm1.Button2Click(Sender: TObject); begin // 拡張子を *.TXT に変更して解凍します CabinetExtractFile('TEST.CAB', 'FCI.H', 'FCI.TXT'); CabinetExtractFile('TEST.CAB', 'FDI.H', 'FDI.TXT'); end; P.S.  私自身もCABを使いはじめたばかりなので、質問されても「SDKを 読んでね」としか答えられない場合があります。ご容赦ください。 1999/02/10、河邦 正(GCC02240@nifty.ne.jp) Original document by 河邦 正 氏 ID:(GCC02240)



ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum