CでExcelを読む
Excelのファイルフォーマット
OLE複合ドキュメントというフォーマットの中に、BIFFと言うフォーマットが入っている。
OLE 複合ドキュメントを扱うライブラリ
http://linux.softpedia.com/get/Programming/Libraries/POLE-1528.shtml
OLE 複合ドキュメント資料
ソース
cotinueレコードに対応していないので、文字が完全に表示されず、
エラーになることもある。(データが途切れてしまうため)
#include <iostream> #include <fstream> #include <stdlib.h> #include <stdio.h> #include <list> #include <string> #include<iconv.h> #include "pole.h" void convertUnicode2Shiftjis(char *to, char *from, size_t outsiz) { // iconvを開く iconv_t it = iconv_open("SHIFT_JIS", "UTF-16LE"); if (it == (iconv_t)-1) { perror("iconv_open失敗"); exit(1); } // 変換する char *outstr = to; const char *instr = from; size_t insiz = outsiz; size_t siz = iconv(it, &instr, &insiz, &outstr, &outsiz); if (siz == -1) { perror("iconv_open失敗"); exit(1); } // iconvを閉じる iconv_close(it); } void dumpSST(POLE::Stream* stream, unsigned short datalength) { unsigned long length = 0; unsigned short stringSize = 0; unsigned short SSTSize = 0; unsigned long extstrSize = 0; unsigned char flag = 0; unsigned short fontSize = 0; // SSTレコードとEXTSSTレコードに格納される文字列数の合計をスキップ stream->seek( stream->tell() + 4); // STTに格納される文字数 if (stream->read( (unsigned char *)&SSTSize, 4 ) != 4) return; while (datalength > length) { // 文字数(バイト数ではない!!) if (stream->read( (unsigned char *)&stringSize, 2 ) != 2) return; length += 2; // フラグ if (stream->read( &flag, 1 ) != 1) return; length += 2; // フォント情報個数 if (flag & 8) { if (stream->read( (unsigned char *)&fontSize, 2 ) != 2) return; length += 2; } // 拡張文字情報数 if (flag & 4) { if (stream->read( (unsigned char *)&extstrSize, 4 ) != 4) return; length += 4; } // 文字列読み込み if (flag & 1) { // unicodeが格納されている unsigned char *buffer = new unsigned char[stringSize * 2 + 2]; memset(buffer, 0, stringSize * 2 + 2); if (stream->read( buffer, stringSize * 2 ) != stringSize * 2) return; length += stringSize * 2; char *out = new char[stringSize *2 + 1]; memset(out, 0, stringSize * 2 + 1); convertUnicode2Shiftjis(out, (char *)buffer, stringSize * 2); printf("%s\n", out); delete[] out; delete[] buffer; } else { // hibitをとったunicodeが格納されている unsigned char *buffer = new unsigned char[stringSize + 1]; memset(buffer, 0, stringSize + 1); if (stream->read( buffer, stringSize ) != stringSize) return; length += stringSize; printf("%s\n", buffer); delete[] buffer; } // フォント情報スキップ if (flag & 8) { // IDをskip stream->seek( stream->tell() + 4 * fontSize); length += 4 * fontSize; } // 拡張文字情報スキップ if (flag & 4) { // IDをskip stream->seek( stream->tell() + extstrSize); length += extstrSize; } } } void dumpExcel(POLE::Stream* stream) { unsigned char buffer[16]; unsigned short recordID = 0; unsigned short dataSize = 0; while (!stream->eof()) { if (stream->read( (unsigned char *)&recordID, 2 ) != 2) return; if (stream->read( (unsigned char *)&dataSize, 2 ) != 2) return; if (recordID == 0xfc) { // SSTレコードのみ調べる dumpSST(stream, dataSize); } else { stream->seek( stream->tell() + dataSize); } } } int main(int argc, char *argv[]) { if( argc < 2 ) { return 0; } POLE::Storage* storage = new POLE::Storage( argv[1] ); storage->open(); if( storage->result() != POLE::Storage::Ok ) { std::cout << "Error on file " << argv[1] << std::endl; return 1; } std::list<std::string> entries= storage->entries( "/" ); for(std::list<std::string>::iterator it = entries.begin(); it != entries.end(); ++it ) { POLE::Stream* ss = new POLE::Stream( storage, "/" + *it ); if (*it == "Workbook") { dumpExcel(ss); } delete ss; } delete storage; return 0; }