mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-04 18:29:23 +02:00
Merge branch 'doc-plugin' of github.com:geometer/FBReaderJ into doc-plugin
This commit is contained in:
commit
bc8ab70a24
26 changed files with 1260 additions and 93 deletions
|
@ -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 \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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 <ZLLogger.h>
|
||||
#include <ZLFile.h>
|
||||
#include <ZLStringUtil.h>
|
||||
#include <ZLFileImage.h>
|
||||
|
||||
#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) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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<FBTextKind> myKindStack;
|
||||
shared_ptr<ZLTextStyleEntry> myCurStyleEntry;
|
||||
OleMainStream::Style myCurStyleInfo;
|
||||
unsigned int myPictureCounter;
|
||||
};
|
||||
|
||||
inline DocBookReader::~DocBookReader() {}
|
||||
|
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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<OleStream> tableStream, shared_ptr<OleStream> 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<OleStream> 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<OleStream> stream, shared_ptr<OleStream> 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<OleStream> stream, shared_ptr<OleStream> 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<OleStream> stream) {
|
||||
stream->seek(header.length, false);
|
||||
return header.length;
|
||||
}
|
||||
|
||||
unsigned int DocFloatImageReader::readBStoreContainerFileBlock(Blip &blip, shared_ptr<OleStream> stream, shared_ptr<OleStream> 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<OleStream> 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<OleStream> 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<OleStream> 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<OleStream> 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<OleStream> 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<OleStream> 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<FOPTE> &fopteArray,unsigned int length, shared_ptr<OleStream> 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<OleStream> 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<OleStream> stream) {
|
||||
char b[1];
|
||||
stream->read(b, 1);
|
||||
return OleUtil::getU1Byte(b, 0);
|
||||
}
|
||||
|
||||
unsigned int DocFloatImageReader::read2Bytes(shared_ptr<OleStream> stream) {
|
||||
char b[2];
|
||||
stream->read(b, 2);
|
||||
return OleUtil::getU2Bytes(b, 0);
|
||||
}
|
||||
|
||||
unsigned int DocFloatImageReader::read4Bytes(shared_ptr<OleStream> stream) {
|
||||
char b[4];
|
||||
stream->read(b, 4);
|
||||
return OleUtil::getU4Bytes(b, 0);
|
||||
}
|
||||
|
107
jni/NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.h
Normal file
107
jni/NativeFormats/fbreader/src/formats/doc/DocFloatImageReader.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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 <ZLFileImage.h>
|
||||
|
||||
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> fopte;
|
||||
};
|
||||
|
||||
struct OfficeArtContent { //see p.405-406 [MS-DOC]
|
||||
std::vector<Blip> blips; //retrieved from OfficeArtDggContainer
|
||||
std::vector<FSPContainer> 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<OleStream> tableStream, shared_ptr<OleStream> mainStream);
|
||||
|
||||
public:
|
||||
void readAll();
|
||||
|
||||
ZLFileImage::Blocks getBlocksForShapeID(unsigned int shapeID) const;
|
||||
|
||||
private:
|
||||
static unsigned int readRecordHeader(RecordHeader &header, shared_ptr<OleStream> stream);
|
||||
static unsigned int readDggContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream);
|
||||
|
||||
static unsigned int readBStoreContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream);
|
||||
static unsigned int readBStoreContainerFileBlock(Blip &blip, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream);
|
||||
static unsigned int readBlip(Blip &blip, const RecordHeader &header, shared_ptr<OleStream> stream);
|
||||
static unsigned int readFBSE(BlipStoreEntry &fbse, shared_ptr<OleStream> stream);
|
||||
|
||||
static unsigned int readFOPTE(FOPTE &fopte, shared_ptr<OleStream> stream);
|
||||
static unsigned int readArrayFOPTE(std::vector<FOPTE> &fopte, unsigned int length, shared_ptr<OleStream> stream);
|
||||
static unsigned int readFSP(FSP &fsp, shared_ptr<OleStream> stream);
|
||||
static unsigned int readSpContainter(FSPContainer &item, unsigned int length, shared_ptr<OleStream> stream);
|
||||
static unsigned int readSpgrContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream);
|
||||
static unsigned int readDgContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream);
|
||||
|
||||
static unsigned int skipRecord(const RecordHeader &header, shared_ptr<OleStream> stream);
|
||||
|
||||
static unsigned int read1Byte(shared_ptr<OleStream> stream);
|
||||
static unsigned int read2Bytes(shared_ptr<OleStream> stream);
|
||||
static unsigned int read4Bytes(shared_ptr<OleStream> stream);
|
||||
|
||||
private:
|
||||
shared_ptr<OleStream> myTableStream;
|
||||
shared_ptr<OleStream> myMainStream;
|
||||
unsigned int myOffset;
|
||||
unsigned int myLength;
|
||||
|
||||
OfficeArtContent myItem;
|
||||
};
|
||||
|
||||
#endif /* __DOCFLOATIMAGEREADER_H__ */
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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<OleStream> 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);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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 <vector>
|
||||
|
||||
#include "OleStream.h"
|
||||
|
||||
class DocInlineImageReader {
|
||||
|
||||
public:
|
||||
DocInlineImageReader(shared_ptr<OleStream> dataStream);
|
||||
ZLFileImage::Blocks getImagePieceInfo(unsigned int dataPos);
|
||||
|
||||
private:
|
||||
shared_ptr<OleStream> myDataStream;
|
||||
};
|
||||
|
||||
#endif /* __DOCINLINEIMAGEREADER_H__ */
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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<OleStorage> storage, OleEntry oleEntry, shared_ptr<ZLInputStream> 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<unsigned int> 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<unsigned int> 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<unsigned int> 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<OleStream> newTableStream = new OleStream(myStorage, tableEntry, myBaseStream);
|
||||
shared_ptr<OleStream> 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<unsigned int> 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<unsigned int> charPos;
|
||||
|
@ -611,7 +714,7 @@ bool OleMainStream::readSectionsInfoTable(const char *headerBuffer, const OleEnt
|
|||
|
||||
//saving sepx offsets
|
||||
std::vector<unsigned int> 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);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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 <string>
|
||||
|
||||
#include "OleStream.h"
|
||||
#include "DocFloatImageReader.h"
|
||||
|
||||
class OleMainStream : public OleStream {
|
||||
public:
|
||||
|
@ -106,16 +107,39 @@ public:
|
|||
bool newPage;
|
||||
SectionInfo();
|
||||
};
|
||||
|
||||
typedef std::vector<SectionInfo> SectionInfoList;
|
||||
|
||||
struct Bookmark {
|
||||
unsigned int charPos;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
typedef std::vector<Bookmark> Bookmarks;
|
||||
|
||||
struct InlineImageInfo {
|
||||
unsigned int dataPos;
|
||||
InlineImageInfo();
|
||||
};
|
||||
typedef std::pair<unsigned int, InlineImageInfo> CharPosToInlineImageInfo;
|
||||
typedef std::vector<CharPosToInlineImageInfo> InlineImageInfoList;
|
||||
|
||||
struct FloatImageInfo {
|
||||
unsigned int shapeID;
|
||||
FloatImageInfo();
|
||||
};
|
||||
typedef std::pair<unsigned int, FloatImageInfo> CharPosToFloatImageInfo;
|
||||
typedef std::vector<CharPosToFloatImageInfo> 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<OleStorage> storage, OleEntry oleEntry, shared_ptr<ZLInputStream> 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<bool> &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<OleStream> myDataStream;
|
||||
|
||||
shared_ptr<DocFloatImageReader> myFLoatImageReader;
|
||||
};
|
||||
|
||||
#endif /* __OLEMAINSTREAM_H__ */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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<OleEntry> &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<OleEntry> &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__ */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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 <ZLFileImage.h>
|
||||
|
||||
#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__ */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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__ */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2010 Geometer Plus <contact@geometerplus.com>
|
||||
* Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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 <ZLUnicodeUtil.h>
|
||||
#include <ZLStringUtil.h>
|
||||
#include <ZLXMLNamespace.h>
|
||||
#include <ZLInputStream.h>
|
||||
#include <ZLLogger.h>
|
||||
|
||||
#include "XHTMLReader.h"
|
||||
|
|
|
@ -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<jint> 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;
|
||||
}
|
||||
|
|
|
@ -20,28 +20,53 @@
|
|||
#ifndef __ZLFILEIMAGE_H__
|
||||
#define __ZLFILEIMAGE_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <ZLFile.h>
|
||||
|
||||
#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<Block> 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<ZLInputStream> 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<ZLInputStream> ZLFileImage::inputStream() const { return myFile.inputStream(); }
|
||||
|
||||
#endif /* __ZLFILEIMAGE_H__ */
|
||||
|
|
|
@ -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);
|
||||
|
|
107
src/org/geometerplus/zlibrary/core/util/MergedInputStream.java
Normal file
107
src/org/geometerplus/zlibrary/core/util/MergedInputStream.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (C) 2007-2012 Geometer Plus <contact@geometerplus.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue