bool ImageDirEngineImpl::LoadImageDir(const WCHAR *dirName) { fileName = str::Dup(dirName); fileExt = L""; ScopedMem<WCHAR> pattern(path::Join(dirName, L"*")); WIN32_FIND_DATA fdata; HANDLE hfind = FindFirstFile(pattern, &fdata); if (INVALID_HANDLE_VALUE == hfind) return false; do { if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (ImageEngine::IsSupportedFile(fdata.cFileName)) pageFileNames.Append(path::Join(dirName, fdata.cFileName)); } } while (FindNextFile(hfind, &fdata)); FindClose(hfind); if (pageFileNames.Count() == 0) return false; pageFileNames.SortNatural(); pages.AppendBlanks(pageFileNames.Count()); mediaboxes.AppendBlanks(pageFileNames.Count()); return true; }
// data is a pointer to a struct being serialized and typeInfo describes // the struct. res is a result as a stream of bytes static void SerializeType(byte *data, TypeSerializeInfo *typeInfo, Vec<byte>& msg) { msg.Reset(); // reserve space for the size of the message, which we only know // after serializeing the data. We're making an assumption here // that serialized data will be smaller than 65k // note: we can easily relax that by using uint32 for len uint16 *msgLenPtr = (uint16*)msg.AppendBlanks(2); uint16 msgId = (uint16)typeInfo->msgId; int msgLen = SerNum16((byte*)&msgId, msg); for (MemberSerializeInfo *member = typeInfo->members; !member->IsSentinel(); ++ member) { switch (member->type) { case MemberSerializeInfo::UInt16: msgLen += SerNum16(data + member->offset, msg); break; case MemberSerializeInfo::Int32: case MemberSerializeInfo::UInt32: msgLen += SerNum32(data + member->offset, msg); break; case MemberSerializeInfo::Int64: case MemberSerializeInfo::UInt64: msgLen += SerNum32(data + member->offset, msg); break; } } *msgLenPtr = (uint16)msgLen; }
static inline int SerNum32(byte *data, Vec<byte>& serOut) { byte *dataOut = serOut.AppendBlanks(4); *dataOut++ = *data++; *dataOut++ = *data++; *dataOut++ = *data++; *dataOut++ = *data++; return 4; }
static void AppendNewline(str::Str<WCHAR>& extracted, Vec<RectI>& coords, const WCHAR *lineSep) { if (extracted.Count() > 0 && ' ' == extracted.Last()) { extracted.Pop(); coords.Pop(); } extracted.Append(lineSep); coords.AppendBlanks(str::Len(lineSep)); }
bool CbxEngineImpl::LoadCbrFile(const WCHAR *file) { if (!file) return false; fileName = str::Dup(file); fileExt = L".cbr"; RAROpenArchiveDataEx arcData = { 0 }; arcData.ArcNameW = (WCHAR *)file; arcData.OpenMode = RAR_OM_EXTRACT; HANDLE hArc = RAROpenArchiveEx(&arcData); if (!hArc || arcData.OpenResult != 0) return false; // UnRAR does not seem to support extracting a single file by name, // so lazy image loading doesn't seem possible Vec<ImagesPage *> found; for (;;) { RARHeaderDataEx rarHeader; int res = RARReadHeaderEx(hArc, &rarHeader); if (0 != res) break; const WCHAR *fileName = rarHeader.FileNameW; if (ImageEngine::IsSupportedFile(fileName)) { ImagesPage *page = LoadCurrentCbrPage(hArc, rarHeader); if (page) found.Append(page); } else if (str::EqI(fileName, L"ComicInfo.xml")) { ScopedMem<char> xmlData(LoadCurrentCbrFile(hArc, rarHeader, NULL)); if (xmlData) ParseComicInfoXml(xmlData); } else RARProcessFile(hArc, RAR_SKIP, NULL, NULL); } RARCloseArchive(hArc); if (found.Count() == 0) return false; found.Sort(ImagesPage::cmpPageByName); for (size_t i = 0; i < found.Count(); i++) { pages.Append(found.At(i)->bmp); found.At(i)->bmp = NULL; } mediaboxes.AppendBlanks(pages.Count()); DeleteVecMembers(found); return true; }
bool CbxEngineImpl::FinishLoadingCbz() { fileExt = L".cbz"; Vec<const WCHAR *> allFileNames; for (size_t idx = 0; idx < cbzFile->GetFileCount(); idx++) { const WCHAR *fileName = cbzFile->GetFileName(idx); // bail, if we accidentally try to load an XPS file if (fileName && str::StartsWith(fileName, L"_rels/.rels")) return false; if (fileName && ImageEngine::IsSupportedFile(fileName) && // OS X occasionally leaves metadata with image extensions !str::StartsWith(path::GetBaseName(fileName), L".")) { allFileNames.Append(fileName); } else { allFileNames.Append(NULL); } } assert(allFileNames.Count() == cbzFile->GetFileCount()); ScopedMem<char> metadata(cbzFile->GetFileData(L"ComicInfo.xml")); if (metadata) ParseComicInfoXml(metadata); metadata.Set(cbzFile->GetComment()); if (metadata) json::Parse(metadata, this); Vec<const WCHAR *> pageFileNames; for (const WCHAR **fn = allFileNames.IterStart(); fn; fn = allFileNames.IterNext()) { if (*fn) pageFileNames.Append(*fn); } pageFileNames.Sort(cmpAscii); for (const WCHAR **fn = pageFileNames.IterStart(); fn; fn = pageFileNames.IterNext()) { fileIdxs.Append(allFileNames.Find(*fn)); } assert(pageFileNames.Count() == fileIdxs.Count()); if (fileIdxs.Count() == 0) return false; pages.AppendBlanks(fileIdxs.Count()); mediaboxes.AppendBlanks(fileIdxs.Count()); return true; }
WCHAR *EbookEngine::ExtractPageText(int pageNo, WCHAR *lineSep, RectI **coords_out, RenderTarget target) { ScopedCritSec scope(&pagesAccess); str::Str<WCHAR> content; Vec<RectI> coords; bool insertSpace = false; Vec<DrawInstr> *pageInstrs = GetHtmlPage(pageNo); for (DrawInstr *i = pageInstrs->IterStart(); i; i = pageInstrs->IterNext()) { RectI bbox = GetInstrBbox(i, pageBorder); switch (i->type) { case InstrString: if (coords.Count() > 0 && bbox.x < coords.Last().BR().x) { content.Append(lineSep); coords.AppendBlanks(str::Len(lineSep)); CrashIf(*lineSep && !coords.Last().IsEmpty()); } else if (insertSpace && coords.Count() > 0) { int swidth = bbox.x - coords.Last().BR().x; if (swidth > 0) { content.Append(' '); coords.Append(RectI(bbox.x - swidth, bbox.y, swidth, bbox.dy)); } } insertSpace = false; { ScopedMem<WCHAR> s(str::conv::FromHtmlUtf8(i->str.s, i->str.len)); content.Append(s); size_t len = str::Len(s); double cwidth = 1.0 * bbox.dx / len; for (size_t k = 0; k < len; k++) coords.Append(RectI((int)(bbox.x + k * cwidth), bbox.y, (int)cwidth, bbox.dy)); } break; case InstrRtlString: if (coords.Count() > 0 && bbox.BR().x > coords.Last().x) { content.Append(lineSep); coords.AppendBlanks(str::Len(lineSep)); CrashIf(*lineSep && !coords.Last().IsEmpty()); } else if (insertSpace && coords.Count() > 0) { int swidth = coords.Last().x - bbox.BR().x; if (swidth > 0) { content.Append(' '); coords.Append(RectI(bbox.BR().x, bbox.y, swidth, bbox.dy)); } } insertSpace = false; { ScopedMem<WCHAR> s(str::conv::FromHtmlUtf8(i->str.s, i->str.len)); content.Append(s); size_t len = str::Len(s); double cwidth = 1.0 * bbox.dx / len; for (size_t k = 0; k < len; k++) coords.Append(RectI((int)(bbox.x + (len - k - 1) * cwidth), bbox.y, (int)cwidth, bbox.dy)); } break; case InstrElasticSpace: case InstrFixedSpace: insertSpace = true; break; } } if (coords_out) { CrashIf(coords.Count() != content.Count()); *coords_out = new RectI[coords.Count()]; memcpy(*coords_out, coords.LendData(), coords.Count() * sizeof(RectI)); } return content.StealData(); }