@Override public boolean endElementHandler(String tag) { tag = tag.toLowerCase().intern(); switch (myReadState) { case READ_NONE: break; case READ_MAP: if (TAG_NAVMAP == tag) { myReadState = READ_NONE; } break; case READ_POINT: if (TAG_NAVPOINT == tag) { NavPoint last = myPointStack.get(myPointStack.size() - 1); if (last.Text.length() == 0) { last.Text = "..."; } myNavigationMap.put(last.Order, last); myPointStack.remove(myPointStack.size() - 1); myReadState = (myPointStack.isEmpty()) ? READ_MAP : READ_POINT; } case READ_LABEL: if (TAG_NAVLABEL == tag) { myReadState = READ_POINT; } break; case READ_TEXT: if (TAG_TEXT == tag) { myReadState = READ_LABEL; } break; } return false; }
private void safeBeginParagraph() { if (!myParagraphStarted) { myParagraphStarted = true; myBufferIsEmpty = true; beginParagraph(ZLTextParagraph.Kind.TEXT_PARAGRAPH); if (!myParagraphStored) { // final ArrayList models = Model.getBookTextModels(); // myParagraphVector.add(new Pair(((ZLTextPlainModel) // models.get(models.size()-1)/*BookTextModel*/).getParagraphsNumber() - 1, models.size() - // 1)); myParagraphStored = true; } for (Iterator it = myDelayedControls.iterator(); it.hasNext(); ) { Pair pit = (Pair) it.next(); addControl((Byte) pit.myFirst, (Boolean) pit.mySecond); } // if (myForcedEntry != null) { // addControl(myForcedEntry); // } else { addControl(FBTextKind.REGULAR, true); // } for (Iterator it = myDelayedHyperlinks.iterator(); it.hasNext(); ) { addHyperlinkControl(FBTextKind.INTERNAL_HYPERLINK, (String) it.next()); } myDelayedHyperlinks.clear(); } }
@Override public void characterDataHandler(char[] ch, int start, int length) { if (myReadState == READ_TEXT) { final ArrayList<NavPoint> stack = myPointStack; final NavPoint last = stack.get(stack.size() - 1); last.Text += new String(ch, start, length); } }
private void safeAddHyperlinkControl(String id) { if (myParagraphStarted) { addHyperlinkControl(FBTextKind.INTERNAL_HYPERLINK, id); } else { myDelayedHyperlinks.add(id); } }
private void safeAddControl(byte kind, boolean start) { if (myParagraphStarted) { addControl((Byte) kind, (Boolean) start); } else { myDelayedControls.add(new Pair(kind, start)); } }
boolean readBook(ZLFile file) { myFilePrefix = MiscUtil.htmlDirectoryPrefix(file); myIdToHref.clear(); myHtmlFileNames.clear(); myParagraphIndexList.clear(); myNCXTOCFileName = null; myTourTOC.clear(); myGuideTOC.clear(); myState = READ_NONE; if (!read(file)) { return false; } myModelReader.setMainTextModel(); myModelReader.pushKind(FBTextKind.REGULAR); int count = 0; for (String name : myHtmlFileNames) { final ZLFile xhtmlFile = ZLFile.createFileByPath(myFilePrefix + name); if (xhtmlFile == null) { // NPE fix: null for bad attributes in .opf XML file return false; } if (count++ == 0 && xhtmlFile.getPath().equals(myCoverFileName)) { continue; } final XHTMLReader reader = new XHTMLReader(myModelReader, myFileNumbers); final String referenceName = reader.getFileAlias(MiscUtil.archiveEntryName(xhtmlFile.getPath())); myModelReader.addHyperlinkLabel(referenceName); myParagraphIndexList.add(myModelReader.Model.BookTextModel.getParagraphsNumber()); myTOCLabels.put(referenceName, myModelReader.Model.BookTextModel.getParagraphsNumber()); reader.readFile(xhtmlFile, referenceName + '#'); myModelReader.insertEndOfSectionParagraph(); } final FBReaderApp fbreader = (FBReaderApp) ZLApplication.Instance(); // fbreader.setTOCLabels(myTOCLabels); fbreader.setParagraphIndexList(myParagraphIndexList); fbreader.setHtmlFileNames(myHtmlFileNames, myFilePrefix, myCoverFileName); generateTOC(); return true; }
private void processTextRecord(int size, ArrayList /*<Integer>*/ pars) { int start = 0; int end = 0; for (Iterator it = pars.iterator(); it.hasNext(); ) { start = end; end = start + (Integer) it.next(); if (end > size) { return; } myParagraphStored = false; processTextParagraph(myCharBuffer, start, end); if (!myParagraphStored) { myParagraphVector.add(new Pair(-1, -1)); } } }
private void processTextParagraph(char[] data, int start, int end) { changeFont(FontType.FT_REGULAR); while (popKind()) {} myParagraphStarted = false; myBytesToSkip = 0; int textStart = start; boolean functionFlag = false; for (int ptr = start; ptr < end; ++ptr) { if (data[ptr] == 0) { functionFlag = true; if (ptr > textStart) { safeBeginParagraph(); // myConvertedTextBuffer = "";//.erase(); myConvertedTextBuffer = ""; // myConverter.convert(data, textStart, ptr); addData(myConvertedTextBuffer.toCharArray()); myBufferIsEmpty = false; } } else if (functionFlag) { int paramCounter = (data[ptr]) % 8; if (end - ptr > paramCounter) { processTextFunction(data, ptr); ptr += paramCounter; } else { ptr = end - 1; } functionFlag = false; if (myBytesToSkip > 0) { ptr += myBytesToSkip; myBytesToSkip = 0; } textStart = ptr + 1; } else { if (data[ptr] == 0xA0) { data[ptr] = 0x20; } if (!myParagraphStarted && (textStart == ptr) && (data[ptr] == ' ')) { ++textStart; } } } if (end > textStart) { safeBeginParagraph(); // myConvertedTextBuffer = "";//erase(); myConvertedTextBuffer = ""; // myConverter.convert(data, textStart, end); addData(myConvertedTextBuffer.toCharArray()); myBufferIsEmpty = false; } safeEndParagraph(); // if (myForcedEntry != null) { // myForcedEntry = null; // } myDelayedControls.clear(); }
private void generateTOC() { if (myNCXTOCFileName != null) { final NCXReader ncxReader = new NCXReader(myModelReader); if (ncxReader.readFile(myFilePrefix + myNCXTOCFileName)) { final Map<Integer, NCXReader.NavPoint> navigationMap = ncxReader.navigationMap(); if (!navigationMap.isEmpty()) { int level = 0; for (NCXReader.NavPoint point : navigationMap.values()) { final BookModel.Label label = getTOCLabel(point.ContentHRef); int index = (label != null) ? label.ParagraphIndex : -1; while (level > point.Level) { myModelReader.endContentsParagraph(); --level; } while (++level <= point.Level) { myModelReader.beginContentsParagraph(-2); myModelReader.addContentsData(Dots); myModelReader.addPathData(Dots); } myModelReader.beginContentsParagraph(index); myModelReader.addContentsData(point.Text.toCharArray()); myModelReader.addPathData(point.ContentHRef.toCharArray()); } while (level > 0) { myModelReader.endContentsParagraph(); --level; } return; } } } for (Reference ref : myTourTOC.isEmpty() ? myGuideTOC : myTourTOC) { final BookModel.Label label = getTOCLabel(ref.HRef); if (label != null) { final int index = label.ParagraphIndex; if (index != -1) { myModelReader.beginContentsParagraph(index); myModelReader.addContentsData(ref.Title.toCharArray()); myModelReader.addPathData(ref.HRef.toCharArray()); myModelReader.endContentsParagraph(); } } } }
public boolean readDocument() { try { myStream = new ZLInputStreamWithOffset(myFile.getInputStream()); PdbHeader header = new PdbHeader(myStream); setMainTextModel(); myFont = FontType.FT_REGULAR; for (int index = 0; index < header.Offsets.length; ++index) { int currentOffset = myStream.offset(); int pit = header.Offsets[index]; if (currentOffset > pit) { break; } // myStream.seek(pit - currentOffset, false); myStream.skip(pit - currentOffset); if (myStream.offset() != pit) { break; } int recordSize = ((index != header.Offsets.length - 1) ? header.Offsets[index + 1] : myFileSize) - pit; readRecord(recordSize); } myStream.close(); } catch (IOException e) { return false; } for (Iterator it = myReferencedParagraphs.iterator(); it.hasNext(); ) { Pair pair = (Pair) it.next(); int first = (Integer) pair.myFirst; int second = (Integer) pair.mySecond; ArrayList /*<Integer>*/ list = (ArrayList) myParagraphMap.get(first); if (list != null) { for (int k = second; k < list.size(); ++k) { if (((Integer) ((Pair) list.get(k)).myFirst) != -1) { // addHyperlinkLabel(fromNumber(first) + '#' + fromNumber(second), // (Integer)list.get(k)); final Pair p = (Pair) list.get(k); // addHyperlinkLabel(fromNumber(first) + '#' + fromNumber(second), (Integer) p.mySecond, // (Integer) p.myFirst); break; } } } } myReferencedParagraphs.clear(); myParagraphMap.clear(); return true; }
@Override public boolean startElementHandler(String tag, ZLStringMap attributes) { tag = tag.toLowerCase().intern(); switch (myReadState) { case READ_NONE: if (tag == TAG_NAVMAP) { myReadState = READ_MAP; } break; case READ_MAP: if (tag == TAG_NAVPOINT) { final String order = attributes.getValue(ATTRIBUTE_PLAYORDER); final int index = (order != null) ? atoi(order) : myPlayIndex++; myPointStack.add(new NavPoint(index, myPointStack.size())); myReadState = READ_POINT; } break; case READ_POINT: if (tag == TAG_NAVPOINT) { final String order = attributes.getValue(ATTRIBUTE_PLAYORDER); final int index = (order != null) ? atoi(order) : myPlayIndex++; myPointStack.add(new NavPoint(index, myPointStack.size())); } else if (tag == TAG_NAVLABEL) { myReadState = READ_LABEL; } else if (tag == TAG_CONTENT) { final int size = myPointStack.size(); if (size > 0) { myPointStack.get(size - 1).ContentHRef = ZLArchiveEntryFile.normalizeEntryName( myLocalPathPrefix + MiscUtil.decodeHtmlReference(attributes.getValue("src"))); } } break; case READ_LABEL: if (TAG_TEXT == tag) { myReadState = READ_TEXT; } break; case READ_TEXT: break; } return false; }
private void processTextFunction(char[] ptr, int cur) { switch (ptr[cur]) { case 0x08: safeAddControl(FBTextKind.INTERNAL_HYPERLINK, false); break; case 0x0A: safeAddHyperlinkControl(fromNumber(twoBytes(ptr, cur + 1))); break; case 0x0C: { int sectionNum = twoBytes(ptr, cur + 1); int paragraphNum = twoBytes(ptr, cur + 3); safeAddHyperlinkControl(fromNumber(sectionNum) + '#' + fromNumber(paragraphNum)); myReferencedParagraphs.add(new Pair(sectionNum, paragraphNum)); break; } case 0x11: changeFont((ptr[cur + 1])); break; case 0x1A: safeBeginParagraph(); // System.out.println("image ref"); addImageReference(fromNumber(twoBytes(ptr, cur + 1)), (short) 0); break; case 0x22: if (!myParagraphStarted) { // if (myForcedEntry == null) { // myForcedEntry = new ZLTextForcedControlEntry(); // } // myForcedEntry.setLeftIndent((short)ptr[cur + 1]); // myForcedEntry.setRightIndent((short)ptr[cur + 2]); } break; case 0x29: if (!myParagraphStarted) { // if (myForcedEntry == null) { // myForcedEntry = new ZLTextForcedControlEntry(); // } // switch (ptr[cur + 1]) { // case 0: myForcedEntry.setAlignmentType(ZLTextAlignmentType.ALIGN_LEFT); break; // case 1: myForcedEntry.setAlignmentType(ZLTextAlignmentType.ALIGN_RIGHT); break; // case 2: myForcedEntry.setAlignmentType(ZLTextAlignmentType.ALIGN_CENTER); break; // case 3: myForcedEntry.setAlignmentType(ZLTextAlignmentType.ALIGN_JUSTIFY); break; // } } break; case 0x33: // just break line instead of horizontal rule (TODO: draw horizontal rule?) safeEndParagraph(); break; case 0x38: safeEndParagraph(); break; case 0x40: safeAddControl(FBTextKind.EMPHASIS, true); break; case 0x48: safeAddControl(FBTextKind.EMPHASIS, false); break; case 0x53: // color setting is ignored break; case 0x5C: // System.out.println("image ref"); addImageReference(fromNumber(twoBytes(ptr, cur + 3)), (short) 0); break; case 0x60: // underlined text is ignored break; case 0x68: // underlined text is ignored break; case 0x70: // strike-through text is ignored break; case 0x78: // strike-through text is ignored break; case 0x83: { safeBeginParagraph(); addData(new char[] {(char) twoBytes(ptr, cur + 2)}); myBufferIsEmpty = false; myBytesToSkip = ptr[cur + 1]; break; } case 0x85: // TODO: process 4-byte unicode character break; case 0x8E: // custom font operations are ignored case 0x8C: case 0x8A: case 0x88: break; case 0x90: // TODO: add table processing case 0x92: // TODO: process table case 0x97: // TODO: process table break; default: // this should be impossible // std::cerr << "Oops... function #" << (int)(unsigned char)*ptr << "\n"; break; } }
private void readRecord(int recordSize) throws IOException { int uid = PdbUtil.readShort(myStream); if (uid == 1) { myCompressionVersion = (short) PdbUtil.readShort(myStream); } else { int paragraphs = PdbUtil.readShort(myStream); int size = PdbUtil.readShort(myStream); // TODO ?????? int type = myStream.read(); int flags = myStream.read(); switch (type) { case 0: // text (TODO: found sample file and test this code) case 1: // compressed text { ArrayList /*<Integer>*/ pars = new ArrayList(); for (int i = 0; i < paragraphs; ++i) { int pSize = PdbUtil.readShort(myStream); pars.add(pSize); myStream.skip(2); } boolean doProcess = false; if (type == 0) { // ? byte[] buf = new byte[size]; doProcess = myStream.read(buf, 0, (int) size) == size; if (doProcess) { // TODO: use encoding!!!! // TODO: don't create any new objects!!!! myCharBuffer = new String(buf).toCharArray(); } } else if (myCompressionVersion == 1) { byte[] buf = new byte[size]; doProcess = DocDecompressor.decompress(myStream, buf, recordSize - 8 - 4 * paragraphs) == size; if (doProcess) { myCharBuffer = new String(buf).toCharArray(); } } else if (myCompressionVersion == 2) { byte input[] = new byte[(int) (recordSize - 10 - 4 * paragraphs)]; final int inputSize = myStream.read(input); Inflater decompressor = new Inflater(); decompressor.setInput(input, 0, inputSize); byte output[] = new byte[size]; try { doProcess = decompressor.inflate(output) == size; decompressor.end(); myCharBuffer = new String(output, 0, size).toCharArray(); } catch (DataFormatException e) { // TODO Auto-generated catch block // e.printStackTrace(); System.out.println(e.getMessage()); } // doProcess = // ZLZDecompressor(recordSize - 10 - 4 * paragraphs). // decompress(myStream, myCharBuffer, size) == size; } if (doProcess) { addHyperlinkLabel(fromNumber(uid)); myParagraphMap.put(uid, new ArrayList()); myParagraphVector = (ArrayList) myParagraphMap.get(uid); processTextRecord(size, pars); if ((flags & 0x1) == 0) { // insertEndOfTextParagraph(); // setNewTextModel(); } } break; } case 2: // image case 3: // compressed image { final String mime = "image/palm"; ZLImage image = null; if (type == 2) { System.out.println("non-compressed image"); image = new PluckerFileImage(mime, myFile, myStream.offset(), recordSize - 8); } else if (myCompressionVersion == 1) { System.out.println("DocCompressedImage"); image = new DocCompressedFileImage(mime, myFile, myStream.offset(), recordSize - 8); } else if (myCompressionVersion == 2) { System.out.println("ZCompressedImage"); image = new ZCompressedFileImage(mime, myFile, myStream.offset() + 2, recordSize - 10); } if (image != null) { addImage(fromNumber(uid), image); } break; } case 9: // category record is ignored break; case 10: short typeCode = (short) PdbUtil.readShort(myStream); break; case 11: // style sheet record is ignored break; case 12: // font page record is ignored break; case 13: // TODO: process tables case 14: // TODO: process tables break; case 15: // multiimage { short columns = (short) PdbUtil.readShort(myStream); short rows = (short) PdbUtil.readShort(myStream); System.out.println("multiimage"); /*PluckerMultiImage image = new PluckerMultiImage(rows, columns, Model.getImageMap()); for (int i = 0; i < size / 2 - 2; ++i) { short us = (short)myStream.read(); PdbUtil.readShort(myStream, us); image.addId(fromNumber(us)); } addImage(fromNumber(uid), image); */ break; } default: // std::cerr << "type = " << (int)type << "\n"; break; } } }
@Override public boolean startElementHandler(String tag, ZLStringMap xmlattributes, String[] tagStack) { tag = tag.toLowerCase(); if (myOPFSchemePrefix != null && tag.startsWith(myOPFSchemePrefix)) { tag = tag.substring(myOPFSchemePrefix.length()); } tag = tag.intern(); if (MANIFEST == tag) { myState = READ_MANIFEST; } else if (SPINE == tag) { myNCXTOCFileName = myIdToHref.get(xmlattributes.getValue("toc")); myState = READ_SPINE; } else if (GUIDE == tag) { myState = READ_GUIDE; } else if (TOUR == tag) { myState = READ_TOUR; } else if (myState == READ_MANIFEST && ITEM == tag) { final String id = xmlattributes.getValue("id"); String href = xmlattributes.getValue("href"); if ((id != null) && (href != null)) { href = MiscUtil.decodeHtmlReference(href); myIdToHref.put(id, href); } } else if (myState == READ_SPINE && ITEMREF == tag) { final String id = xmlattributes.getValue("idref"); if (id != null) { final String fileName = myIdToHref.get(id); if (fileName != null) { myHtmlFileNames.add(fileName); } } } else if (myState == READ_GUIDE && REFERENCE == tag) { final String type = xmlattributes.getValue("type"); final String title = xmlattributes.getValue("title"); String href = xmlattributes.getValue("href"); if (href != null) { href = MiscUtil.decodeHtmlReference(href); if (title != null) { myGuideTOC.add(new Reference(title, href)); } if (COVER.equals(type)) { final ZLFile imageFile = ZLFile.createFileByPath(myFilePrefix + href); myCoverFileName = imageFile.getPath(); final String imageName = imageFile.getLongName(); final ZLFileImage image = XHTMLImageFinder.getCoverImage(imageFile); if (image != null) { myModelReader.setMainTextModel(); myModelReader.addImageReference(imageName, (short) 0, true); myModelReader.addImage(imageName, image); myModelReader.insertEndOfSectionParagraph(); } } else if (COVER_IMAGE.equals(type)) { final ZLFile imageFile = ZLFile.createFileByPath(myFilePrefix + href); myCoverFileName = imageFile.getPath(); final String imageName = imageFile.getLongName(); myModelReader.setMainTextModel(); myModelReader.addImageReference(imageName, (short) 0, true); myModelReader.addImage(imageName, new ZLFileImage(MimeType.IMAGE_AUTO, imageFile)); myModelReader.insertEndOfSectionParagraph(); } } } else if (myState == READ_TOUR && SITE == tag) { final String title = xmlattributes.getValue("title"); String href = xmlattributes.getValue("href"); if ((title != null) && (href != null)) { href = MiscUtil.decodeHtmlReference(href); myTourTOC.add(new Reference(title, href)); } } return false; }