static Vec<PageAnnotation> *ParseFileModifications(const char *data) { if (!data) return NULL; SquareTree sqt(data); if (!sqt.root || sqt.root->data.Count() == 0) return NULL; SquareTreeNode::DataItem& item = sqt.root->data.At(0); if (!item.isChild || !str::EqI(item.key, "@meta")) return NULL; if (!item.value.child->GetValue("version")) { // don't check the version value - rather extend the format // in a way to ensure backwards compatibility return NULL; } Vec<PageAnnotation> *list = new Vec<PageAnnotation>(); for (SquareTreeNode::DataItem *i = sqt.root->data.IterStart(); i; i = sqt.root->data.IterNext()) { PageAnnotType type = str::EqI(i->key, "highlight") ? Annot_Highlight : str::EqI(i->key, "underline") ? Annot_Underline : str::EqI(i->key, "strikeout") ? Annot_StrikeOut : str::EqI(i->key, "squiggly") ? Annot_Squiggly : Annot_None; CrashIf(!i->isChild); if (Annot_None == type || !i->isChild) continue; int pageNo; geomutil::RectT<float> rect; PageAnnotation::Color color; float opacity; int r, g, b; SquareTreeNode *node = i->value.child; const char *value = node->GetValue("page"); if (!value || !str::Parse(value, "%d%$", &pageNo)) continue; value = node->GetValue("rect"); if (!value || !str::Parse(value, "%f %f %f %f%$", &rect.x, &rect.y, &rect.dx, &rect.dy)) continue; value = node->GetValue("color"); if (!value || !str::Parse(value, "#%2x%2x%2x%$", &r, &g, &b)) continue; value = node->GetValue("opacity"); if (!value || !str::Parse(value, "%f%$", &opacity)) opacity = 1.0f; color = PageAnnotation::Color((uint8_t)r, (uint8_t)g, (uint8_t)b, (uint8_t)(255 * opacity)); list->Append(PageAnnotation(type, pageNo, rect.Convert<double>(), color)); } return list; }
Vec<PageAnnotation> *LoadFileModifications(const WCHAR *filepath) { ScopedMem<WCHAR> modificationsPath(str::Join(filepath, SMX_FILE_EXT)); size_t len; ScopedMem<char> data(file::ReadAll(modificationsPath, &len)); if (!data) return NULL; CssPullParser parser(data, len); if (!parser.NextRule()) return NULL; const CssSelector *sel = parser.NextSelector(); if (!sel || !IsSelector(sel, "@meta") || parser.NextSelector()) return NULL; const CssProperty *prop = parser.NextProperty(); if (!prop || Css_Version != prop->type || !str::Parse(prop->s, prop->sLen, SMX_CURR_VERSION "%$")) return NULL; Vec<PageAnnotation> *list = new Vec<PageAnnotation>(); while (parser.NextRule()) { sel = parser.NextSelector(); if (!sel) continue; PageAnnotType type = IsSelector(sel, "highlight") ? Annot_Highlight : IsSelector(sel, "underline") ? Annot_Underline : IsSelector(sel, "strikeout") ? Annot_StrikeOut : IsSelector(sel, "squiggly") ? Annot_Squiggly : Annot_None; if (Annot_None == type || parser.NextSelector()) continue; int pageNo = 0; RectT<float> rect; PageAnnotation::Color color; while ((prop = parser.NextProperty())) { switch (prop->type) { case Css_Page: if (!str::Parse(prop->s, prop->sLen, "%d%$", &pageNo)) pageNo = 0; break; case Css_Rect: if (!str::Parse(prop->s, prop->sLen, "%f %f %f %f%$", &rect.x, &rect.y, &rect.dx, &rect.dy)) rect = RectT<float>(); break; case Css_Color: int r, g, b, a; if (str::Parse(prop->s, prop->sLen, "#%2x%2x%2x%2x%$", &a, &r, &g, &b)) color = PageAnnotation::Color(r, g, b, a); else if (str::Parse(prop->s, prop->sLen, "#%2x%2x%2x%$", &r, &g, &b)) color = PageAnnotation::Color(r, g, b); break; } } if (pageNo <= 0 || rect.IsEmpty()) continue; list->Append(PageAnnotation(type, pageNo, rect.Convert<double>(), color)); } return list; }