diff --git a/jni/Android.mk b/jni/Android.mk index 5d88f81ed..48469ba74 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -101,6 +101,8 @@ LOCAL_SRC_FILES := \ NativeFormats/fbreader/src/formats/fb2/FB2TagManager.cpp \ NativeFormats/fbreader/src/formats/fb2/FB2UidReader.cpp \ NativeFormats/fbreader/src/formats/css/FontMap.cpp \ + NativeFormats/fbreader/src/formats/css/CSSInputStream.cpp \ + NativeFormats/fbreader/src/formats/css/StringInputStream.cpp \ NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp \ NativeFormats/fbreader/src/formats/css/StyleSheetTable.cpp \ NativeFormats/fbreader/src/formats/html/HtmlBookReader.cpp \ diff --git a/jni/NativeFormats/fbreader/src/formats/css/CSSInputStream.cpp b/jni/NativeFormats/fbreader/src/formats/css/CSSInputStream.cpp new file mode 100644 index 000000000..139973ac4 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/css/CSSInputStream.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2004-2014 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 + +#include + +#include "CSSInputStream.h" + +CSSInputStream::Buffer::Buffer(std::size_t capacity) : Capacity(capacity - 1) { + Content = new char[capacity]; + Length = 0; + Offset = 0; +} + +CSSInputStream::Buffer::~Buffer() { + delete[] Content; +} + +CSSInputStream::CSSInputStream(shared_ptr base) : myBaseStream(base), myBuffer(8192), myBufferNoComments(8192) { + //ZLLogger::Instance().registerClass("CSSInputStream"); +} + +CSSInputStream::~CSSInputStream() { + close(); +} + +bool CSSInputStream::open() { + myState = PLAIN_TEXT; + return myBaseStream->open(); +} + +std::size_t CSSInputStream::read(char *buffer, std::size_t maxSize) { + std::size_t ready = 0; + while (ready < maxSize) { + fillBufferNoComments(); + if (myBufferNoComments.isEmpty()) { + break; + } + std::size_t len = std::min( + maxSize - ready, + myBufferNoComments.Length - myBufferNoComments.Offset + ); + if (buffer != 0) { + std::memcpy(buffer + ready, myBufferNoComments.Content + myBufferNoComments.Offset, len); + } + myBufferNoComments.Offset += len; + ready += len; + } + //ZLLogger::Instance().println("CSSInputStream", std::string(buffer, ready)); + return ready; +} + +void CSSInputStream::close() { + return myBaseStream->close(); +} + +void CSSInputStream::seek(int offset, bool absoluteOffset) { + // TODO: implement +} + +std::size_t CSSInputStream::offset() const { + // TODO: implement + return 0; +} + +std::size_t CSSInputStream::sizeOfOpened() { + // TODO: not a correct computation + return myBaseStream->sizeOfOpened(); +} + +void CSSInputStream::fillBufferNoComments() { + if (!myBufferNoComments.isEmpty()) { + return; + } + myBufferNoComments.Length = 0; + myBufferNoComments.Offset = 0; + while (!myBufferNoComments.isFull()) { + if (myBuffer.isEmpty()) { + myBuffer.Offset = 0; + myBuffer.Length = myBaseStream->read(myBuffer.Content, myBuffer.Capacity); + } + if (myBuffer.isEmpty()) { + break; + } + while (!myBuffer.isEmpty() && !myBufferNoComments.isFull()) { + const char ch = myBuffer.Content[myBuffer.Offset++]; + switch (myState) { + case PLAIN_TEXT: + switch (ch) { + case '\'': + myBufferNoComments.Content[myBufferNoComments.Length++] = ch; + myState = S_QUOTED_TEXT; + break; + case '"': + myBufferNoComments.Content[myBufferNoComments.Length++] = ch; + myState = D_QUOTED_TEXT; + break; + case '/': + myState = COMMENT_START_SLASH; + break; + default: + myBufferNoComments.Content[myBufferNoComments.Length++] = ch; + break; + } + break; + case S_QUOTED_TEXT: + if (ch == '\'') { + myState = PLAIN_TEXT; + } + myBufferNoComments.Content[myBufferNoComments.Length++] = ch; + break; + case D_QUOTED_TEXT: + if (ch == '"') { + myState = PLAIN_TEXT; + } + myBufferNoComments.Content[myBufferNoComments.Length++] = ch; + break; + case COMMENT_START_SLASH: + switch (ch) { + case '/': + myBufferNoComments.Content[myBufferNoComments.Length++] = '/'; + break; + case '*': + myState = COMMENT; + break; + default: + myState = PLAIN_TEXT; + myBufferNoComments.Content[myBufferNoComments.Length++] = '/'; + myBufferNoComments.Content[myBufferNoComments.Length++] = ch; + break; + } + break; + case COMMENT: + if (ch == '*') { + myState = COMMENT_END_ASTERISK; + } + break; + case COMMENT_END_ASTERISK: + switch (ch) { + case '/': + myState = PLAIN_TEXT; + break; + case '*': + break; + default: + myState = COMMENT; + break; + } + break; + } + } + } +} diff --git a/jni/NativeFormats/fbreader/src/formats/css/CSSInputStream.h b/jni/NativeFormats/fbreader/src/formats/css/CSSInputStream.h new file mode 100644 index 000000000..734ee4bff --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/css/CSSInputStream.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2004-2014 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 __CSSINPUTSTREAM_H__ +#define __CSSINPUTSTREAM_H__ + +#include +#include + +class CSSInputStream : public ZLInputStream { + +public: + CSSInputStream(shared_ptr base); + ~CSSInputStream(); + +private: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +private: + void fillBufferNoComments(); + +private: + shared_ptr myBaseStream; + + struct Buffer { + Buffer(std::size_t capacity); + ~Buffer(); + + bool isEmpty() const; + bool isFull() const; + + const std::size_t Capacity; + std::size_t Offset; + std::size_t Length; + char *Content; + }; + + Buffer myBuffer; + Buffer myBufferNoComments; + + enum { + PLAIN_TEXT, + S_QUOTED_TEXT, + D_QUOTED_TEXT, + COMMENT_START_SLASH, + COMMENT, + COMMENT_END_ASTERISK + } myState; +}; + +inline bool CSSInputStream::Buffer::isEmpty() const { + return Offset == Length; +} + +inline bool CSSInputStream::Buffer::isFull() const { + return Length >= Capacity; +} + +#endif /* __CSSINPUTSTREAM_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/css/StringInputStream.cpp b/jni/NativeFormats/fbreader/src/formats/css/StringInputStream.cpp new file mode 100644 index 000000000..7db7e99b9 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/css/StringInputStream.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004-2014 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 + +#include + +#include "StringInputStream.h" + +StringInputStream::StringInputStream(const char *cString, std::size_t len) : myCString(cString), myLength(len), myOffset(0) { + //ZLLogger::Instance().registerClass("StringInputStream"); +} + +bool StringInputStream::open() { + return true; +} + +std::size_t StringInputStream::read(char *buffer, std::size_t maxSize) { + const std::size_t len = std::min(maxSize, myLength - myOffset); + std::memcpy(buffer, myCString + myOffset, len); + myOffset += len; + //ZLLogger::Instance().println("StringInputStream", std::string(buffer, len)); + return len; +} + +void StringInputStream::close() { +} + +void StringInputStream::seek(int offset, bool absoluteOffset) { + if (!absoluteOffset) { + offset += myOffset; + } + myOffset = std::max(0, std::min(offset, (int)myLength)); +} + +std::size_t StringInputStream::offset() const { + return myOffset; +} + +std::size_t StringInputStream::sizeOfOpened() { + return myLength; +} diff --git a/jni/NativeFormats/fbreader/src/formats/css/StringInputStream.h b/jni/NativeFormats/fbreader/src/formats/css/StringInputStream.h new file mode 100644 index 000000000..b2ed34947 --- /dev/null +++ b/jni/NativeFormats/fbreader/src/formats/css/StringInputStream.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004-2014 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 __STRINGINPUTSTREAM_H__ +#define __STRINGINPUTSTREAM_H__ + +#include +#include + +class StringInputStream : public ZLInputStream { + +public: + StringInputStream(const char *cstring, std::size_t len); + +private: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +private: + const char *myCString; + const std::size_t myLength; + std::size_t myOffset; +}; + +#endif /* __STRINGINPUTSTREAM_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp index 86204a137..ba6b41d8c 100644 --- a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp +++ b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp @@ -26,6 +26,8 @@ #include #include "StyleSheetParser.h" +#include "StringInputStream.h" +#include "CSSInputStream.h" #include "../util/MiscUtil.h" StyleSheetParser::StyleSheetParser(const std::string &pathPrefix) : myPathPrefix(pathPrefix) { @@ -40,13 +42,32 @@ void StyleSheetParser::reset() { myWord.erase(); myAttributeName.erase(); myReadState = WAITING_FOR_SELECTOR; - myInsideComment = false; mySelectorString.erase(); myMap.clear(); myImportVector.clear(); myFirstRuleProcessed = false; } +void StyleSheetParser::parseString(const char *data, std::size_t len) { + parseStream(new StringInputStream(data, len)); +} + +void StyleSheetParser::parseStream(shared_ptr stream) { + stream = new CSSInputStream(stream); + if (stream->open()) { + char *buffer = new char[1024]; + while (true) { + int len = stream->read(buffer, 1024); + if (len == 0) { + break; + } + parse(buffer, len); + } + delete[] buffer; + stream->close(); + } +} + void StyleSheetParser::parse(const char *text, int len, bool final) { const char *start = text; const char *end = text + len; @@ -172,25 +193,11 @@ void StyleSheetParser::processControl(const char control) { } } -void StyleSheetParser::processWord(std::string &word) { - while (!word.empty()) { - int index = word.find(myInsideComment ? "*/" : "/*"); - if (!myInsideComment) { - if (index == -1) { - processWordWithoutComments(word); - } else if (index > 0) { - processWordWithoutComments(word.substr(0, index)); - } - } - if (index == -1) { - break; - } - myInsideComment = !myInsideComment; - word.erase(0, index + 2); +void StyleSheetParser::processWord(const std::string &word) { + if (word.empty()) { + return; } -} -void StyleSheetParser::processWordWithoutComments(const std::string &word) { switch (myReadState) { case WAITING_FOR_SELECTOR: mySelectorString = word; @@ -229,7 +236,7 @@ void StyleSheetParser::processWordWithoutComments(const std::string &word) { StyleSheetSingleStyleParser::StyleSheetSingleStyleParser(const std::string &pathPrefix) : StyleSheetParser(pathPrefix) { } -shared_ptr StyleSheetSingleStyleParser::parseString(const char *text) { +shared_ptr StyleSheetSingleStyleParser::parseSingleEntry(const char *text) { myReadState = WAITING_FOR_ATTRIBUTE; parse(text, std::strlen(text), true); shared_ptr control = StyleSheetTable::createControl(myMap); @@ -308,21 +315,6 @@ void StyleSheetMultiStyleParser::processAtRule(const std::string &name, const St } } -void StyleSheetMultiStyleParser::parseStream(ZLInputStream &stream) { - if (stream.open()) { - char *buffer = new char[1024]; - while (true) { - int len = stream.read(buffer, 1024); - if (len == 0) { - break; - } - parse(buffer, len); - } - delete[] buffer; - stream.close(); - } -} - StyleSheetTableParser::StyleSheetTableParser(const std::string &pathPrefix, StyleSheetTable &styleTable, FontMap &fontMap) : StyleSheetMultiStyleParser(pathPrefix, fontMap), myStyleTable(styleTable) { } @@ -351,7 +343,7 @@ void StyleSheetParserWithCache::importCSS(const std::string &path) { if (!stream.isNull()) { StyleSheetParserWithCache importParser(fileToImport, myPathPrefix, myFontMap, myEncryptionMap); importParser.myProcessedFiles.insert(myProcessedFiles.begin(), myProcessedFiles.end()); - importParser.parseStream(*stream); + importParser.parseStream(stream); myEntries.insert(myEntries.end(), importParser.myEntries.begin(), importParser.myEntries.end()); } myProcessedFiles.insert(fileToImport.path()); diff --git a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.h b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.h index 2b7e3a599..e9c10a8e9 100644 --- a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.h +++ b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.h @@ -40,7 +40,8 @@ protected: public: virtual ~StyleSheetParser(); void reset(); - void parse(const char *text, int len, bool final = false); + void parseStream(shared_ptr stream); + void parseString(const char *data, std::size_t len); protected: virtual void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map); @@ -48,9 +49,9 @@ protected: virtual void importCSS(const std::string &path); private: + void parse(const char *text, int len, bool final = false); bool isControlSymbol(const char symbol); - void processWord(std::string &word); - void processWordWithoutComments(const std::string &word); + void processWord(const std::string &word); void processControl(const char control); protected: @@ -67,7 +68,6 @@ private: ATTRIBUTE_NAME, ATTRIBUTE_VALUE, } myReadState; - bool myInsideComment; std::string mySelectorString; StyleSheetTable::AttributeMap myMap; std::vector myImportVector; @@ -80,7 +80,7 @@ class StyleSheetSingleStyleParser : public StyleSheetParser { public: StyleSheetSingleStyleParser(const std::string &pathPrefix); - shared_ptr parseString(const char *text); + shared_ptr parseSingleEntry(const char *text); }; class StyleSheetMultiStyleParser : public StyleSheetParser { @@ -88,9 +88,6 @@ class StyleSheetMultiStyleParser : public StyleSheetParser { protected: StyleSheetMultiStyleParser(const std::string &pathPrefix, FontMap &map); -public: - void parseStream(ZLInputStream &stream); - protected: virtual void store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map) = 0; diff --git a/jni/NativeFormats/fbreader/src/formats/html/HtmlBookReader.cpp b/jni/NativeFormats/fbreader/src/formats/html/HtmlBookReader.cpp index 90687ac72..ecdf97e45 100644 --- a/jni/NativeFormats/fbreader/src/formats/html/HtmlBookReader.cpp +++ b/jni/NativeFormats/fbreader/src/formats/html/HtmlBookReader.cpp @@ -519,7 +519,7 @@ void HtmlBookReader::preformattedCharacterDataHandler(const char *text, std::siz bool HtmlBookReader::characterDataHandler(const char *text, std::size_t len, bool convert) { if (!myStyleSheetParser.isNull()) { - myStyleSheetParser->parse(text, len); + myStyleSheetParser->parseString(text, len); return true; } diff --git a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp index 33aeabb4e..843513558 100644 --- a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp +++ b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp @@ -277,7 +277,7 @@ void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattribut shared_ptr cssStream = cssFile.inputStream(reader.myEncryptionMap); if (!cssStream.isNull()) { ZLLogger::Instance().println("CSS", "parsing file"); - parser->parseStream(*cssStream); + parser->parseStream(cssStream); } } parser->applyToTable(reader.myStyleSheetTable); @@ -729,8 +729,8 @@ void XHTMLReader::startElementHandler(const char *tag, const char **attributes) addTextStyleEntry(sTag, *it); const char *style = attributeValue(attributes, "style"); if (style != 0) { - ZLLogger::Instance().println("CSS", std::string("parsing style attribute: ") + style); - shared_ptr entry = myStyleParser->parseString(style); + //ZLLogger::Instance().println("CSS", std::string("parsing style attribute: ") + style); + shared_ptr entry = myStyleParser->parseSingleEntry(style); addTextStyleEntry(*entry); myStyleEntryStack.push_back(entry); } @@ -813,7 +813,7 @@ void XHTMLReader::characterDataHandler(const char *text, std::size_t len) { break; case XHTML_READ_STYLE: if (!myTableParser.isNull()) { - myTableParser->parse(text, len); + myTableParser->parseString(text, len); } break; case XHTML_READ_BODY: