diff --git a/jni/Android.mk b/jni/Android.mk index e7814b67f..2a0c623ae 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -133,6 +133,8 @@ LOCAL_SRC_FILES := \ NativeFormats/fbreader/src/formats/doc/OleStream.cpp \ NativeFormats/fbreader/src/formats/doc/OleStreamReader.cpp \ NativeFormats/fbreader/src/formats/doc/OleUtil.cpp \ + NativeFormats/fbreader/src/formats/doc/DocInlineImageReader.cpp \ + NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.cpp \ NativeFormats/fbreader/src/library/Author.cpp \ NativeFormats/fbreader/src/library/Book.cpp \ NativeFormats/fbreader/src/library/Comparators.cpp \ diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocBookReader.cpp b/jni/NativeFormats/fbreader/src/formats/doc/DocBookReader.cpp index a83c7ca57..5c2a573a3 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/DocBookReader.cpp +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocBookReader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ #include #include #include +#include #include "DocBookReader.h" #include "../../bookmodel/BookModel.h" @@ -35,7 +36,8 @@ DocBookReader::DocBookReader(BookModel &model, const std::string &encoding) : OleStreamReader(encoding), - myModelReader(model) { + myModelReader(model), + myPictureCounter(0) { myReadState = READ_TEXT; } @@ -160,6 +162,7 @@ void DocBookReader::handleStartField() { void DocBookReader::handleSeparatorField() { static const std::string HYPERLINK = "HYPERLINK"; + static const std::string SEQUENCE = "SEQ"; // static const std::string PAGE = "PAGE"; // static const std::string PAGEREF = "PAGEREF"; // static const std::string SHAPE = "SHAPE"; @@ -185,6 +188,12 @@ void DocBookReader::handleSeparatorField() { } } + if (!splitted.empty() && splitted.at(0) == SEQUENCE) { + myReadFieldState = READ_FIELD_TEXT; + myHyperlinkTypeState = NO_HYPERLINK; + return; + } + if (splitted.size() < 2 || splitted.at(0) != HYPERLINK) { myReadFieldState = DONT_READ_FIELD_TEXT; //to remove pagination from TOC and not hyperlink fields @@ -221,9 +230,12 @@ void DocBookReader::handleEndField() { } -void DocBookReader::handleStartOfHeading() { - //heading can be, for example, a picture - //TODO implement +void DocBookReader::handleImage(const ZLFileImage::Blocks &blocks) { + std::string number; + ZLStringUtil::appendNumber(number, myPictureCounter++); + myModelReader.addImageReference(number, 0, false); + ZLFile file(myModelReader.model().book()->file().path(), "image/auto"); + myModelReader.addImage(number, new ZLFileImage(file, "", blocks)); } void DocBookReader::handleOtherControlChar(ZLUnicodeUtil::Ucs2Char ucs2char) { diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocBookReader.h b/jni/NativeFormats/fbreader/src/formats/doc/DocBookReader.h index 0fbadcbfb..f93e02f3e 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/DocBookReader.h +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocBookReader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,7 +51,7 @@ private: void handleStartField(); void handleSeparatorField(); void handleEndField(); - void handleStartOfHeading(); + void handleImage(const ZLFileImage::Blocks &blocks); void handleOtherControlChar(ZLUnicodeUtil::Ucs2Char ucs2char); //formatting: @@ -89,6 +89,7 @@ private: std::vector myKindStack; shared_ptr myCurStyleEntry; OleMainStream::Style myCurStyleInfo; + unsigned int myPictureCounter; }; inline DocBookReader::~DocBookReader() {} diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.cpp b/jni/NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.cpp new file mode 100644 index 000000000..8b75fda84 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.cpp @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "OleUtil.h" +#include "OleStream.h" +#include "OleMainStream.h" + +#include "DocFloatImageReader.h" + +DocFloatImageReader::DocFloatImageReader(unsigned int off, unsigned int len, shared_ptr tableStream, shared_ptr mainStream) : + myTableStream(tableStream), + myMainStream(mainStream), + myOffset(off), + myLength(len) { +} + +void DocFloatImageReader::readAll() { + //OfficeArtContent structure is described at p.405-406 [MS-DOC] + myTableStream->seek(myOffset, true); + + unsigned int count = 0; + + RecordHeader header; + while (count < myLength) { + count += readRecordHeader(header, myTableStream); + switch (header.type) { + case 0xF000: + count += readDggContainer(myItem, header.length, myTableStream, myMainStream); + break; + case 0xF002: + count += readDgContainer(myItem, header.length, myTableStream); + break; + default: + return; + break; + } + } +} + +ZLFileImage::Blocks DocFloatImageReader::getBlocksForShapeID(unsigned int shapeID) const { + FSPContainer container; + bool found = false; + for (size_t i = 0; !found && i < myItem.FSPs.size(); ++i) { + if (myItem.FSPs.at(i).fsp.shapeID == shapeID) { + found = true; + container = myItem.FSPs.at(i); + } + } + + if (!found || container.fopte.empty()) { + return ZLFileImage::Blocks(); + } + + for (size_t i = 0; i < container.fopte.size(); ++i) { + const FOPTE &fopte = container.fopte.at(i); + if (fopte.pID == 0x0104 && !fopte.isComplex) { //0x0104 specifies the BLIP, see p.420 [MS-ODRAW] + if (fopte.value <= myItem.blips.size() && fopte.value > 0) { + Blip blip = myItem.blips.at(fopte.value - 1); + return blip.blocks; + } + } + } + return ZLFileImage::Blocks(); +} + +unsigned int DocFloatImageReader::readRecordHeader(RecordHeader &header, shared_ptr stream) { + //OfficeArtRecordHeader structure is described at p.26 [MS-ODRAW] + char buffer[8]; + stream->read(buffer, 8); + unsigned int temp = OleUtil::getU2Bytes(buffer, 0); + header.version = temp & 0x000F; + header.instance = temp >> 4; + header.type = OleUtil::getU2Bytes(buffer, 2); + header.length = OleUtil::getU4Bytes(buffer, 4); + return 8; +} + +unsigned int DocFloatImageReader::readDggContainer(OfficeArtContent &item, unsigned int length, shared_ptr stream, shared_ptr mainStream) { + //OfficeArtDggContainer structure is described at p.50 [MS-ODRAW] + RecordHeader header; + unsigned int count = 0; + + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF001: + count += readBStoreContainer(item, header.length, stream, mainStream); + break; + default: + count += skipRecord(header, stream); + break; + } + } + + stream->seek(1, false); //skipping dgglbl (see p.406 [MS-DOC]) + ++count; + + return count; +} + +unsigned int DocFloatImageReader::readBStoreContainer(OfficeArtContent &item, unsigned int length, shared_ptr stream, shared_ptr mainStream) { + //OfficeArtBStoreContainer structure is described at p.58 [MS-ODRAW] + RecordHeader header; + unsigned int count = 0; + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF007: + { + Blip blip; + count += readBStoreContainerFileBlock(blip, stream, mainStream); + item.blips.push_back(blip); + } + break; + default: + count += skipRecord(header, stream); + break; + } + } + return count; +} + +unsigned int DocFloatImageReader::skipRecord(const RecordHeader &header, shared_ptr stream) { + stream->seek(header.length, false); + return header.length; +} + +unsigned int DocFloatImageReader::readBStoreContainerFileBlock(Blip &blip, shared_ptr stream, shared_ptr mainStream) { + //OfficeArtBStoreContainerFileBlock structure is described at p.59 [MS-ODRAW] + unsigned int count = readFBSE(blip.storeEntry, stream); + if( blip.storeEntry.offsetInDelay != (unsigned int)(-1)) { + mainStream->seek(blip.storeEntry.offsetInDelay, true); //see p.70 [MS-ODRAW] + } + RecordHeader header; + unsigned int count2 = readRecordHeader(header, mainStream); + switch (header.type) { + case OleMainStream::WMF: + case OleMainStream::EMF: + case OleMainStream::PICT: + count2 += skipRecord(header, mainStream); + break; + case OleMainStream::JPEG: case OleMainStream::JPEG2: + case OleMainStream::PNG: + case OleMainStream::DIB: + case OleMainStream::TIFF: + count2 += readBlip(blip, header, mainStream); + break; + } + blip.type = header.type; + return count; +} + +unsigned int DocFloatImageReader::readBlip(Blip &blip, const RecordHeader &header, shared_ptr stream) { + //OfficeArtBlip structure is described at p.60-66 [MS-ODRAW] + stream->seek(16, false); //skipping rgbUid1 + unsigned int count = 16; + + bool addField = false; + switch (header.type) { + case OleMainStream::PNG: + if (header.instance == 0x6E1) { + addField = true; + } + break; + case OleMainStream::JPEG: case OleMainStream::JPEG2: + if (header.instance == 0x46B || header.instance == 0x6E3) { + addField = true; + } + break; + case OleMainStream::DIB: + if (header.instance == 0x7A9) { + addField = true; + } + case OleMainStream::TIFF: + if (header.instance == 0x6E5) { + addField = true; + } + break; + } + + if (addField) { + stream->seek(16, false); //skipping rgbUid2 + count += 16; + } + stream->seek(1, false); //skipping tag + count += 1; + + blip.blocks = stream->getBlockPieceInfoList(stream->offset(), header.length - count); + count += header.length; + return count; +} + +unsigned int DocFloatImageReader::readFBSE(BlipStoreEntry &fbse, shared_ptr stream) { + //OfficeArtFBSE structure is described at p.68 [MS-ODRAW] + stream->seek(2, false); //skipping btWin32 and btMacOS + stream->seek(16, false); //skipping rgbUid + stream->seek(2, false); //skipping tag + fbse.size = read4Bytes(stream); + fbse.referenceCount = read4Bytes(stream); + fbse.offsetInDelay = read4Bytes(stream); + stream->seek(1, false); //skipping unused value + unsigned int lengthName = read1Byte(stream); //if it should be multiplied on 2? + stream->seek(2, false); // skipping unused values + if (lengthName > 0) { + stream->seek(lengthName, false); //skipping nameData + } + return 36 + lengthName; +} + +unsigned int DocFloatImageReader::readDgContainer(OfficeArtContent &item, unsigned int length, shared_ptr stream) { + //OfficeArtDgContainer structure is described at p.52 [MS-ODRAW] + unsigned int count = 0; + + RecordHeader header; + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF008: //skip OfficeArtFDG record, p. 82 [MS-ODRAW] + stream->seek(8, false); + count += 8; + break; + case 0xF003: + count += readSpgrContainer(item, header.length, stream); + break; + case 0xF004: + { + FSPContainer fspContainer; + count += readSpContainter(fspContainer, header.length, stream); + item.FSPs.push_back(fspContainer); + } + break; + default: + count += skipRecord(header, stream); + break; + } + } + return count; +} + +unsigned int DocFloatImageReader::readSpgrContainer(OfficeArtContent &item, unsigned int length, shared_ptr stream) { + //OfficeArtSpgrContainer structure is described at p.56 [MS-ODRAW] + unsigned count = 0; + RecordHeader header; + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF003: + count += readSpgrContainer(item, header.length, stream); + break; + case 0xF004: + { + FSPContainer fspContainer; + count += readSpContainter(fspContainer, header.length, stream); + item.FSPs.push_back(fspContainer); + } + break; + default: + count += skipRecord(header, stream); + break; + } + } + return count; +} + +unsigned int DocFloatImageReader::readSpContainter(FSPContainer &item, unsigned int length, shared_ptr stream) { + //OfficeArtSpContainter structure is described at p.53-55 [MS-ODRAW] + RecordHeader header; + unsigned int count = 0; + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF009: //skip OfficeArtFSPGR record, p.74 [MS-ODRAW] + stream->seek(16, false); + count += 16; + break; + case 0xF00A: + count += readFSP(item.fsp, stream); + break; + case 0xF00B: + count += readArrayFOPTE(item.fopte, header.length, stream); + break; + case 0xF00E: //OfficeArtAnchor + case 0xF00F: //OfficeArtChildAnchor, p.75 [MS-ODRAW] + case 0xF010: //OfficeArtClientAnchor + stream->seek(4, false); + count += 4; + break; + case 0xF00C: + case 0xF11F: + case 0xF11D: + break; + default: + count += skipRecord(header, stream); + break; + } + } + return count; +} + +unsigned int DocFloatImageReader::readFSP(FSP &fsp, shared_ptr stream) { + //OfficeArtFSP structure is described at p.76 [MS-ODRAW] + fsp.shapeID = read4Bytes(stream); + stream->seek(4, false); + return 8; +} + +unsigned int DocFloatImageReader::readArrayFOPTE(std::vector &fopteArray,unsigned int length, shared_ptr stream) { + //OfficeArtRGFOPTE structure is described at p.98 [MS-ODRAW] + unsigned int count = 0; + while (count < length) { + FOPTE fopte; + count += readFOPTE(fopte, stream); + fopteArray.push_back(fopte); + } + for (size_t i = 0; i < fopteArray.size(); ++i) { + if (fopteArray.at(i).isComplex) { + stream->seek(fopteArray.at(i).value, false); + count += fopteArray.at(i).value; + } + } + return count; +} + +unsigned int DocFloatImageReader::readFOPTE(FOPTE &fopte, shared_ptr stream) { + //OfficeArtFOPTE structure is described at p.32 [MS-ODRAW] + unsigned int dtemp; + dtemp = read2Bytes (stream); + fopte.pID = (dtemp & 0x3fff); + fopte.isBlipID = ((dtemp & 0x4000) >> 14) == 0x1; + fopte.isComplex = ((dtemp & 0x8000) >> 15) == 0x1; + fopte.value = read4Bytes (stream); + return 6; +} + +unsigned int DocFloatImageReader::read1Byte(shared_ptr stream) { + char b[1]; + stream->read(b, 1); + return OleUtil::getU1Byte(b, 0); +} + +unsigned int DocFloatImageReader::read2Bytes(shared_ptr stream) { + char b[2]; + stream->read(b, 2); + return OleUtil::getU2Bytes(b, 0); +} + +unsigned int DocFloatImageReader::read4Bytes(shared_ptr stream) { + char b[4]; + stream->read(b, 4); + return OleUtil::getU4Bytes(b, 0); +} + diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.h b/jni/NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.h new file mode 100644 index 000000000..2bf657269 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DOCFLOATIMAGEREADER_H__ +#define __DOCFLOATIMAGEREADER_H__ + +#include + +class DocFloatImageReader { + +public: + struct BlipStoreEntry { // see p.68 [MS-ODRAW] + unsigned int size; // size of blip in stream + unsigned int referenceCount; // (cRef) reference count for the the blip + unsigned int offsetInDelay; // foDelay, file offset in the delay stream + }; + + struct Blip { //see p.59, p63-66 [MS-ODRAW] + BlipStoreEntry storeEntry; + unsigned int type; + ZLFileImage::Blocks blocks; + }; + + struct FSP { //see p.76-77 [MS-ODRAW] + unsigned int shapeID; //spid + }; + + struct FOPTE { //see p.98 and p.32 [MS-ODRAW] + unsigned int pID; //pid + bool isBlipID; //fBid + bool isComplex; //fComplex + unsigned int value; //op + }; + + struct FSPContainer { //see p.53-55 [MS-ODRAW] + FSP fsp; + std::vector fopte; + }; + + struct OfficeArtContent { //see p.405-406 [MS-DOC] + std::vector blips; //retrieved from OfficeArtDggContainer + std::vector FSPs; //retrieved from OfficeArtDgContainer + }; + + struct RecordHeader { //see p.26 [MS-ODRAW] + unsigned int version; + unsigned int instance; + unsigned int type; + unsigned int length; + }; + +public: + DocFloatImageReader(unsigned int off, unsigned int len, shared_ptr tableStream, shared_ptr mainStream); + +public: + void readAll(); + + ZLFileImage::Blocks getBlocksForShapeID(unsigned int shapeID) const; + +private: + static unsigned int readRecordHeader(RecordHeader &header, shared_ptr stream); + static unsigned int readDggContainer(OfficeArtContent &item, unsigned int length, shared_ptr stream, shared_ptr mainStream); + + static unsigned int readBStoreContainer(OfficeArtContent &item, unsigned int length, shared_ptr stream, shared_ptr mainStream); + static unsigned int readBStoreContainerFileBlock(Blip &blip, shared_ptr stream, shared_ptr mainStream); + static unsigned int readBlip(Blip &blip, const RecordHeader &header, shared_ptr stream); + static unsigned int readFBSE(BlipStoreEntry &fbse, shared_ptr stream); + + static unsigned int readFOPTE(FOPTE &fopte, shared_ptr stream); + static unsigned int readArrayFOPTE(std::vector &fopte, unsigned int length, shared_ptr stream); + static unsigned int readFSP(FSP &fsp, shared_ptr stream); + static unsigned int readSpContainter(FSPContainer &item, unsigned int length, shared_ptr stream); + static unsigned int readSpgrContainer(OfficeArtContent &item, unsigned int length, shared_ptr stream); + static unsigned int readDgContainer(OfficeArtContent &item, unsigned int length, shared_ptr stream); + + static unsigned int skipRecord(const RecordHeader &header, shared_ptr stream); + + static unsigned int read1Byte(shared_ptr stream); + static unsigned int read2Bytes(shared_ptr stream); + static unsigned int read4Bytes(shared_ptr stream); + +private: + shared_ptr myTableStream; + shared_ptr myMainStream; + unsigned int myOffset; + unsigned int myLength; + + OfficeArtContent myItem; +}; + +#endif /* __DOCFLOATIMAGEREADER_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocInlineImageReader.cpp b/jni/NativeFormats/fbreader/src/formats/doc/DocInlineImageReader.cpp new file mode 100644 index 000000000..5e46b66f3 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocInlineImageReader.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "OleUtil.h" +#include "OleMainStream.h" + +#include "DocInlineImageReader.h" + +DocInlineImageReader::DocInlineImageReader(shared_ptr dataStream) : + myDataStream(dataStream) { +} + +ZLFileImage::Blocks DocInlineImageReader::getImagePieceInfo(unsigned int dataPos) { + if (myDataStream.isNull()) { + return ZLFileImage::Blocks(); + } + if (!myDataStream->seek(dataPos, true)) { + return ZLFileImage::Blocks(); + } + + //reading PICF structure (see p. 421 [MS-DOC]) + unsigned int picfHeaderSize = 4 + 2 + 8; //record length, headerLength and storage format + char headerBuffer[picfHeaderSize]; + if (myDataStream->read(headerBuffer, picfHeaderSize) != picfHeaderSize) { + return ZLFileImage::Blocks(); + } + unsigned int length = OleUtil::getU4Bytes(headerBuffer, 0); + unsigned int headerLength = OleUtil::getU2Bytes(headerBuffer, 4); + unsigned int formatType = OleUtil::getU2Bytes(headerBuffer, 6); + + if (formatType != 0x0064) { //external link to some file; see p.394 [MS-DOC] + //TODO implement + return ZLFileImage::Blocks(); + } + if (headerLength >= length) { + return ZLFileImage::Blocks(); + } + + //reading OfficeArtInlineSpContainer structure; see p.421 [MS-DOC] and p.56 [MS-ODRAW] + if (!myDataStream->seek(headerLength - picfHeaderSize, false)) { //skip header + return ZLFileImage::Blocks(); + } + + char buffer[8]; //for OfficeArtRecordHeader structure; see p.69 [MS-ODRAW] + bool found = false; + unsigned int curOffset = 0; + for (curOffset = headerLength; !found && curOffset + 8 <= length; curOffset += 8) { + if (myDataStream->read(buffer, 8) != 8) { + return ZLFileImage::Blocks(); + } + unsigned int recordInstance = OleUtil::getU2Bytes(buffer, 0) >> 4; + unsigned int recordType = OleUtil::getU2Bytes(buffer, 2); + unsigned int recordLen = OleUtil::getU4Bytes(buffer, 4); + + switch (recordType) { + case 0xF000: case 0xF001: case 0xF002: case 0xF003: case 0xF004: case 0xF005: + break; + case 0xF007: + { + myDataStream->seek(33, false); + char tmpBuf[1]; + myDataStream->read(tmpBuf, 1); + unsigned int nameLength = OleUtil::getU1Byte(tmpBuf, 0); + myDataStream->seek(nameLength * 2 + 2, false); + curOffset += 33 + 1 + nameLength * 2 + 2; + } + break; + case 0xF008: + myDataStream->seek(8, false); + curOffset += 8; + break; + case 0xF009: + myDataStream->seek(16, false); + curOffset += 16; + break; + case 0xF006: case 0xF00A: case 0xF00B: case 0xF00D: case 0xF00E: case 0xF00F: case 0xF010: case 0xF011: case 0xF122: + myDataStream->seek(recordLen, false); + curOffset += recordLen; + break; + case OleMainStream::EMF: //EMF + case OleMainStream::WMF: //WMF + case OleMainStream::PICT: //PICT + //TODO implement + return ZLFileImage::Blocks(); + case OleMainStream::JPEG: case OleMainStream::JPEG2: //JPEG + myDataStream->seek(17, false); + curOffset += 17; + if (recordInstance == 0x46B || recordInstance == 0x6E3) { + myDataStream->seek(16, false); + curOffset += 16; + } + found = true; + break; + case OleMainStream::PNG: //PNG + myDataStream->seek(17, false); + curOffset += 17; + if (recordInstance == 0x6E1) { + myDataStream->seek(16, false); + curOffset += 16; + } + found = true; + break; + case OleMainStream::DIB: //DIB (BMP without 14-bytes header) + myDataStream->seek(17, false); + curOffset += 17; + if (recordInstance == 0x7A9) { + myDataStream->seek(16, false); + curOffset += 16; + } + found = true; + break; + case OleMainStream::TIFF: //TIFF + myDataStream->seek(17, false); + curOffset += 17; + if (recordInstance == 0x6E5) { + myDataStream->seek(16, false); + curOffset += 16; + } + found = true; + break; + case 0xF00C: + default: + return ZLFileImage::Blocks(); + } + } + + if (!found) { + return ZLFileImage::Blocks(); + } + return myDataStream->getBlockPieceInfoList(dataPos + curOffset, length - curOffset); +} diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocInlineImageReader.h b/jni/NativeFormats/fbreader/src/formats/doc/DocInlineImageReader.h new file mode 100644 index 000000000..9dab9ae5a --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocInlineImageReader.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DOCINLINEIMAGEREADER_H__ +#define __DOCINLINEIMAGEREADER_H__ + +#include + +#include "OleStream.h" + +class DocInlineImageReader { + +public: + DocInlineImageReader(shared_ptr dataStream); + ZLFileImage::Blocks getImagePieceInfo(unsigned int dataPos); + +private: + shared_ptr myDataStream; +}; + +#endif /* __DOCINLINEIMAGEREADER_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocMetaInfoReader.cpp b/jni/NativeFormats/fbreader/src/formats/doc/DocMetaInfoReader.cpp index 6f3f14750..0ddcb4230 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/DocMetaInfoReader.cpp +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocMetaInfoReader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocMetaInfoReader.h b/jni/NativeFormats/fbreader/src/formats/doc/DocMetaInfoReader.h index ea75cd903..30e9ec020 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/DocMetaInfoReader.h +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocMetaInfoReader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocPlugin.cpp b/jni/NativeFormats/fbreader/src/formats/doc/DocPlugin.cpp index 00cdd015d..2afdf9241 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/DocPlugin.cpp +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocPlugin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/jni/NativeFormats/fbreader/src/formats/doc/DocPlugin.h b/jni/NativeFormats/fbreader/src/formats/doc/DocPlugin.h index cb8665548..93b18035a 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/DocPlugin.h +++ b/jni/NativeFormats/fbreader/src/formats/doc/DocPlugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleMainStream.cpp b/jni/NativeFormats/fbreader/src/formats/doc/OleMainStream.cpp index 4a2b51092..d0694b144 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleMainStream.cpp +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleMainStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,8 @@ #include "OleUtil.h" #include "OleStorage.h" +#include "DocInlineImageReader.h" + #include "OleMainStream.h" OleMainStream::Style::Style() { @@ -47,6 +49,14 @@ OleMainStream::SectionInfo::SectionInfo() : newPage(true) { } +OleMainStream::InlineImageInfo::InlineImageInfo() : + dataPos(0) { +} + +OleMainStream::FloatImageInfo::FloatImageInfo() : + shapeID(0) { +} + OleMainStream::OleMainStream(shared_ptr storage, OleEntry oleEntry, shared_ptr stream) : OleStream(storage, oleEntry, stream) { } @@ -90,6 +100,11 @@ bool OleMainStream::open() { return false; } + OleEntry dataEntry; + if (myStorage->getEntryByName("Data", dataEntry)) { + myDataStream = new OleStream(myStorage, dataEntry, myBaseStream); + } + //result of reading following structures doesn't check, because all these //problems can be ignored, and document can be showed anyway, maybe with wrong formatting readBookmarks(headerBuffer, tableEntry); @@ -97,6 +112,7 @@ bool OleMainStream::open() { //readSectionsInfoTable(headerBuffer, tableEntry); //it isn't used now readParagraphStyleTable(headerBuffer, tableEntry); readCharInfoTable(headerBuffer, tableEntry); + readFloatingImages(headerBuffer, tableEntry); return true; } @@ -116,6 +132,29 @@ const OleMainStream::Bookmarks &OleMainStream::getBookmarks() const { return myBookmarks; } +const OleMainStream::InlineImageInfoList &OleMainStream::getInlineImageInfoList() const { + return myInlineImageInfoList; +} + +const OleMainStream::FloatImageInfoList &OleMainStream::getFloatImageInfoList() const { + return myFloatImageInfoList; +} + +ZLFileImage::Blocks OleMainStream::getFloatImage(unsigned int shapeID) const { + if (myFLoatImageReader.isNull()) { + return ZLFileImage::Blocks(); + } + return myFLoatImageReader->getBlocksForShapeID(shapeID); +} + +ZLFileImage::Blocks OleMainStream::getInlineImage(unsigned int dataPos) const { + if (myDataStream.isNull()) { + return ZLFileImage::Blocks(); + } + DocInlineImageReader imageReader(myDataStream); + return imageReader.getImagePieceInfo(dataPos); +} + bool OleMainStream::readFIB(const char *headerBuffer) { int flags = OleUtil::getU2Bytes(headerBuffer, 0xA); //offset for flags @@ -197,7 +236,7 @@ std::string OleMainStream::getPiecesTableBuffer(const char *headerBuffer, OleStr tableStream.seek(clxOffset, true); tableStream.read(clxBuffer, clxLength); std::string clx(clxBuffer, clxLength); - delete clxBuffer; + delete[] clxBuffer; //2 step: searching for pieces table buffer at CLX //(determines it by 0x02 as start symbol) @@ -314,7 +353,6 @@ bool OleMainStream::readBookmarks(const char *headerBuffer, const OleEntry &tabl return true; //there's no bookmarks } - OleStream tableStream(myStorage, tableEntry, myBaseStream); std::string buffer; if (!readToBuffer(buffer, beginNamesInfo, namesInfoLength, tableStream)) { @@ -352,7 +390,8 @@ bool OleMainStream::readBookmarks(const char *headerBuffer, const OleEntry &tabl return false; } - size_t size = (charPosInfoLen / 4 - 1) / 2; + static const unsigned int BKF_SIZE = 4; + size_t size = calcCountOfPLC(charPosInfoLen, BKF_SIZE); std::vector charPage; for (size_t index = 0, offset = 0; index < size; ++index, offset += 4) { charPage.push_back(OleUtil::getU4Bytes(buffer.c_str(), offset)); @@ -474,14 +513,14 @@ bool OleMainStream::readStylesheet(const char *headerBuffer, const OleEntry &tab } } } while (styleSheetWasChanged); - delete buffer; + delete[] buffer; return true; } bool OleMainStream::readCharInfoTable(const char *headerBuffer, const OleEntry &tableEntry) { - //fcPlcfbteChpx structure is table with formatting for particular run of text - unsigned int beginCharInfo = OleUtil::getU4Bytes(headerBuffer, 0xfa); // address of fcPlcfbteChpx structure - size_t charInfoLength = (size_t)OleUtil::getU4Bytes(headerBuffer, 0xfe); // length of fcPlcfbteChpx structure + //PlcfbteChpx structure is table with formatting for particular run of text + unsigned int beginCharInfo = OleUtil::getU4Bytes(headerBuffer, 0xfa); // address of PlcfbteChpx structure + size_t charInfoLength = (size_t)OleUtil::getU4Bytes(headerBuffer, 0xfe); // length of PlcfbteChpx structure if (charInfoLength < 4) { return false; } @@ -492,9 +531,10 @@ bool OleMainStream::readCharInfoTable(const char *headerBuffer, const OleEntry & return false; } - size_t size = (charInfoLength / 4 - 1) / 2; + static const unsigned int CHPX_SIZE = 4; + size_t size = calcCountOfPLC(charInfoLength, CHPX_SIZE); std::vector charBlocks; - for (size_t index = 0, offset = (size + 1) * 4; index < size; ++index, offset += 4) { + for (size_t index = 0, offset = (size + 1) * 4; index < size; ++index, offset += CHPX_SIZE) { charBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), offset)); } @@ -520,9 +560,70 @@ bool OleMainStream::readCharInfoTable(const char *headerBuffer, const OleEntry & getCharInfo(chpxOffset, istd, formatPageBuffer + 1, len - 1, charInfo); } myCharInfoList.push_back(CharPosToCharInfo(charPos, charInfo)); + + if (chpxOffset != 0) { + InlineImageInfo pictureInfo; + if (getInlineImageInfo(chpxOffset, formatPageBuffer + 1, len - 1, pictureInfo)) { + myInlineImageInfoList.push_back(CharPosToInlineImageInfo(charPos, pictureInfo)); + } + } + } } - delete formatPageBuffer; + delete[] formatPageBuffer; + return true; +} + +bool OleMainStream::readFloatingImages(const char *headerBuffer, const OleEntry &tableEntry) { + //Plcspa structure is a table with information for FSPA (File Shape Address) + unsigned int beginPicturesInfo = OleUtil::getU4Bytes(headerBuffer, 0x01DA); // address of Plcspa structure + if (beginPicturesInfo == 0) { + return true; //there's no office art objects + } + unsigned int picturesInfoLength = OleUtil::getU4Bytes(headerBuffer, 0x01DE); // length of Plcspa structure + if (picturesInfoLength < 4) { + return false; + } + + OleStream tableStream(myStorage, tableEntry, myBaseStream); + std::string buffer; + if (!readToBuffer(buffer, beginPicturesInfo, picturesInfoLength, tableStream)) { + return false; + } + + + static const unsigned int SPA_SIZE = 26; + size_t size = calcCountOfPLC(picturesInfoLength, SPA_SIZE); + + std::vector picturesBlocks; + for (size_t index = 0, tOffset = 0; index < size; ++index, tOffset += 4) { + picturesBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset)); + } + + for (size_t index = 0, tOffset = (size + 1) * 4; index < size; ++index, tOffset += SPA_SIZE) { + unsigned int spid = OleUtil::getU4Bytes(buffer.c_str(), tOffset); + FloatImageInfo info; + unsigned int charPos = picturesBlocks.at(index); + info.shapeID = spid; + myFloatImageInfoList.push_back(CharPosToFloatImageInfo(charPos, info)); + } + + //DggInfo structure is office art object table data + unsigned int beginOfficeArtContent = OleUtil::getU4Bytes(headerBuffer, 0x22A); // address of DggInfo structure + if (beginOfficeArtContent == 0) { + return true; //there's no office art objects + } + unsigned int officeArtContentLength = OleUtil::getU4Bytes(headerBuffer, 0x022E); // length of DggInfo structure + if (officeArtContentLength < 4) { + return false; + } + + shared_ptr newTableStream = new OleStream(myStorage, tableEntry, myBaseStream); + shared_ptr newMainStream = new OleStream(myStorage, myOleEntry, myBaseStream); + if (newTableStream->open() && newMainStream->open()) { + myFLoatImageReader = new DocFloatImageReader(beginOfficeArtContent, officeArtContentLength, newTableStream, newMainStream); + myFLoatImageReader->readAll(); + } return true; } @@ -540,10 +641,11 @@ bool OleMainStream::readParagraphStyleTable(const char *headerBuffer, const OleE return false; } - size_t size = (paragraphInfoLength / 4 - 1) / 2; + static const unsigned int PAPX_SIZE = 4; + size_t size = calcCountOfPLC(paragraphInfoLength, PAPX_SIZE); std::vector paragraphBlocks; - for (size_t index = 0, tOffset = (size + 1) * 4; index < size; ++index, tOffset += 4) { + for (size_t index = 0, tOffset = (size + 1) * 4; index < size; ++index, tOffset += PAPX_SIZE) { paragraphBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset)); } @@ -580,7 +682,7 @@ bool OleMainStream::readParagraphStyleTable(const char *headerBuffer, const OleE myStyleInfoList.push_back(CharPosToStyle(charPos, styleInfo)); } } - delete formatPageBuffer; + delete[] formatPageBuffer; return true; } @@ -600,7 +702,8 @@ bool OleMainStream::readSectionsInfoTable(const char *headerBuffer, const OleEnt return false; } - size_t decriptorsCount = (sectInfoLen - 4) / 16; + static const unsigned int SED_SIZE = 12; + size_t decriptorsCount = calcCountOfPLC(sectInfoLen, SED_SIZE); //saving the section offsets (in character positions) std::vector charPos; @@ -611,7 +714,7 @@ bool OleMainStream::readSectionsInfoTable(const char *headerBuffer, const OleEnt //saving sepx offsets std::vector sectPage; - for (size_t index = 0, tOffset = (decriptorsCount + 1) * 4; index < decriptorsCount; ++index, tOffset += 12) { + for (size_t index = 0, tOffset = (decriptorsCount + 1) * 4; index < decriptorsCount; ++index, tOffset += SED_SIZE) { sectPage.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset + 2)); } @@ -638,14 +741,14 @@ bool OleMainStream::readSectionsInfoTable(const char *headerBuffer, const OleEnt } char *formatPageBuffer = new char[bytes]; if (read(formatPageBuffer, bytes) != bytes) { - delete formatPageBuffer; + delete[] formatPageBuffer; continue; } SectionInfo sectionInfo; sectionInfo.charPos = charPos.at(index); getSectionInfo(formatPageBuffer + 2, bytes - 2, sectionInfo); mySectionInfoList.push_back(sectionInfo); - delete formatPageBuffer; + delete[] formatPageBuffer; } return true; } @@ -780,6 +883,39 @@ void OleMainStream::getSectionInfo(const char *grpprlBuffer, size_t bytes, Secti } } +bool OleMainStream::getInlineImageInfo(unsigned int chpxOffset, const char *grpprlBuffer, unsigned int bytes, InlineImageInfo &pictureInfo) { + //p. 105 of [MS-DOC] documentation + unsigned int offset = 0; + bool isFound = false; + while (bytes >= offset + 2) { + switch (OleUtil::getU2Bytes(grpprlBuffer, chpxOffset + offset)) { + case 0x080a: // ole object, p.107 [MS-DOC] + if (OleUtil::getU1Byte(grpprlBuffer, chpxOffset + offset + 2) == 0x01) { + return false; + } + break; + case 0x0806: // is not a picture, but a binary data? (sprmCFData, p.106 [MS-DOC]) + if (OleUtil::getU4Bytes(grpprlBuffer, chpxOffset + offset + 2) == 0x01) { + return false; + } + break; +// case 0x0855: // sprmCFSpec, p.117 [MS-DOC], MUST BE applied with a value of 1 (see p.105 [MS-DOC]) +// if (OleUtil::getU1Byte(grpprlBuffer, chpxOffset + offset + 2) != 0x01) { +// return false; +// } +// break; + case 0x6a03: // location p.105 [MS-DOC] + pictureInfo.dataPos = OleUtil::getU4Bytes(grpprlBuffer, chpxOffset + offset + 2); + isFound = true; + break; + default: + break; + } + offset += getPrlLength(grpprlBuffer, chpxOffset + offset); + } + return isFound; +} + OleMainStream::Style OleMainStream::getStyleFromStylesheet(unsigned int istd, const StyleSheet &stylesheet) { //TODO optimize it: StyleSheet can be map structure with istd key Style style; @@ -831,7 +967,8 @@ bool OleMainStream::offsetToCharPos(unsigned int offset, unsigned int &charPos, return false; } if ((unsigned int)pieces.front().offset > offset) { - return false; + charPos = 0; + return true; } if ((unsigned int)(pieces.back().offset + pieces.back().length) <= offset) { return false; @@ -867,10 +1004,15 @@ bool OleMainStream::readToBuffer(std::string &result, unsigned int offset, size_ return false; } result = std::string(buffer, length); - delete buffer; + delete[] buffer; return true; } +unsigned int OleMainStream::calcCountOfPLC(unsigned int totalSize, unsigned int elementSize) { + //calculates count of elements in PLC structure, formula from p.30 [MS-DOC] + return (totalSize - 4) / (4 + elementSize); +} + unsigned int OleMainStream::getPrlLength(const char *grpprlBuffer, unsigned int byteNumber) { unsigned int tmp; unsigned int opCode = OleUtil::getU2Bytes(grpprlBuffer, byteNumber); diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleMainStream.h b/jni/NativeFormats/fbreader/src/formats/doc/OleMainStream.h index 0a4dca8a2..5abaf7c4d 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleMainStream.h +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleMainStream.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ #include #include "OleStream.h" +#include "DocFloatImageReader.h" class OleMainStream : public OleStream { public: @@ -106,16 +107,39 @@ public: bool newPage; SectionInfo(); }; - typedef std::vector SectionInfoList; struct Bookmark { unsigned int charPos; std::string name; }; - typedef std::vector Bookmarks; + struct InlineImageInfo { + unsigned int dataPos; + InlineImageInfo(); + }; + typedef std::pair CharPosToInlineImageInfo; + typedef std::vector InlineImageInfoList; + + struct FloatImageInfo { + unsigned int shapeID; + FloatImageInfo(); + }; + typedef std::pair CharPosToFloatImageInfo; + typedef std::vector FloatImageInfoList; + + enum ImageType { //see p. 60 [MS-ODRAW] + EMF = 0xF01A, + WMF = 0xF01B, + PICT = 0xF01C, + JPEG = 0xF01D, + PNG = 0xF01E, + DIB = 0xF01F, + TIFF = 0xF029, + JPEG2 = 0xF02A + }; + public: OleMainStream(shared_ptr storage, OleEntry oleEntry, shared_ptr stream); @@ -125,6 +149,11 @@ public: const CharInfoList &getCharInfoList() const; const StyleInfoList &getStyleInfoList() const; const Bookmarks &getBookmarks() const; + const InlineImageInfoList &getInlineImageInfoList() const; + const FloatImageInfoList &getFloatImageInfoList() const; + + ZLFileImage::Blocks getFloatImage(unsigned int shapeID) const; + ZLFileImage::Blocks getInlineImage(unsigned int dataPos) const; private: bool readFIB(const char *headerBuffer); @@ -134,6 +163,7 @@ private: bool readSectionsInfoTable(const char *headerBuffer, const OleEntry &tableEntry); bool readParagraphStyleTable(const char *headerBuffer, const OleEntry &tableEntry); bool readCharInfoTable(const char *headerBuffer, const OleEntry &tableEntry); + bool readFloatingImages(const char *headerBuffer, const OleEntry &tableEntry); private: //readPieceTable helpers methods static std::string getPiecesTableBuffer(const char *headerBuffer, OleStream &tableStream); @@ -144,6 +174,7 @@ private: //formatting reader helpers methods static void getCharInfo(unsigned int chpxOffset, unsigned int istd, const char *grpprlBuffer, unsigned int bytes, CharInfo &charInfo); static void getStyleInfo(unsigned int papxOffset, const char *grpprlBuffer, unsigned int bytes, Style &styleInfo); static void getSectionInfo(const char *grpprlBuffer, size_t bytes, SectionInfo §ionInfo); + static bool getInlineImageInfo(unsigned int chpxOffset, const char *grpprlBuffer, unsigned int bytes, InlineImageInfo &pictureInfo); static Style getStyleFromStylesheet(unsigned int istd, const StyleSheet &stylesheet); static int getStyleIndex(unsigned int istd, const std::vector &isFilled, const StyleSheet &stylesheet); @@ -152,6 +183,8 @@ private: //formatting reader helpers methods static bool offsetToCharPos(unsigned int offset, unsigned int &charPos, const Pieces &pieces); static bool readToBuffer(std::string &result, unsigned int offset, size_t length, OleStream &stream); + static unsigned int calcCountOfPLC(unsigned int totalSize, unsigned int elementSize); + private: enum PrlFlag { UNSET = 0, @@ -171,8 +204,14 @@ private: CharInfoList myCharInfoList; StyleInfoList myStyleInfoList; SectionInfoList mySectionInfoList; + InlineImageInfoList myInlineImageInfoList; + FloatImageInfoList myFloatImageInfoList; Bookmarks myBookmarks; + + shared_ptr myDataStream; + + shared_ptr myFLoatImageReader; }; #endif /* __OLEMAINSTREAM_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleStorage.cpp b/jni/NativeFormats/fbreader/src/formats/doc/OleStorage.cpp index c1f5ea0fc..fbdb13513 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleStorage.cpp +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleStorage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -259,11 +259,11 @@ bool OleStorage::readOleEntry(int propNumber, OleEntry &e) { chainCur < (int)(e.isBigBlock ? myBBD.size() : mySBD.size()) && e.blocks.size() <= e.length / (e.isBigBlock ? mySectorSize : myShortSectorSize)); } - e.length = std::min(e.length, (unsigned int)(e.isBigBlock ? mySectorSize : myShortSectorSize) * e.blocks.size()); + e.length = std::min(e.length, (unsigned int)((e.isBigBlock ? mySectorSize : myShortSectorSize) * e.blocks.size())); return true; } -unsigned int OleStorage::getFileOffsetOfBlock(OleEntry &e, unsigned int blockNumber) { +unsigned int OleStorage::getFileOffsetOfBlock(const OleEntry &e, unsigned int blockNumber) const { unsigned int res; if (e.isBigBlock) { res = BBD_BLOCK_SIZE + e.blocks.at(blockNumber) * mySectorSize; diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleStorage.h b/jni/NativeFormats/fbreader/src/formats/doc/OleStorage.h index 099cb26bd..715ffa50c 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleStorage.h +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleStorage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,11 +55,11 @@ public: const std::vector &getEntries() const; bool getEntryByName(std::string name, OleEntry &entry) const; - unsigned int getSectorSize(); - unsigned int getShortSectorSize(); + unsigned int getSectorSize() const; + unsigned int getShortSectorSize() const; public: //TODO make private - unsigned int getFileOffsetOfBlock(OleEntry &e, unsigned int blockNumber); + unsigned int getFileOffsetOfBlock(const OleEntry &e, unsigned int blockNumber) const; private: bool readDIFAT(char *oleBuf); @@ -86,7 +86,7 @@ private: }; inline const std::vector &OleStorage::getEntries() const { return myEntries; } -inline unsigned int OleStorage::getSectorSize() { return mySectorSize; } -inline unsigned int OleStorage::getShortSectorSize() { return myShortSectorSize; } +inline unsigned int OleStorage::getSectorSize() const { return mySectorSize; } +inline unsigned int OleStorage::getShortSectorSize() const { return myShortSectorSize; } #endif /* __OLESTORAGE_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleStream.cpp b/jni/NativeFormats/fbreader/src/formats/doc/OleStream.cpp index 126be646a..5838a62ab 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleStream.cpp +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,20 +70,17 @@ size_t OleStream::read(char *buffer, size_t maxSize) { readedBytes = myBaseStream->read(buffer, std::min(length, bytesLeftInCurBlock)); for (size_t i = 0; i < toReadBlocks; ++i) { - size_t readbytes; - ++curBlockNumber; + if (++curBlockNumber >= myOleEntry.blocks.size()) { + break; + } newFileOffset = myStorage->getFileOffsetOfBlock(myOleEntry, curBlockNumber); myBaseStream->seek(newFileOffset, true); - readbytes = myBaseStream->read(buffer + readedBytes, std::min(length - readedBytes, sectorSize)); - readedBytes += readbytes; + readedBytes += myBaseStream->read(buffer + readedBytes, std::min(length - readedBytes, sectorSize)); } - if (toReadBytes > 0) { - size_t readbytes; - ++curBlockNumber; + if (toReadBytes > 0 && ++curBlockNumber < myOleEntry.blocks.size()) { newFileOffset = myStorage->getFileOffsetOfBlock(myOleEntry, curBlockNumber); myBaseStream->seek(newFileOffset, true); - readbytes = myBaseStream->read(buffer + readedBytes, toReadBytes); - readedBytes += readbytes; + readedBytes += myBaseStream->read(buffer + readedBytes, toReadBytes); } myOleOffset += readedBytes; return readedBytes; @@ -125,3 +122,74 @@ bool OleStream::seek(unsigned int offset, bool absoluteOffset) { size_t OleStream::offset() { return myOleOffset; } + +ZLFileImage::Blocks OleStream::getBlockPieceInfoList(unsigned int offset, unsigned int size) const { + ZLFileImage::Blocks list; + unsigned int sectorSize = (myOleEntry.isBigBlock ? myStorage->getSectorSize() : myStorage->getShortSectorSize()); + unsigned int curBlockNumber = offset / sectorSize; + if (curBlockNumber >= myOleEntry.blocks.size()) { + return list; + } + unsigned int modBlock = offset % sectorSize; + unsigned int startFileOffset = myStorage->getFileOffsetOfBlock(myOleEntry, curBlockNumber) + modBlock; + + unsigned int bytesLeftInCurBlock = sectorSize - modBlock; + unsigned int toReadBlocks = 0, toReadBytes = 0; + if (bytesLeftInCurBlock < size) { + toReadBlocks = (size - bytesLeftInCurBlock) / sectorSize; + toReadBytes = (size - bytesLeftInCurBlock) % sectorSize; + } + + unsigned int readedBytes = std::min(size, bytesLeftInCurBlock); + list.push_back(ZLFileImage::Block(startFileOffset, readedBytes)); + + for (unsigned int i = 0; i < toReadBlocks; ++i) { + if (++curBlockNumber >= myOleEntry.blocks.size()) { + break; + } + unsigned int newFileOffset = myStorage->getFileOffsetOfBlock(myOleEntry, curBlockNumber); + unsigned int readbytes = std::min(size - readedBytes, sectorSize); + list.push_back(ZLFileImage::Block(newFileOffset, readbytes)); + readedBytes += readbytes; + } + if (toReadBytes > 0 && ++curBlockNumber < myOleEntry.blocks.size()) { + unsigned int newFileOffset = myStorage->getFileOffsetOfBlock(myOleEntry, curBlockNumber); + unsigned int readbytes = toReadBytes; + list.push_back(ZLFileImage::Block(newFileOffset, readbytes)); + readedBytes += readbytes; + } + + return concatBlocks(list); +} + +ZLFileImage::Blocks OleStream::concatBlocks(const ZLFileImage::Blocks &blocks) { + if (blocks.size() < 2) { + return blocks; + } + ZLFileImage::Blocks optList; + ZLFileImage::Block curBlock = blocks.at(0); + unsigned int nextOffset = curBlock.offset + curBlock.size; + for (size_t i = 1; i < blocks.size(); ++i) { + ZLFileImage::Block b = blocks.at(i); + if (b.offset == nextOffset) { + curBlock.size += b.size; + nextOffset += b.size; + } else { + optList.push_back(curBlock); + curBlock = b; + nextOffset = curBlock.offset + curBlock.size; + } + } + optList.push_back(curBlock); + return optList; +} + +size_t OleStream::fileOffset() { + size_t sectorSize = (size_t)(myOleEntry.isBigBlock ? myStorage->getSectorSize() : myStorage->getShortSectorSize()); + unsigned int curBlockNumber = myOleOffset / sectorSize; + if (curBlockNumber >= myOleEntry.blocks.size()) { + return 0; + } + unsigned int modBlock = myOleOffset % sectorSize; + return myStorage->getFileOffsetOfBlock(myOleEntry, curBlockNumber) + modBlock; +} diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleStream.h b/jni/NativeFormats/fbreader/src/formats/doc/OleStream.h index 1859b3b47..2108fa295 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleStream.h +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleStream.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,8 @@ #ifndef __OLESTREAM_H__ #define __OLESTREAM_H__ +#include + #include "OleStorage.h" class OleStream { @@ -36,6 +38,11 @@ public: bool seek(unsigned int offset, bool absoluteOffset); size_t offset(); +public: + ZLFileImage::Blocks getBlockPieceInfoList(unsigned int offset, unsigned int size) const; + static ZLFileImage::Blocks concatBlocks(const ZLFileImage::Blocks &blocks); + size_t fileOffset(); + public: bool eof() const; @@ -48,6 +55,4 @@ protected: unsigned int myOleOffset; }; - - #endif /* __OLESTREAM_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleStreamReader.cpp b/jni/NativeFormats/fbreader/src/formats/doc/OleStreamReader.cpp index 960d34a4f..66053a4bf 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleStreamReader.cpp +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleStreamReader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include "OleMainStream.h" #include "DocBookReader.h" #include "OleUtil.h" +#include "DocInlineImageReader.h" #include "OleStreamReader.h" @@ -42,13 +43,14 @@ const ZLUnicodeUtil::Ucs2Char OleStreamReader::WORD_START_FIELD = 0x0013; const ZLUnicodeUtil::Ucs2Char OleStreamReader::WORD_SEPARATOR_FIELD = 0x0014; const ZLUnicodeUtil::Ucs2Char OleStreamReader::WORD_END_FIELD = 0x0015; const ZLUnicodeUtil::Ucs2Char OleStreamReader::WORD_ZERO_WIDTH_UNBREAKABLE_SPACE = 0xfeff; +const ZLUnicodeUtil::Ucs2Char OleStreamReader::INLINE_IMAGE = 0x0001; +const ZLUnicodeUtil::Ucs2Char OleStreamReader::FLOAT_IMAGE = 0x0008; //unicode values: const ZLUnicodeUtil::Ucs2Char OleStreamReader::NULL_SYMBOL = 0x0; const ZLUnicodeUtil::Ucs2Char OleStreamReader::FILE_SEPARATOR = 0x1c; const ZLUnicodeUtil::Ucs2Char OleStreamReader::LINE_FEED = 0x000a; const ZLUnicodeUtil::Ucs2Char OleStreamReader::SOFT_HYPHEN = 0xad; -const ZLUnicodeUtil::Ucs2Char OleStreamReader::START_OF_HEADING = 0x0001; const ZLUnicodeUtil::Ucs2Char OleStreamReader::SPACE = 0x20; const ZLUnicodeUtil::Ucs2Char OleStreamReader::SHORT_DEFIS = 0x2D; const ZLUnicodeUtil::Ucs2Char OleStreamReader::VERTICAL_LINE = 0x7C; @@ -67,6 +69,8 @@ void OleStreamReader::clear() { myNextStyleInfoIndex = 0; myNextCharInfoIndex = 0; myNextBookmarkIndex = 0; + myNextInlineImageInfoIndex = 0; + myNextFloatImageInfoIndex = 0; } bool OleStreamReader::readStream(OleMainStream &oleMainStream) { @@ -122,8 +126,7 @@ bool OleStreamReader::readStream(OleMainStream &oleMainStream) { case WORD_END_FIELD: handleEndField(); break; - case START_OF_HEADING: - handleStartOfHeading(); + case INLINE_IMAGE: case FLOAT_IMAGE: break; default: handleOtherControlChar(ucs2char); @@ -133,11 +136,11 @@ bool OleStreamReader::readStream(OleMainStream &oleMainStream) { continue; //skip } else { //debug output - //std::string utf8String; - //ZLUnicodeUtil::Ucs2String ucs2String; - //ucs2String.push_back(ucs2char); - //ZLUnicodeUtil::ucs2ToUtf8(utf8String, ucs2String); - //printf("%s", utf8String.c_str()); +// std::string utf8String; +// ZLUnicodeUtil::Ucs2String ucs2String; +// ucs2String.push_back(ucs2char); +// ZLUnicodeUtil::ucs2ToUtf8(utf8String, ucs2String); +// printf("%s", utf8String.c_str()); handleChar(ucs2char); } @@ -152,7 +155,57 @@ bool OleStreamReader::getUcs2Char(OleMainStream &stream, ZLUnicodeUtil::Ucs2Char return false; } } + ucs2char = myBuffer.at(myCurBufferPosition++); + processStyles(stream); + if (ucs2char == INLINE_IMAGE) { + processInlineImage(stream); + } else if (ucs2char == FLOAT_IMAGE) { + processFloatImage(stream); + } + ++myCurCharPos; + return true; +} + +void OleStreamReader::processInlineImage(OleMainStream &stream) { + const OleMainStream::InlineImageInfoList &imageInfoList = stream.getInlineImageInfoList(); + if (imageInfoList.empty()) { + return; + } + //seek to curCharPos, because not all entries are real pictures + while(myNextInlineImageInfoIndex < imageInfoList.size() && imageInfoList.at(myNextInlineImageInfoIndex).first < myCurCharPos) { + ++myNextInlineImageInfoIndex; + } + while (myNextInlineImageInfoIndex < imageInfoList.size() && imageInfoList.at(myNextInlineImageInfoIndex).first == myCurCharPos) { + OleMainStream::InlineImageInfo info = imageInfoList.at(myNextInlineImageInfoIndex).second; + ZLFileImage::Blocks list = stream.getInlineImage(info.dataPos); + if (!list.empty()) { + handleImage(list); + } + ++myNextInlineImageInfoIndex; + } +} + +void OleStreamReader::processFloatImage(OleMainStream &stream) { + const OleMainStream::FloatImageInfoList &imageInfoList = stream.getFloatImageInfoList(); + if (imageInfoList.empty()) { + return; + } + //seek to curCharPos, because not all entries are real pictures + while(myNextFloatImageInfoIndex < imageInfoList.size() && imageInfoList.at(myNextFloatImageInfoIndex).first < myCurCharPos) { + ++myNextFloatImageInfoIndex; + } + while (myNextFloatImageInfoIndex < imageInfoList.size() && imageInfoList.at(myNextFloatImageInfoIndex).first == myCurCharPos) { + OleMainStream::FloatImageInfo info = imageInfoList.at(myNextFloatImageInfoIndex).second; + ZLFileImage::Blocks list = stream.getFloatImage(info.shapeID); + if (!list.empty()) { + handleImage(list); + } + ++myNextFloatImageInfoIndex; + } +} + +void OleStreamReader::processStyles(OleMainStream &stream) { const OleMainStream::StyleInfoList &styleInfoList = stream.getStyleInfoList(); if (!styleInfoList.empty()) { while (myNextStyleInfoIndex < styleInfoList.size() && styleInfoList.at(myNextStyleInfoIndex).first == myCurCharPos) { @@ -179,10 +232,6 @@ bool OleStreamReader::getUcs2Char(OleMainStream &stream, ZLUnicodeUtil::Ucs2Char ++myNextBookmarkIndex; } } - - ucs2char = myBuffer.at(myCurBufferPosition++); - ++myCurCharPos; - return true; } bool OleStreamReader::fillBuffer(OleMainStream &stream) { @@ -229,7 +278,7 @@ bool OleStreamReader::fillBuffer(OleMainStream &stream) { } myCurBufferPosition = 0; ++myNextPieceNumber; - delete textBuffer; + delete[] textBuffer; return true; } diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleStreamReader.h b/jni/NativeFormats/fbreader/src/formats/doc/OleStreamReader.h index d36fb31dd..89ccf998c 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleStreamReader.h +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleStreamReader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,13 +41,14 @@ public: static const ZLUnicodeUtil::Ucs2Char WORD_SEPARATOR_FIELD; static const ZLUnicodeUtil::Ucs2Char WORD_END_FIELD; static const ZLUnicodeUtil::Ucs2Char WORD_ZERO_WIDTH_UNBREAKABLE_SPACE; + static const ZLUnicodeUtil::Ucs2Char INLINE_IMAGE; + static const ZLUnicodeUtil::Ucs2Char FLOAT_IMAGE; //unicode values: static const ZLUnicodeUtil::Ucs2Char NULL_SYMBOL; static const ZLUnicodeUtil::Ucs2Char FILE_SEPARATOR; static const ZLUnicodeUtil::Ucs2Char LINE_FEED; static const ZLUnicodeUtil::Ucs2Char SOFT_HYPHEN; - static const ZLUnicodeUtil::Ucs2Char START_OF_HEADING; static const ZLUnicodeUtil::Ucs2Char SPACE; static const ZLUnicodeUtil::Ucs2Char SHORT_DEFIS; static const ZLUnicodeUtil::Ucs2Char VERTICAL_LINE; @@ -70,7 +71,7 @@ protected: virtual void handleStartField() = 0; virtual void handleSeparatorField() = 0; virtual void handleEndField() = 0; - virtual void handleStartOfHeading() = 0; + virtual void handleImage(const ZLFileImage::Blocks &blocks) = 0; virtual void handleOtherControlChar(ZLUnicodeUtil::Ucs2Char ucs2char) = 0; virtual void handleFontStyle(unsigned int fontStyle) = 0; @@ -79,6 +80,9 @@ protected: private: bool getUcs2Char(OleMainStream &stream, ZLUnicodeUtil::Ucs2Char &ucs2char); + void processInlineImage(OleMainStream &stream); + void processFloatImage(OleMainStream &stream); + void processStyles(OleMainStream &stream); bool fillBuffer(OleMainStream &stream); private: @@ -94,6 +98,8 @@ private: size_t myNextStyleInfoIndex; size_t myNextCharInfoIndex; size_t myNextBookmarkIndex; + size_t myNextInlineImageInfoIndex; + size_t myNextFloatImageInfoIndex; }; #endif /* __OLESTREAMREADER_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleUtil.cpp b/jni/NativeFormats/fbreader/src/formats/doc/OleUtil.cpp index 39ff75d13..2e8f68502 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleUtil.cpp +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleUtil.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/jni/NativeFormats/fbreader/src/formats/doc/OleUtil.h b/jni/NativeFormats/fbreader/src/formats/doc/OleUtil.h index d74903236..531c76918 100644 --- a/jni/NativeFormats/fbreader/src/formats/doc/OleUtil.h +++ b/jni/NativeFormats/fbreader/src/formats/doc/OleUtil.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Geometer Plus + * Copyright (C) 2004-2012 Geometer Plus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp index 8b526295a..582c35c1a 100644 --- a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp +++ b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "XHTMLReader.h" diff --git a/jni/NativeFormats/util/AndroidUtil.cpp b/jni/NativeFormats/util/AndroidUtil.cpp index 84e582d4e..529bb00e3 100644 --- a/jni/NativeFormats/util/AndroidUtil.cpp +++ b/jni/NativeFormats/util/AndroidUtil.cpp @@ -166,7 +166,7 @@ bool AndroidUtil::init(JavaVM* jvm) { Method_ZLFile_getPath = new StringMethod(Class_ZLFile, "getPath", "()"); Method_ZLFile_size = new LongMethod(Class_ZLFile, "size", "()"); - Constructor_ZLFileImage = new Constructor(Class_ZLFileImage, "(Ljava/lang/String;Lorg/geometerplus/zlibrary/core/filesystem/ZLFile;Ljava/lang/String;II)V"); + Constructor_ZLFileImage = new Constructor(Class_ZLFileImage, "(Ljava/lang/String;Lorg/geometerplus/zlibrary/core/filesystem/ZLFile;Ljava/lang/String;[I[I)V"); StaticMethod_Paths_cacheDirectory = new StaticObjectMethod(Class_Paths, "cacheDirectory", Class_java_lang_String, "()"); @@ -213,14 +213,25 @@ jobject AndroidUtil::createJavaImage(JNIEnv *env, const ZLFileImage &image) { jobject javaFile = createJavaFile(env, image.file().path()); jstring javaEncoding = createJavaString(env, image.encoding()); + std::vector offsets, sizes; + const ZLFileImage::Blocks &blocks = image.blocks(); + for (size_t i = 0; i < blocks.size(); ++i) { + offsets.push_back((jint)blocks.at(i).offset); + sizes.push_back((jint)blocks.at(i).size); + } + jintArray javaOffsets = createJavaIntArray(env, offsets); + jintArray javaSizes = createJavaIntArray(env, sizes); + jobject javaImage = Constructor_ZLFileImage->call( javaMimeType, javaFile, javaEncoding, - image.offset(), image.size() + javaOffsets, javaSizes ); env->DeleteLocalRef(javaEncoding); env->DeleteLocalRef(javaFile); env->DeleteLocalRef(javaMimeType); + env->DeleteLocalRef(javaOffsets); + env->DeleteLocalRef(javaSizes); return javaImage; } diff --git a/jni/NativeFormats/zlibrary/core/src/image/ZLFileImage.h b/jni/NativeFormats/zlibrary/core/src/image/ZLFileImage.h index e92f5aeb2..25e55effa 100644 --- a/jni/NativeFormats/zlibrary/core/src/image/ZLFileImage.h +++ b/jni/NativeFormats/zlibrary/core/src/image/ZLFileImage.h @@ -20,28 +20,53 @@ #ifndef __ZLFILEIMAGE_H__ #define __ZLFILEIMAGE_H__ +#include + #include -#include "ZLStreamImage.h" +#include "ZLImage.h" -class ZLFileImage : public ZLStreamImage { +class ZLFileImage : public ZLSingleImage { + +public: + struct Block { + unsigned int offset; + unsigned int size; + + Block(unsigned int off, unsigned int s); + }; + typedef std::vector Blocks; public: ZLFileImage(const ZLFile &file, const std::string &encoding, size_t offset, size_t size = 0); + ZLFileImage(const ZLFile &file, const std::string &encoding, const Blocks &blocks); //Kind kind() const; const ZLFile &file() const; + const std::string &encoding() const; + const ZLFileImage::Blocks& blocks() const; protected: //shared_ptr inputStream() const; private: const ZLFile myFile; + const std::string myEncoding; + Blocks myBlocks; }; -inline ZLFileImage::ZLFileImage(const ZLFile &file, const std::string &encoding, size_t offset, size_t size) : ZLStreamImage(file.mimeType(), encoding, offset, size), myFile(file) {} +inline ZLFileImage::Block::Block(unsigned int off, unsigned int s) : offset(off), size(s) {} + +inline ZLFileImage::ZLFileImage(const ZLFile &file, const std::string &encoding, size_t offset, size_t size) : ZLSingleImage(file.mimeType()), myFile(file), myEncoding(encoding) { + myBlocks.push_back(Block(offset, size)); +} + +inline ZLFileImage::ZLFileImage(const ZLFile &file, const std::string &encoding, const ZLFileImage::Blocks &blocks) : ZLSingleImage(file.mimeType()), myFile(file), myEncoding(encoding), myBlocks(blocks) { } + //inline ZLSingleImage::Kind ZLFileImage::kind() const { return FILE_IMAGE; } inline const ZLFile &ZLFileImage::file() const { return myFile; } +inline const std::string &ZLFileImage::encoding() const { return myEncoding; } +inline const ZLFileImage::Blocks &ZLFileImage::blocks() const { return myBlocks; } //inline shared_ptr ZLFileImage::inputStream() const { return myFile.inputStream(); } #endif /* __ZLFILEIMAGE_H__ */ diff --git a/src/org/geometerplus/zlibrary/core/image/ZLFileImage.java b/src/org/geometerplus/zlibrary/core/image/ZLFileImage.java index 8fc3082e0..317b52caf 100644 --- a/src/org/geometerplus/zlibrary/core/image/ZLFileImage.java +++ b/src/org/geometerplus/zlibrary/core/image/ZLFileImage.java @@ -34,12 +34,19 @@ public class ZLFileImage extends ZLSingleImage { public static ZLFileImage byUrlPath(String urlPath) { try { final String[] data = urlPath.split("\000"); + int count = Integer.parseInt(data[2]); + int[] offsets = new int[count]; + int[] lengths = new int[count]; + for (int i = 0; i < count; ++i) { + offsets[i] = Integer.parseInt(data[3 + i]); + lengths[i] = Integer.parseInt(data[3 + count + i]); + } return new ZLFileImage( MimeType.IMAGE_AUTO, ZLFile.createFileByPath(data[0]), data[1], - Integer.parseInt(data[2]), - Integer.parseInt(data[3]) + offsets, + lengths ); } catch (Exception e) { e.printStackTrace(); @@ -49,19 +56,33 @@ public class ZLFileImage extends ZLSingleImage { private final ZLFile myFile; private final String myEncoding; - private final int myOffset; - private final int myLength; + private final int[] myOffsets; + private final int[] myLengths; + + public ZLFileImage(String mimeType, ZLFile file, String encoding, int[] offsets, int[] lengths) { + this(MimeType.get(mimeType), file, encoding, offsets, lengths); + } + + public ZLFileImage(MimeType mimeType, ZLFile file, String encoding, int[] offsets, int[] lengths) { + super(mimeType); + myFile = file; + myEncoding = encoding != null ? encoding : ENCODING_NONE; + myOffsets = offsets; + myLengths = lengths; + } public ZLFileImage(String mimeType, ZLFile file, String encoding, int offset, int length) { this(MimeType.get(mimeType), file, encoding, offset, length); } public ZLFileImage(MimeType mimeType, ZLFile file, String encoding, int offset, int length) { - super(mimeType); - myFile = file; - myEncoding = encoding != null ? encoding : ENCODING_NONE; - myOffset = offset; - myLength = length; + super(mimeType); + myFile = file; + myEncoding = encoding != null ? encoding : ENCODING_NONE; + myOffsets = new int[1]; + myLengths = new int[1]; + myOffsets[0] = offset; + myLengths[0] = length; } public ZLFileImage(MimeType mimeType, ZLFile file) { @@ -69,15 +90,34 @@ public class ZLFileImage extends ZLSingleImage { } public String getURI() { - return SCHEME + "://" + myFile.getPath() + "\000" + myEncoding + "\000" + myOffset + "\000" + myLength; + String result = SCHEME + "://" + myFile.getPath() + "\000" + myEncoding + "\000" + myOffsets.length; + for (int offset : myOffsets) { + result += "\000" + offset; + } + for (int length : myLengths) { + result += "\000" + length; + } + return result; } @Override public InputStream inputStream() { try { - final InputStream stream = - new SliceInputStream(myFile.getInputStream(), myOffset, myLength != 0 ? myLength : Integer.MAX_VALUE); - if (ENCODING_NONE.equals(myEncoding)) { + final InputStream stream; + if (myOffsets.length == 1) { + final int offset = myOffsets[0]; + final int length = myLengths[0]; + stream = new SliceInputStream(myFile.getInputStream(), offset, length != 0 ? length : Integer.MAX_VALUE); + } else { + final InputStream[] streams = new InputStream[myOffsets.length]; + for (int i = 0; i < myOffsets.length; ++i) { + final int offset = myOffsets[i]; + final int length = myLengths[i]; + streams[i] = new SliceInputStream(myFile.getInputStream(), offset, length != 0 ? length : Integer.MAX_VALUE); + } + stream = new MergedInputStream(streams); + } + if (ENCODING_NONE.equals(myEncoding)) { return stream; } else if (ENCODING_HEX.equals(myEncoding)) { return new HexInputStream(stream); diff --git a/src/org/geometerplus/zlibrary/core/util/MergedInputStream.java b/src/org/geometerplus/zlibrary/core/util/MergedInputStream.java new file mode 100644 index 000000000..f7185f190 --- /dev/null +++ b/src/org/geometerplus/zlibrary/core/util/MergedInputStream.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2007-2012 Geometer Plus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +package org.geometerplus.zlibrary.core.util; + +import java.io.IOException; +import java.io.InputStream; + +public class MergedInputStream extends InputStream { + private final InputStream[] myStreams; + private InputStream myCurrentStream; + private int myCurrentStreamNumber; + + public MergedInputStream(InputStream[] streams) throws IOException { + myStreams = streams; + myCurrentStream = streams[0]; + myCurrentStreamNumber = 0; + } + + @Override + public int read() throws IOException { + int readed = -1; + boolean streamIsAvailable = true; + while (readed == -1 && streamIsAvailable) { + readed = myCurrentStream.read(); + if (readed == -1) { + streamIsAvailable = nextStream(); + } + } + return readed; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int bytesToRead = len; + int bytesReaded = 0; + boolean streamIsAvailable = true; + while (bytesToRead > 0 && streamIsAvailable) { + int readed = myCurrentStream.read(b, off, bytesToRead); + if (readed != -1) { + bytesToRead -= readed; + off += readed; + bytesReaded += readed; + } + if (bytesToRead != 0) { + streamIsAvailable = nextStream(); + } + } + return bytesReaded == 0 ? -1 : bytesReaded; + } + + @Override + public long skip(long n) throws IOException { + long skipped = myCurrentStream.skip(n); + boolean streamIsAvailable = true; + while (skipped < n && streamIsAvailable) { + streamIsAvailable = nextStream(); + if (streamIsAvailable) { + skipped += myCurrentStream.skip(n - skipped); + } + } + return skipped; + } + + @Override + public int available() throws IOException { + int total = 0; + for (int i = myCurrentStreamNumber; i < myStreams.length; ++i) { + total += myStreams[i].available(); + } + return total; + } + + @Override + public void reset() throws IOException { + myCurrentStream = myStreams[0]; + myCurrentStreamNumber = 0; + for (InputStream stream : myStreams) { + stream.reset(); + } + } + + private boolean nextStream() { + if (myCurrentStreamNumber + 1 >= myStreams.length) { + return false; + } + ++myCurrentStreamNumber; + myCurrentStream = myStreams[myCurrentStreamNumber]; + return true; + } +}