1*0e16a31dSJim Jagielski# usage: runpy.sh dump7.py <port> <outdir> <file>... 2*0e16a31dSJim Jagielski# Loads each ODF package read-only over UNO and writes a JSON dump of a fixed property set (Task 7, Review Focus 2). 3*0e16a31dSJim Jagielskiimport sys, os, json, hashlib, uno 4*0e16a31dSJim Jagielskifrom unohelp import connect, desktop, load 5*0e16a31dSJim Jagielski 6*0e16a31dSJim Jagielskiport, outdir, files = int(sys.argv[1]), sys.argv[2], sys.argv[3:] 7*0e16a31dSJim JagielskiLIM = 400 8*0e16a31dSJim Jagielski 9*0e16a31dSJim Jagielskidef v(x, depth=0): 10*0e16a31dSJim Jagielski if isinstance(x, uno.Enum): return x.value 11*0e16a31dSJim Jagielski if x is None or isinstance(x, (bool, int, float, str)): return x 12*0e16a31dSJim Jagielski if isinstance(x, (tuple, list)): return [v(i, depth + 1) for i in x][:200] 13*0e16a31dSJim Jagielski if hasattr(x, "typeName"): 14*0e16a31dSJim Jagielski if depth > 3: return "<deep>" 15*0e16a31dSJim Jagielski try: return {k: v(getattr(x, k), depth + 1) for k in dir(x) if not k.startswith("_") and k not in ("typeName", "value")} 16*0e16a31dSJim Jagielski except Exception: return "<struct>" 17*0e16a31dSJim Jagielski return "<obj>" 18*0e16a31dSJim Jagielskidef g(o, n): 19*0e16a31dSJim Jagielski try: return v(o.getPropertyValue(n)) 20*0e16a31dSJim Jagielski except Exception: return "n/a" 21*0e16a31dSJim Jagielskidef gs(o, names): return [g(o, n) for n in names] 22*0e16a31dSJim Jagielskidef h(s): return hashlib.sha256(s.encode("utf-8", "replace")).hexdigest()[:16] 23*0e16a31dSJim Jagielskidef tryf(f, d="n/a"): 24*0e16a31dSJim Jagielski try: return f() 25*0e16a31dSJim Jagielski except Exception as e: return d if d != "ERR" else repr(e)[:80] 26*0e16a31dSJim Jagielskidef has(doc, s): return tryf(lambda: doc.supportsService(s), False) 27*0e16a31dSJim Jagielski 28*0e16a31dSJim JagielskiSHAPE_PROPS = ["FillStyle", "FillColor", "FillTransparence", "FillGradientName", "FillHatchName", "FillBitmapName", "LineStyle", "LineColor", "LineWidth", "CharHeight", "ParaAdjust"] 29*0e16a31dSJim Jagielskidef shape(s, depth=0): 30*0e16a31dSJim Jagielski d = {"t": tryf(lambda: s.ShapeType), "name": tryf(lambda: s.Name), "pos": v(tryf(lambda: s.Position)), "size": v(tryf(lambda: s.Size)), 31*0e16a31dSJim Jagielski "text": tryf(lambda: s.String[:80]), "p": gs(s, SHAPE_PROPS)} 32*0e16a31dSJim Jagielski t = d["t"] if isinstance(d["t"], str) else "" 33*0e16a31dSJim Jagielski if "Connector" in t: 34*0e16a31dSJim Jagielski d["conn"] = {"kind": g(s, "EdgeKind"), "start": g(s, "StartPosition"), "end": g(s, "EndPosition"), "bez": g(s, "PolyPolygonBezier")} 35*0e16a31dSJim Jagielski if "OLE2" in t: 36*0e16a31dSJim Jagielski d["ole"] = {"cls": g(s, "CLSID"), "internal": g(s, "IsInternal"), "model": embedded(tryf(lambda: s.Model, None))} 37*0e16a31dSJim Jagielski if "GraphicObject" in t: d["gr"] = gs(s, ["GraphicURL", "Transparency"])[1:] 38*0e16a31dSJim Jagielski if tryf(lambda: s.supportsService("com.sun.star.drawing.GroupShape"), False) and depth < 4: 39*0e16a31dSJim Jagielski d["kids"] = [shape(s.getByIndex(i), depth + 1) for i in range(min(s.Count, 100))] 40*0e16a31dSJim Jagielski return d 41*0e16a31dSJim Jagielskidef forms_of(page): 42*0e16a31dSJim Jagielski out = [] 43*0e16a31dSJim Jagielski try: forms = page.Forms 44*0e16a31dSJim Jagielski except Exception: return out 45*0e16a31dSJim Jagielski def walk(c): 46*0e16a31dSJim Jagielski for i in range(min(c.Count, 300)): 47*0e16a31dSJim Jagielski e = c.getByIndex(i) 48*0e16a31dSJim Jagielski if tryf(lambda: e.supportsService("com.sun.star.form.FormComponents"), False) or tryf(lambda: e.supportsService("com.sun.star.form.component.Form"), False): 49*0e16a31dSJim Jagielski out.append(["FORM", tryf(lambda: e.Name)]); walk(e) 50*0e16a31dSJim Jagielski else: 51*0e16a31dSJim Jagielski names = tryf(lambda: [p.Name for p in e.getPropertySetInfo().getProperties()], []) 52*0e16a31dSJim Jagielski out.append([tryf(lambda: e.Name), tryf(lambda: e.ImplementationName), g(e, "ObjIDinMSO") if "ObjIDinMSO" in names else "-", 53*0e16a31dSJim Jagielski tryf(lambda: e.getValueBinding() is not None, "-"), tryf(lambda: (e.getListEntrySource() is not None), "-"), len(names)]) 54*0e16a31dSJim Jagielski walk(forms) 55*0e16a31dSJim Jagielski return out 56*0e16a31dSJim Jagielskidef chart_info(m): 57*0e16a31dSJim Jagielski if m is None: return None 58*0e16a31dSJim Jagielski try: 59*0e16a31dSJim Jagielski r = {"title": tryf(lambda: m.Title.String if m.HasMainTitle else ""), "diagram": tryf(lambda: m.Diagram.ServiceName if hasattr(m.Diagram, "ServiceName") else m.getDiagram().getDiagramType()), 60*0e16a31dSJim Jagielski "addshapes": tryf(lambda: [m.DrawPage.Count, sorted(m.DrawPage.getByIndex(i).ShapeType.split(".")[-1] for i in range(m.DrawPage.Count))]), "intdata": tryf(lambda: m.hasInternalDataProvider())} 61*0e16a31dSJim Jagielski return r 62*0e16a31dSJim Jagielski except Exception: return "n/a" 63*0e16a31dSJim Jagielskidef embedded(m, depth=0): 64*0e16a31dSJim Jagielski """Dump an embedded model: drawing and spreadsheet documents fully, charts by title/type/additional shapes.""" 65*0e16a31dSJim Jagielski if m is None: return None 66*0e16a31dSJim Jagielski if depth > 1: return "<deep>" 67*0e16a31dSJim Jagielski try: 68*0e16a31dSJim Jagielski if has(m, "com.sun.star.drawing.DrawingDocument") or has(m, "com.sun.star.presentation.PresentationDocument"): return {"draw": draw(m)} 69*0e16a31dSJim Jagielski if has(m, "com.sun.star.sheet.SpreadsheetDocument"): return {"calc": calc(m)} 70*0e16a31dSJim Jagielski if has(m, "com.sun.star.chart2.ChartDocument") or has(m, "com.sun.star.chart.ChartDocument"): return chart_info(m) 71*0e16a31dSJim Jagielski return {"other": tryf(lambda: list(m.SupportedServiceNames)[:3])} 72*0e16a31dSJim Jagielski except Exception as e: return "ERR " + repr(e)[:80] 73*0e16a31dSJim Jagielskidef docprops(doc): 74*0e16a31dSJim Jagielski p = doc.DocumentProperties 75*0e16a31dSJim Jagielski ud = tryf(lambda: [[n, v(p.UserDefinedProperties.getPropertyValue(n))] for n in sorted(i.Name for i in p.UserDefinedProperties.getPropertySetInfo().getProperties())], []) 76*0e16a31dSJim Jagielski return {"title": p.Title, "subject": p.Subject, "author": p.Author, "keywords": list(p.Keywords), "desc": p.Description, "gen": p.Generator[:20] if p.Generator else "", 77*0e16a31dSJim Jagielski "print_date": v(p.PrintDate), "printed_by": p.PrintedBy, "creation_date": v(p.CreationDate), "template": p.TemplateName, "edit_cycles": p.EditingCycles, 78*0e16a31dSJim Jagielski "autoload": [p.AutoloadURL, p.AutoloadSecs], "defaulttarget": p.DefaultTarget, "userdef": ud} 79*0e16a31dSJim Jagielskidef basic(doc): 80*0e16a31dSJim Jagielski out = {} 81*0e16a31dSJim Jagielski for k in ("BasicLibraries", "DialogLibraries"): 82*0e16a31dSJim Jagielski out[k] = tryf(lambda: sorted(getattr(doc, k).ElementNames), "n/a") 83*0e16a31dSJim Jagielski return out 84*0e16a31dSJim Jagielski 85*0e16a31dSJim Jagielskidef writer(doc): 86*0e16a31dSJim Jagielski o = {} 87*0e16a31dSJim Jagielski txt = doc.Text.String 88*0e16a31dSJim Jagielski o["text_hash"] = h(txt); o["chars"] = len(txt) 89*0e16a31dSJim Jagielski paras = []; ncell = 0 90*0e16a31dSJim Jagielski e = doc.Text.createEnumeration(); tbl = 0; port_hash = [] 91*0e16a31dSJim Jagielski while e.hasMoreElements() and len(paras) < LIM: 92*0e16a31dSJim Jagielski p = e.nextElement() 93*0e16a31dSJim Jagielski if p.supportsService("com.sun.star.text.Paragraph"): 94*0e16a31dSJim Jagielski paras.append([len(p.String), g(p, "ParaStyleName"), g(p, "ParaBackColor"), g(p, "ParaBackTransparent"), g(p, "FillStyle"), g(p, "FillColor"), g(p, "FillTransparence"), 95*0e16a31dSJim Jagielski g(p, "CharHeight"), g(p, "ParaAdjust"), g(p, "ParaHyphenationMaxLeadingChars"), g(p, "ParaHyphenationMaxTrailingChars"), g(p, "ParaHyphenationMaxHyphens")]) 96*0e16a31dSJim Jagielski try: 97*0e16a31dSJim Jagielski pe = p.createEnumeration(); sig = [] 98*0e16a31dSJim Jagielski while pe.hasMoreElements(): 99*0e16a31dSJim Jagielski t = pe.nextElement(); ty = t.TextPortionType; sig.append(ty) 100*0e16a31dSJim Jagielski if ty == "TextField": sig.append(tryf(lambda: t.TextField.ServiceName if hasattr(t.TextField, "ServiceName") else ",".join(t.TextField.SupportedServiceNames))) 101*0e16a31dSJim Jagielski u = g(t, "HyperLinkURL") 102*0e16a31dSJim Jagielski if u: sig.append("URL:" + str(u)) 103*0e16a31dSJim Jagielski port_hash.append(h("|".join(map(str, sig)))) 104*0e16a31dSJim Jagielski except Exception: port_hash.append("n/a") 105*0e16a31dSJim Jagielski else: tbl += 1 106*0e16a31dSJim Jagielski o["paras"] = paras; o["nparas"] = len(paras); o["port_hash"] = h("".join(port_hash)); o["top_tables"] = tbl 107*0e16a31dSJim Jagielski ps = doc.StyleFamilies.getByName("PageStyles") 108*0e16a31dSJim Jagielski pk = ["Width", "Height", "BackColor", "BackTransparent", "FillStyle", "FillColor", "FillTransparence", "HeaderIsOn", "HeaderBackColor", "HeaderBackTransparent", "HeaderFillStyle", 109*0e16a31dSJim Jagielski "HeaderFillColor", "HeaderFillTransparence", "FooterIsOn", "FooterBackColor", "FooterBackTransparent", "FooterFillStyle", "FooterFillColor", "FooterFillTransparence", 110*0e16a31dSJim Jagielski "GridMode", "GridBaseWidth", "GridBaseHeight", "GridLines", "GridSnapToChars", "StandardPageMode", "GridRubyHeight", "GridDisplay", "GridPrint", "IsLandscape", "PageStyleLayout"] 111*0e16a31dSJim Jagielski o["pagestyles"] = {n: gs(ps.getByName(n), pk) + [bool(g(ps.getByName(n), "BackGraphicURL")), bool(g(ps.getByName(n), "HeaderBackGraphicURL")), bool(g(ps.getByName(n), "FooterBackGraphicURL"))] for n in ps.ElementNames} 112*0e16a31dSJim Jagielski pa = doc.StyleFamilies.getByName("ParagraphStyles") 113*0e16a31dSJim Jagielski ak = ["ParaBackColor", "ParaBackTransparent", "FillStyle", "FillColor", "FillTransparence", "CharHeight", "ParaHyphenationMaxLeadingChars", "ParaHyphenationMaxTrailingChars", "ParaKeepTogether", "ParaAdjust"] 114*0e16a31dSJim Jagielski o["parastyles"] = {n: gs(pa.getByName(n), ak) for n in pa.ElementNames} 115*0e16a31dSJim Jagielski cs = doc.StyleFamilies.getByName("CharacterStyles") 116*0e16a31dSJim Jagielski o["charstyles"] = {n: gs(cs.getByName(n), ["CharHeight", "CharWeight", "CharColor"]) for n in cs.ElementNames} 117*0e16a31dSJim Jagielski fs = doc.StyleFamilies.getByName("FrameStyles") 118*0e16a31dSJim Jagielski o["framestyles"] = {n: gs(fs.getByName(n), ["BackColor", "FillStyle", "FillTransparence", "FillColor", "Width", "Height"]) for n in fs.ElementNames} 119*0e16a31dSJim Jagielski tabs = [] 120*0e16a31dSJim Jagielski for i in range(min(doc.TextTables.Count, 100)): 121*0e16a31dSJim Jagielski t = doc.TextTables.getByIndex(i) 122*0e16a31dSJim Jagielski cn = list(t.CellNames) 123*0e16a31dSJim Jagielski tabs.append({"name": t.Name, "rows": t.Rows.Count, "cols": t.Columns.Count, "cells": len(cn), "cellhash": h("|".join(cn) + "".join(tryf(lambda: t.getCellByName(c).String, "") for c in cn[:300])), 124*0e16a31dSJim Jagielski "split": [tryf(lambda: t.Rows.getByIndex(r).IsSplitAllowed) for r in range(min(t.Rows.Count, 50))], "bg": g(t, "BackColor"), "kt": g(t, "Split")}) 125*0e16a31dSJim Jagielski o["tables"] = tabs 126*0e16a31dSJim Jagielski fld = [] 127*0e16a31dSJim Jagielski en = doc.TextFields.createEnumeration() 128*0e16a31dSJim Jagielski while en.hasMoreElements() and len(fld) < LIM: 129*0e16a31dSJim Jagielski f = en.nextElement() 130*0e16a31dSJim Jagielski sn = tryf(lambda: ",".join(f.SupportedServiceNames)) 131*0e16a31dSJim Jagielski r = [sn.replace("com.sun.star.text.", "")[:120]] 132*0e16a31dSJim Jagielski if "GetReference" in sn: r += gs(f, ["ReferenceFieldPart", "ReferenceFieldSource", "SourceName", "SequenceNumber"]) 133*0e16a31dSJim Jagielski if "URL" in sn: r += gs(f, ["URL", "Representation"]) 134*0e16a31dSJim Jagielski fld.append(r) 135*0e16a31dSJim Jagielski o["fields"] = fld 136*0e16a31dSJim Jagielski o["footnotes"] = [doc.Footnotes.Count, [tryf(lambda: doc.Footnotes.getByIndex(i).String[:30], "") for i in range(min(doc.Footnotes.Count, 30))]] 137*0e16a31dSJim Jagielski o["endnotes"] = [doc.Endnotes.Count, [tryf(lambda: doc.Endnotes.getByIndex(i).String[:30], "") for i in range(min(doc.Endnotes.Count, 30))]] 138*0e16a31dSJim Jagielski fr = [] 139*0e16a31dSJim Jagielski for coll, name in ((doc.TextFrames, "frame"), (doc.GraphicObjects, "graphic"), (doc.EmbeddedObjects, "embedded")): 140*0e16a31dSJim Jagielski for n in coll.ElementNames[:100]: 141*0e16a31dSJim Jagielski f = coll.getByName(n) 142*0e16a31dSJim Jagielski fr.append([name, n, g(f, "AnchorType"), g(f, "AnchorPageNo"), g(f, "Width"), g(f, "Height"), g(f, "BackColor"), g(f, "FillTransparence"), g(f, "Transparency"), g(f, "FillStyle"), g(f, "HoriOrientPosition"), g(f, "VertOrientPosition")]) 143*0e16a31dSJim Jagielski if name == "embedded": fr[-1].append(embedded(tryf(lambda: f.Model, None))) 144*0e16a31dSJim Jagielski o["frames"] = fr 145*0e16a31dSJim Jagielski sec = [] 146*0e16a31dSJim Jagielski for n in doc.TextSections.ElementNames[:100]: 147*0e16a31dSJim Jagielski s = doc.TextSections.getByName(n); sec.append([n, g(s, "FileLink"), g(s, "LinkRegion"), g(s, "IsProtected"), g(s, "IsVisible")]) 148*0e16a31dSJim Jagielski o["sections"] = sec 149*0e16a31dSJim Jagielski rl = [] 150*0e16a31dSJim Jagielski try: 151*0e16a31dSJim Jagielski en = doc.Redlines.createEnumeration() 152*0e16a31dSJim Jagielski while en.hasMoreElements() and len(rl) < 100: 153*0e16a31dSJim Jagielski r = en.nextElement(); rl.append([g(r, "RedlineType"), g(r, "RedlineAuthor"), g(r, "RedlineDateTime"), g(r, "RedlineComment"), g(r, "RedlineSuccessorData") != "n/a" and bool(g(r, "RedlineSuccessorData"))]) 154*0e16a31dSJim Jagielski except Exception: rl = "n/a" 155*0e16a31dSJim Jagielski o["redlines"] = rl 156*0e16a31dSJim Jagielski o["bookmarks"] = tryf(lambda: sorted(doc.Bookmarks.ElementNames)) 157*0e16a31dSJim Jagielski o["refmarks"] = tryf(lambda: sorted(doc.ReferenceMarks.ElementNames)) 158*0e16a31dSJim Jagielski o["indexes"] = tryf(lambda: doc.DocumentIndexes.Count) 159*0e16a31dSJim Jagielski o["shapes"] = [shape(doc.DrawPage.getByIndex(i)) for i in range(min(doc.DrawPage.Count, 150))] 160*0e16a31dSJim Jagielski o["forms"] = forms_of(doc.DrawPage) 161*0e16a31dSJim Jagielski o["nstyles"] = {k: len(doc.StyleFamilies.getByName(k).ElementNames) for k in doc.StyleFamilies.ElementNames} 162*0e16a31dSJim Jagielski return o 163*0e16a31dSJim Jagielski 164*0e16a31dSJim Jagielskidef calc(doc): 165*0e16a31dSJim Jagielski o = {"sheets": []} 166*0e16a31dSJim Jagielski nfs = doc.NumberFormats; ftype = {} 167*0e16a31dSJim Jagielski def ft(k): 168*0e16a31dSJim Jagielski if k not in ftype: ftype[k] = tryf(lambda: nfs.getByKey(k).Type) 169*0e16a31dSJim Jagielski return ftype[k] 170*0e16a31dSJim Jagielski for i in range(doc.Sheets.Count): 171*0e16a31dSJim Jagielski sh = doc.Sheets.getByIndex(i) 172*0e16a31dSJim Jagielski cur = sh.createCursor(); cur.gotoEndOfUsedArea(False) 173*0e16a31dSJim Jagielski rng = sh.getCellRangeByPosition(0, 0, cur.RangeAddress.EndColumn, cur.RangeAddress.EndRow) 174*0e16a31dSJim Jagielski if cur.RangeAddress.EndColumn > 300 or cur.RangeAddress.EndRow > 3000: 175*0e16a31dSJim Jagielski rng = sh.getCellRangeByPosition(0, 0, min(cur.RangeAddress.EndColumn, 300), min(cur.RangeAddress.EndRow, 3000)) 176*0e16a31dSJim Jagielski da = rng.DataArray; fa = rng.FormulaArray 177*0e16a31dSJim Jagielski so = {"name": sh.Name, "end": [cur.RangeAddress.EndColumn, cur.RangeAddress.EndRow], "data_hash": h(repr(da)), "formula_hash": h(repr(fa)), 178*0e16a31dSJim Jagielski "nformulas": sum(1 for r in fa for c in r if isinstance(c, str) and c.startswith("="))} 179*0e16a31dSJim Jagielski cells = [] 180*0e16a31dSJim Jagielski nrow = min(len(da), 400) 181*0e16a31dSJim Jagielski for r in range(nrow): 182*0e16a31dSJim Jagielski for c in range(min(len(da[r]), 60)): 183*0e16a31dSJim Jagielski if da[r][c] != "" and da[r][c] is not None: 184*0e16a31dSJim Jagielski cell = rng.getCellByPosition(c, r) 185*0e16a31dSJim Jagielski cells.append([r, c, ft(cell.NumberFormat), cell.getError(), cell.Type.value]) 186*0e16a31dSJim Jagielski so["cells_hash"] = h(repr(cells)); so["ncells"] = len(cells) 187*0e16a31dSJim Jagielski so["errors"] = sum(1 for x in cells if x[3]) 188*0e16a31dSJim Jagielski so["annotations"] = [sh.Annotations.Count, h("".join(tryf(lambda: sh.Annotations.getByIndex(k).String, "") for k in range(min(sh.Annotations.Count, 100))))] 189*0e16a31dSJim Jagielski so["charts"] = {n: chart_info(tryf(lambda: sh.Charts.getByName(n).EmbeddedObject, None)) for n in sh.Charts.ElementNames[:30]} 190*0e16a31dSJim Jagielski urls = [] 191*0e16a31dSJim Jagielski for r in range(nrow): 192*0e16a31dSJim Jagielski for c in range(min(len(da[r]), 40)): 193*0e16a31dSJim Jagielski if isinstance(fa[r][c], str) and fa[r][c] and not fa[r][c].startswith("="): 194*0e16a31dSJim Jagielski cell = rng.getCellByPosition(c, r) 195*0e16a31dSJim Jagielski try: 196*0e16a31dSJim Jagielski en = cell.Text.createEnumeration() 197*0e16a31dSJim Jagielski while en.hasMoreElements(): 198*0e16a31dSJim Jagielski pe = en.nextElement().createEnumeration() 199*0e16a31dSJim Jagielski while pe.hasMoreElements(): 200*0e16a31dSJim Jagielski pt = pe.nextElement() 201*0e16a31dSJim Jagielski if pt.TextPortionType == "TextField": urls.append([r, c, tryf(lambda: pt.TextField.URL), tryf(lambda: pt.TextField.Representation)]) 202*0e16a31dSJim Jagielski except Exception: pass 203*0e16a31dSJim Jagielski if len(urls) > 100: break 204*0e16a31dSJim Jagielski so["urls"] = urls 205*0e16a31dSJim Jagielski so["shapes"] = [shape(sh.DrawPage.getByIndex(k)) for k in range(min(sh.DrawPage.Count, 100))] 206*0e16a31dSJim Jagielski so["forms"] = forms_of(sh.DrawPage) 207*0e16a31dSJim Jagielski so["pagestyle"] = sh.PageStyle 208*0e16a31dSJim Jagielski so["flags"] = gs(sh, ["IsVisible", "IsProtected"]) 209*0e16a31dSJim Jagielski o["sheets"].append(so) 210*0e16a31dSJim Jagielski o["dde"] = tryf(lambda: [[n, doc.DDELinks.getByName(n).Application, doc.DDELinks.getByName(n).Topic, doc.DDELinks.getByName(n).Item] for n in doc.DDELinks.ElementNames]) 211*0e16a31dSJim Jagielski o["names"] = tryf(lambda: sorted(doc.NamedRanges.ElementNames)) 212*0e16a31dSJim Jagielski ps = doc.StyleFamilies.getByName("PageStyles") 213*0e16a31dSJim Jagielski o["pagestyles"] = {n: gs(ps.getByName(n), ["BackColor", "BackTransparent", "FillStyle", "HeaderIsOn", "FooterIsOn", "IsLandscape", "Width", "Height", "ScaleToPagesX"]) for n in ps.ElementNames} 214*0e16a31dSJim Jagielski cs = doc.StyleFamilies.getByName("CellStyles") 215*0e16a31dSJim Jagielski o["cellstyles"] = {n: gs(cs.getByName(n), ["CellBackColor", "IsCellBackgroundTransparent", "CharHeight", "NumberFormat"]) for n in cs.ElementNames} 216*0e16a31dSJim Jagielski return o 217*0e16a31dSJim Jagielski 218*0e16a31dSJim Jagielskidef draw(doc): 219*0e16a31dSJim Jagielski o = {"pages": []} 220*0e16a31dSJim Jagielski pages = doc.DrawPages 221*0e16a31dSJim Jagielski for i in range(pages.Count): 222*0e16a31dSJim Jagielski pg = pages.getByIndex(i) 223*0e16a31dSJim Jagielski po = {"name": tryf(lambda: pg.Name), "shapes": [shape(pg.getByIndex(k)) for k in range(min(pg.Count, 300))], "forms": forms_of(pg), 224*0e16a31dSJim Jagielski "layout": g(pg, "Layout"), "bg": tryf(lambda: gs(pg.Background, ["FillStyle", "FillColor", "FillTransparence", "FillGradientName"])), "master": tryf(lambda: pg.MasterPage.Name)} 225*0e16a31dSJim Jagielski if has(doc, "com.sun.star.presentation.PresentationDocument"): 226*0e16a31dSJim Jagielski po["notes"] = tryf(lambda: [pg.NotesPage.getByIndex(k).String[:40] for k in range(min(pg.NotesPage.Count, 20)) if hasattr(pg.NotesPage.getByIndex(k), "String")], "n/a") 227*0e16a31dSJim Jagielski o["pages"].append(po) 228*0e16a31dSJim Jagielski masters = doc.MasterPages 229*0e16a31dSJim Jagielski o["masters"] = [[tryf(lambda: masters.getByIndex(i).Name), len(shape_list(masters.getByIndex(i)))] for i in range(masters.Count)] 230*0e16a31dSJim Jagielski for fam in ("graphics", "Default"): 231*0e16a31dSJim Jagielski pass 232*0e16a31dSJim Jagielski try: 233*0e16a31dSJim Jagielski gf = doc.StyleFamilies.getByName("graphics") 234*0e16a31dSJim Jagielski o["graphicstyles"] = {n: gs(gf.getByName(n), ["FillStyle", "FillColor", "FillTransparence", "CharHeight", "LineStyle", "LineColor", "TextWritingMode"]) for n in gf.ElementNames} 235*0e16a31dSJim Jagielski except Exception: pass 236*0e16a31dSJim Jagielski return o 237*0e16a31dSJim Jagielskidef shape_list(pg): return [shape(pg.getByIndex(k)) for k in range(min(pg.Count, 300))] 238*0e16a31dSJim Jagielski 239*0e16a31dSJim JagielskiDESK = desktop(connect(port)) 240*0e16a31dSJim Jagielskios.makedirs(outdir, exist_ok=True) 241*0e16a31dSJim Jagielskifor f in files: 242*0e16a31dSJim Jagielski dest = os.path.join(outdir, os.path.basename(f) + ".json") 243*0e16a31dSJim Jagielski if os.path.exists(dest): continue 244*0e16a31dSJim Jagielski open(os.path.join(outdir, ".current"), "w").write(f) 245*0e16a31dSJim Jagielski out = {} 246*0e16a31dSJim Jagielski try: 247*0e16a31dSJim Jagielski doc = load(DESK, f) 248*0e16a31dSJim Jagielski out["type"] = ("writer" if has(doc, "com.sun.star.text.TextDocument") else "calc" if has(doc, "com.sun.star.sheet.SpreadsheetDocument") 249*0e16a31dSJim Jagielski else "impress" if has(doc, "com.sun.star.presentation.PresentationDocument") else "draw" if has(doc, "com.sun.star.drawing.DrawingDocument") else "other") 250*0e16a31dSJim Jagielski out["props"] = tryf(lambda: docprops(doc), "ERR") 251*0e16a31dSJim Jagielski out["basic"] = basic(doc) 252*0e16a31dSJim Jagielski try: 253*0e16a31dSJim Jagielski out["body"] = {"writer": writer, "calc": calc, "impress": draw, "draw": draw}.get(out["type"], lambda d: {})(doc) 254*0e16a31dSJim Jagielski except Exception as e: 255*0e16a31dSJim Jagielski out["body_error"] = repr(e)[:200] 256*0e16a31dSJim Jagielski doc.close(True) 257*0e16a31dSJim Jagielski except Exception as e: 258*0e16a31dSJim Jagielski out["error"] = repr(e)[:200] 259*0e16a31dSJim Jagielski json.dump(out, open(dest, "w"), sort_keys=True, indent=0, default=str) 260*0e16a31dSJim Jagielskiprint("done", len(files)) 261