CSSSheet *CSSSheetNew(void)
{
    CSSSheet *sheet = (CSSSheet *)xcalloc(1,sizeof(CSSSheet));
    sheet->retainCount = 1;
    sheet->_styles = DFHashTableNew((DFCopyFunction)CSSStyleRetain,(DFFreeFunction)CSSStyleRelease);
    sheet->_defaultStyles = DFHashTableNew((DFCopyFunction)CSSStyleRetain,(DFFreeFunction)CSSStyleRelease);
    return sheet;
}
Exemple #2
0
CSSProperties *CSSPropertiesNewWithExtra(CSSProperties *orig, const char *string)
{
    DFHashTable *extra = CSSParseProperties(string);
    CSSExpandProperties(extra);

    CSSProperties *result = (CSSProperties *)calloc(1,sizeof(CSSProperties));
    result->retainCount = 1;
    result->hashTable = DFHashTableNew((DFCopyFunction)strdup,free);
    const char **names = DFHashTableCopyKeys(orig->hashTable);
    for (int i = 0; names[i]; i++) {
        const char *value = DFHashTableLookup(orig->hashTable,names[i]);
        DFHashTableAdd(result->hashTable,names[i],(void *)value);
    }
    free(names);

    const char **keys = DFHashTableCopyKeys(extra);
    for (int i = 0; keys[i]; i++) {
        const char *key = keys[i];
        const char *value = DFHashTableLookup(extra,key);
        DFHashTableAdd(result->hashTable,key,value);
    }
    free(keys);

    DFHashTableRelease(extra);
    return result;
}
DFHashTable *CSSParserRules(CSSParser *p)
{
    DFHashTable *result = DFHashTableNew((DFCopyFunction)xstrdup,free);
    while (p->pos < p->length) {
        size_t start = p->pos;
        int invalid = 0;
        if (!matchBefore(p,'{',&invalid))
            return result;
        char *selectors = trimmedSubstring(p,start,p->pos);
        if (strlen(selectors) == 0) {
            free(selectors);
            break;
        }
        if (!match(p,'{')) {
            CSSParserSetError(p,"Expected {");
            free(selectors);
            return result;
        }
        start = p->pos;
        if (!matchBefore(p,'}',&invalid)) {
            free(selectors);
            return result;
        }
        char *ruleBody = trimmedSubstring(p,start,p->pos);
        if (!match(p,'}')) {
            CSSParserSetError(p,"Expected }");
        }

        DFHashTableAdd(result,selectors,ruleBody);
        free(selectors);
        free(ruleBody);
    }
    return result;
}
CSSStyle *CSSSheetFlattenedStyle(CSSSheet *sheet, CSSStyle *orig)
{
    // FIXME: Need tests for parent cycles
    CSSStyle *ancestor = orig;
    CSSStyle *result = CSSStyleNew("temp");
    DFHashTable *visited = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
    const char **allSuffixes = NULL;
    while (1) {
        free(allSuffixes);
        allSuffixes = CSSStyleCopySuffixes(ancestor);
        for (int suffixIndex = 0; allSuffixes[suffixIndex]; suffixIndex++) {
            const char *suffix = allSuffixes[suffixIndex];
            CSSProperties *origProperties = CSSStyleRuleForSuffix(ancestor,suffix);
            CSSProperties *collapsedProperties = CSSStyleRuleForSuffix(result,suffix);

            const char **allNames = CSSPropertiesCopyNames(origProperties);
            for (int nameIndex = 0; allNames[nameIndex]; nameIndex++) {
                const char *name = allNames[nameIndex];
                if (!strcmp(name,"-uxwrite-default") && (ancestor != orig))
                    continue;
                if (CSSGet(collapsedProperties,name) == NULL)
                    CSSPut(collapsedProperties,name,CSSGet(origProperties,name));
            }
            free(allNames);
        }
        DFHashTableAdd(visited,ancestor->selector,"");
        ancestor = CSSSheetGetStyleParent(sheet,ancestor);
        if ((ancestor == NULL) || (DFHashTableLookup(visited,ancestor->selector) != NULL))
            break;
    }
    free(allSuffixes);
    DFHashTableRelease(visited);
    return result;
}
Exemple #5
0
WordConverter *WordConverterNew(DFDocument *html, const char *abstractPath,
                                const char *idPrefix, WordPackage *package,
                                DFBuffer *warnings)
{
    WordConverter *converter = (WordConverter *)calloc(1,sizeof(WordConverter));
    if ((abstractPath == NULL) || (strlen(abstractPath) == 0))
        abstractPath = ".";
    converter->html = DFDocumentRetain(html);
    converter->abstractPath = strdup(abstractPath);
    converter->concretePath = strdup(package->tempPath);
    converter->idPrefix = DFStrDup(idPrefix);
    converter->package = WordPackageRetain(package);
    converter->styles = WordSheetNew(converter->package->styles);
    converter->numbering = WordNumberingNew(converter->package);
    converter->theme = WordThemeNew(converter->package);
    converter->mainSection = WordSectionNew();
    converter->objects = WordObjectsNew(converter->package);
    converter->footnotes = WordNoteGroupNewFootnotes(converter->package->footnotes);
    converter->endnotes = WordNoteGroupNewEndnotes(converter->package->endnotes);
    converter->supportedContentTypes = DFHashTableNew((DFCopyFunction)strdup,free);
    DFHashTableAdd(converter->supportedContentTypes,"jpg","image/jpeg");
    DFHashTableAdd(converter->supportedContentTypes,"jpeg","image/jpeg");
    DFHashTableAdd(converter->supportedContentTypes,"tif","image/tiff");
    DFHashTableAdd(converter->supportedContentTypes,"tiff","image/tiff");
    DFHashTableAdd(converter->supportedContentTypes,"gif","image/gif");
    DFHashTableAdd(converter->supportedContentTypes,"bmp","image/bmp");
    DFHashTableAdd(converter->supportedContentTypes,"png","image/png");
    converter->warnings = DFBufferRetain(warnings);
    return converter;
}
Exemple #6
0
static char *genImageFilename(const char *mediaDir, const char *extension, DFError **error)
{
    const char **names = DFContentsOfDirectory(mediaDir,0,error);
    if (names == NULL)
        return NULL;

    DFHashTable *existingNames = DFHashTableNew((DFCopyFunction)strdup,free);
    for (int i = 0; names[i]; i++) {
        const char *filename = names[i];
        char *lowerFilename = DFLowerCase(filename);
        char *noExtension = DFPathWithoutExtension(lowerFilename);
        DFHashTableAdd(existingNames,noExtension,noExtension);
        free(lowerFilename);
        free(noExtension);
    }

    int num = 1;
    char *candidate = NULL;
    do {
        free(candidate);
        candidate = DFFormatString("image%d",num);
        num++;
    } while (DFHashTableLookup(existingNames,candidate) != NULL);

    char *result = DFFormatString("%s.%s",candidate,extension);

    free(candidate);
    free(names);
    DFHashTableRelease(existingNames);
    return result;
}
Exemple #7
0
static TextPackage *TextPackageNew(void)
{
    TextPackage *package = (TextPackage *)calloc(1,sizeof(TextPackage));
    package->retainCount = 1;
    package->items = DFHashTableNew((DFCopyFunction)strdup,free);
    package->keys = (char **)calloc(1,sizeof(char *));
    return package;
}
Exemple #8
0
ODFManifest *ODFManifestNewWithDoc(DFDocument *doc)
{
    ODFManifest *manifest = (ODFManifest *)calloc(1,sizeof(ODFManifest));
    manifest->doc = DFDocumentRetain(doc);
    manifest->entriesByPath = DFHashTableNew(NULL,NULL);
    ODFManifestParse(manifest);
    return manifest;
}
Exemple #9
0
ODFManifest *ODFManifestNew(void)
{
    ODFManifest *manifest = (ODFManifest *)calloc(1,sizeof(ODFManifest));
    manifest->retainCount = 1;
    manifest->doc = DFDocumentNewWithRoot(MF_MANIFEST);
    manifest->entriesByPath = DFHashTableNew(NULL,NULL);
    return manifest;
}
void WordGarbageCollect(WordPackage *package)
{
    assert(package->documentPart != NULL);
    assert(package->document != NULL);
    DFHashTable *referencedIds = DFHashTableNew(NULL,NULL); // used as a set
    collect(package,referencedIds);
    DFHashTableRelease(referencedIds);
}
Exemple #11
0
void WordBookmarks_collapseNew(DFDocument *doc)
{
    putInParagraphsRecursive(doc->docNode);
    DFHashTable *bookmarksById = DFHashTableNew(NULL,(DFFreeFunction)WordRawBookmarkFree);
    int offset = 0;
    findBookmarkSizes(doc->root,bookmarksById,&offset);
    collapseRecursive(doc->root,bookmarksById);
    DFHashTableRelease(bookmarksById);
}
Exemple #12
0
CSSProperties *CSSPropertiesNewWithRaw(DFHashTable *raw)
{
    CSSProperties *result = (CSSProperties *)calloc(1,sizeof(CSSProperties));
    result->retainCount = 1;

    result->hashTable = DFHashTableNew((DFCopyFunction)strdup,free);
    if (raw != NULL)
        CSSPropertiesUpdateFromRaw(result,raw);

    return result;
}
Exemple #13
0
static void updateFromRawCSSRules(CSSSheet *sheet, DFHashTable *rules)
{
    // FIXME: Handle class names containing escape sequences
    DFHashTableRelease(sheet->_styles);
    sheet->_styles = DFHashTableNew((DFCopyFunction)CSSStyleRetain,(DFFreeFunction)CSSStyleRelease);

    const char **sortedSelectors = DFHashTableCopyKeys(rules);
    DFSortStringsCaseInsensitive(sortedSelectors);
    for (int selIndex = 0; sortedSelectors[selIndex]; selIndex++) {
        const char *constSelector = sortedSelectors[selIndex];

        // Treat any selectors specifying the class name only as paragraph styles
        char *selector;
        if (!strncmp(constSelector,".",1))
            selector = DFFormatString("p%s",constSelector); // FIXME: Not covered by tests
        else
            selector = xstrdup(constSelector);

        DFHashTable *raw = DFHashTableLookup(rules,constSelector);
        char *baseId = NULL;
        char *suffix = NULL;
        CSSParseSelector(selector,&baseId,&suffix);

        CSSStyle *style = CSSSheetLookupSelector(sheet,baseId,0,0);
        if (style == NULL) {
            style = CSSStyleNew(baseId);
            CSSSheetAddStyle(sheet,style);
            CSSStyleRelease(style);
        }

        CSSProperties *properties = CSSStyleRuleForSuffix(style,suffix);
        CSSProperties *expanded = CSSPropertiesNewWithRaw(raw);

        const char **allNames = CSSPropertiesCopyNames(expanded);
        for (int nameIndex = 0; allNames[nameIndex]; nameIndex++) {
            const char *name = allNames[nameIndex];
            CSSPut(properties,name,CSSGet(expanded,name));
        }
        free(allNames);

        if (!strcmp(suffix,"")) {
            const char *defaultVal = CSSGet(properties,"-uxwrite-default");
            if ((defaultVal != NULL) && DFStringEqualsCI(defaultVal,"true"))
                CSSSheetSetDefaultStyle(sheet,style,StyleFamilyFromHTMLTag(style->tag));
        }
        CSSPropertiesRelease(expanded);
        free(baseId);
        free(suffix);
        free(selector);
    }
    free(sortedSelectors);
    removeRedundantProperties(sheet);
}
static DFHashTable *WordSheetFindUsedConcreteNumIds(WordSheet *sheet)
{
    DFHashTable *concreteNumIds = DFHashTableNew(NULL,NULL); // Used as a set
    const char **allIdents = WordSheetCopyIdents(sheet);
    for (int i = 0; allIdents[i]; i++) {
        const char *ident = allIdents[i];
        WordStyle *style = WordSheetStyleForIdent(sheet,ident);
        DFNode *pPr = DFChildWithTag(style->element,WORD_PPR);
        DFNode *numPr = DFChildWithTag(pPr,WORD_NUMPR);
        const char *numId = DFGetChildAttribute(numPr,WORD_NUMID,WORD_VAL);
        if (numId != NULL)
            DFHashTableAdd(concreteNumIds,numId,"");
    }
    free(allIdents);
    return concreteNumIds;
}
Exemple #15
0
static DFHashTable *getStylesByHeadingLevel(CSSSheet *sheet)
{
    DFHashTable *stylesByHeadingLevel = DFHashTableNew(NULL,NULL);
    const char **allSelectors = CSSSheetCopySelectors(sheet);
    for (int i = 0; allSelectors[i]; i++) {
        CSSStyle *style = CSSSheetLookupSelector(sheet,allSelectors[i],0,0);
        if (style->headingLevel > 0) {
            int headingLevel = style->headingLevel;
            StyleList *item = (StyleList *)xcalloc(1,sizeof(StyleList));
            item->style = CSSStyleRetain(style);
            item->next = DFHashTableLookupInt(stylesByHeadingLevel,headingLevel);
            DFHashTableAddInt(stylesByHeadingLevel,headingLevel,item);
        }
    }
    free(allSelectors);
    return stylesByHeadingLevel;
}
Exemple #16
0
DFHashTable *CSSSheetRules(CSSSheet *sheet)
{
    DFHashTable *result = DFHashTableNew((DFCopyFunction)DFHashTableRetain,(DFFreeFunction)DFHashTableRelease);
    const char **allSelectors = CSSSheetCopySelectors(sheet);
    for (int selIndex = 0; allSelectors[selIndex]; selIndex++) {
        const char *selector = allSelectors[selIndex];
        CSSStyle *origStyle = CSSSheetLookupSelector(sheet,selector,0,0);
        if ((origStyle == NULL) || origStyle->latent)
            continue;

        char *elementName = CSSSelectorCopyElementName(selector);
        char *className = CSSSelectorCopyClassName(selector);

        char *baseSelector;
        if (className != NULL) {
            char *escapedClassName = CSSEscapeIdent(className);
            baseSelector = DFFormatString("%s.%s",elementName,escapedClassName);
            free(escapedClassName);
        }
        else {
            baseSelector = xstrdup(elementName);
        }

        CSSStyle *flattenedStyle = CSSSheetFlattenedStyle(sheet,origStyle);
        const char **allSuffixes = CSSStyleCopySuffixes(flattenedStyle);
        for (int suffixIndex = 0; allSuffixes[suffixIndex]; suffixIndex++) {
            const char *suffix = allSuffixes[suffixIndex];
            char *fullSelector = DFFormatString("%s%s",baseSelector,suffix);
            CSSProperties *properties = CSSStyleRuleForSuffix(flattenedStyle,suffix);
            DFHashTable *collapsed = CSSCollapseProperties(properties);
            if (!((DFHashTableCount(collapsed) == 0) && ((strlen(suffix) > 0) || CSSIsBuiltinSelector(selector))))
                DFHashTableAdd(result,fullSelector,collapsed);
            free(fullSelector);
            DFHashTableRelease(collapsed);
        }
        free(allSuffixes);

        CSSStyleRelease(flattenedStyle);
        free(elementName);
        free(className);
        free(baseSelector);
    }
    free(allSelectors);
    return result;
}
static char *Word_toPlainFromDir(DFStorage *storage, DFHashTable *parts, DFError **error)
{
    char *documentPath = NULL;
    DFHashTable *rels = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
    DFBuffer *output = DFBufferNew();
    char *relsPathRel = NULL;
    DFDocument *relsDoc = NULL;
    int ok = 0;


    documentPath = findDocumentPath(storage,error);
    if (documentPath == NULL) {
        DFErrorFormat(error,"findDocumentPath: %s",DFErrorMessage(error));
        goto end;
    }

    relsPathRel = computeDocumentRelsPath(documentPath);
    if (DFStorageExists(storage,relsPathRel) && ((relsDoc = DFParseXMLStorage(storage,relsPathRel,error)) == NULL)) {
        DFErrorFormat(error,"%s: %s",relsPathRel,DFErrorMessage(error));
        goto end;
    }

    parseDocumentRels(documentPath,relsDoc,rels,error);

    if (!processParts(parts,documentPath,relsDoc,rels,output,storage,error))
        goto end;

    ok = 1;

end:
    free(relsPathRel);
    free(documentPath);
    DFHashTableRelease(rels);
    DFDocumentRelease(relsDoc);
    if (!ok) {
        DFBufferRelease(output);
        return NULL;
    }
    else {
        char *result = xstrdup(output->data);
        DFBufferRelease(output);
        return result;
    }
}
Exemple #18
0
void CSSSheetUpdateFromCSSText(CSSSheet *sheet, const char *cssText)
{
    DFHashTable *rules = DFHashTableNew((DFCopyFunction)DFHashTableRetain,(DFFreeFunction)DFHashTableRelease);

    CSSParser *parser = CSSParserNew(cssText);
    DFHashTable *top = CSSParserRules(parser);
    CSSParserFree(parser);

    const char **allSelectorsText = DFHashTableCopyKeys(top);
    for (int i = 0; allSelectorsText[i]; i++) {
        const char *selectorsText = allSelectorsText[i];
        const char *propertiesText = DFHashTableLookup(top,selectorsText);

        parser = CSSParserNew(selectorsText);
        DFArray *selectors = CSSParserSelectors(parser);
        CSSParserFree(parser);
        if (selectors == NULL)
            continue;

        parser = CSSParserNew(propertiesText);
        DFHashTable *properties = CSSParserProperties(parser);
        CSSParserFree(parser);
        if (properties == NULL) {
            DFArrayRelease(selectors);
            continue;
        }

        for (size_t selIndex = 0; selIndex < DFArrayCount(selectors); selIndex++) {
            const char *selector = DFArrayItemAt(selectors,selIndex);
            DFHashTableAdd(rules,selector,properties);
        }

        DFHashTableRelease(properties);
        DFArrayRelease(selectors);
    }

    updateFromRawCSSRules(sheet,rules);
    free(allSelectorsText);
    DFHashTableRelease(top);
    DFHashTableRelease(rules);
}
void DFMarkupCompatibilityPush(DFMarkupCompatibility *mc, int nb_namespaces, const char **namespaces, DFNameMap *map)
{
    mc->depth++;
    if (mc->depth < MAX_DEPTH) {
        MCRecord *record = &mc->records[mc->depth-1];
        bzero(record,sizeof(MCRecord));
        if (nb_namespaces > 0) {
            record->namespaces = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
            for (int i = 0; i < nb_namespaces; i++) {
                const char *nsPrefix = namespaces[i*2];
                const char *nsURI = namespaces[i*2+1];
                NamespaceID nsId = DFNameMapFoundNamespace(map,nsURI,nsPrefix);
                char nsIdStr[20];
                snprintf(nsIdStr,20,"%u",nsId);
                const char *prefix = "";
                if (nsPrefix != NULL)
                    prefix = (const char *)nsPrefix;
                DFHashTableAdd(record->namespaces,prefix,nsIdStr);
            }
        }
    }
}
Exemple #20
0
static void breakCycles(CSSSheet *sheet)
{
    // FIXME: Not covered by tests
    const char **allSelectors = CSSSheetCopySelectors(sheet);
    for (int i = 0; allSelectors[i]; i++) {
        const char *selector = allSelectors[i];
        CSSStyle *style = CSSSheetLookupSelector(sheet,selector,0,0);
        DFHashTable *visited = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
        int depth = 0;

        while (style != NULL) {
            if (DFHashTableLookup(visited,style->selector) != NULL) {
                CSSStyleSetParent(style,NULL);
                break;
            }
            DFHashTableAdd(visited,style->selector,"");
            style = CSSSheetGetStyleParent(sheet,style);
            depth++;
        }
        DFHashTableRelease(visited);
    }
    free(allSelectors);
}
DFHashTable *CSSParserProperties(CSSParser *p)
{
    DFHashTable *result = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
    while (p->pos < p->length) {
        size_t start = p->pos;
        int invalid = 0;
        if (!matchBefore(p,':',&invalid)) {
            DFHashTableRelease(result);
            return NULL;
        }
        char *name = trimmedSubstring(p,start,p->pos);
        if (strlen(name) == 0) {
            free(name);
            break;
        }
        if (!match(p,':')) {
            CSSParserSetError(p,"Missing :");
            DFHashTableRelease(result);
            free(name);
            return NULL;
        }
        start = p->pos;
        if (!matchBefore(p,';',&invalid)) {
            DFHashTableRelease(result);
            free(name);
            return NULL;
        }
        if (!invalid) {
            char *value = trimmedSubstring(p,start,p->pos);
            DFHashTableAdd(result,name,value);
            free(value);
        }
        match(p,';');
        free(name);
    }
    return result;
}
static int processParts(DFHashTable *parts, const char *documentPath, DFDocument *relsDoc,
                        DFHashTable *documentRels,
                        DFBuffer *output, DFStorage *storage, DFError **error)
{
    int ok = 0;
    DFHashTable *includeTypes = DFHashTableNew((DFCopyFunction)xstrdup,free);
    DFHashTableAdd(includeTypes,WORDREL_HYPERLINK,"");
    DFHashTableAdd(includeTypes,WORDREL_IMAGE,"");

    if ((parts == NULL) || (DFHashTableLookup(parts,"document") != NULL)) {
        DFDocument *doc = DFParseXMLStorage(storage,documentPath,error);
        if (doc == NULL)
            goto end;
        addStrippedSerializedDoc(output,doc,"document.xml");
        DFDocumentRelease(doc);
    }

    if ((parts == NULL) || (DFHashTableLookup(parts,"styles") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_STYLES,"styles.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts == NULL) || (DFHashTableLookup(parts,"numbering") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_NUMBERING,"numbering.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts == NULL) || (DFHashTableLookup(parts,"footnotes") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_FOOTNOTES,"footnotes.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts == NULL) || (DFHashTableLookup(parts,"endnotes") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_ENDNOTES,"endnotes.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts != NULL) && (DFHashTableLookup(parts,"settings") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_SETTINGS,"settings.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts != NULL) && (DFHashTableLookup(parts,"theme") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_THEME,"theme.xml",output,includeTypes,storage,error))
            goto end;
    }

    if ((DFHashTableLookup(documentRels,WORDREL_HYPERLINK) != NULL) ||
        (DFHashTableLookup(documentRels,WORDREL_IMAGE) != NULL) ||
        ((parts != NULL) && (DFHashTableLookup(parts,"documentRels") != NULL))) {
        if (relsDoc == NULL) {
            DFErrorFormat(error,"document.xml.rels does not exist");
            goto end;
        }
        DFNode *next;
        for (DFNode *child = relsDoc->root->first; child != NULL; child = next) {
            next = child->next;
            if (child->tag != REL_RELATIONSHIP)
                continue;
            const char *type = DFGetAttribute(child,NULL_Type);
            if ((type != NULL) && (DFHashTableLookup(includeTypes,type) == NULL)) {
                DFRemoveNode(child);
            }
        }
        addSerializedDoc(output,relsDoc,"document.xml.rels");
    }

    const char **entries = DFStorageList(storage,NULL);
    if (entries != NULL) { // FIXME: Should really report an error if this is not the case
        for (int i = 0; entries[i]; i++) {
            const char *filename = entries[i];
            char *extension = DFPathExtension(filename);
            if (DFStringEqualsCI(extension,"png") || DFStringEqualsCI(extension,"jpg")) {
                char *absFilename;
                if (!DFStringHasSuffix(filename,"/"))
                    absFilename = DFFormatString("/%s",filename);
                else
                    absFilename = xstrdup(filename);
                DFBuffer *data = DFBufferReadFromStorage(storage,absFilename,NULL);
                addSerializedBinary(output,data,absFilename);
                DFBufferRelease(data);
                free(absFilename);
            }
            free(extension);
        }
    }
    free(entries);
    DFHashTableRelease(includeTypes);

    ok = 1;

end:
    return ok;
}
void WordUpdateStyles(WordConverter *converter, CSSSheet *styleSheet)
{
    CSSStyle *paraDefault = CSSSheetDefaultStyleForFamily(styleSheet,StyleFamilyParagraph);
    if (CSSGet(CSSStyleRule(paraDefault),"margin-top") == NULL)
        CSSPut(CSSStyleRule(paraDefault),"margin-top","-word-auto");

    if (CSSGet(CSSStyleRule(paraDefault),"margin-bottom") == NULL)
        CSSPut(CSSStyleRule(paraDefault),"margin-bottom","-word-auto");

    if (converter->package->styles == NULL) // FIXME: create this document
        return;;
    DFNode *root = converter->package->styles->root;
    if ((root == NULL) || (root->tag != WORD_STYLES))
        return;;

    DFHashTable *remainingSelectors = DFHashTableNew(NULL,NULL); // Used as a set
    const char **allSelectors = CSSSheetCopySelectors(styleSheet);
    for (int i = 0; allSelectors[i]; i++) {
        const char *selector = allSelectors[i];
        DFHashTableAdd(remainingSelectors,selector,"");
    }
    free(allSelectors);

    WordSheet *sheet = converter->styles;
    DFHashTable *oldConcreteNumIds = WordSheetFindUsedConcreteNumIds(sheet);
    updateNumbering(converter,styleSheet);

    // Update or remove existing styles
    const char **allIdents = WordSheetCopyIdents(sheet);
    for (int i = 0; allIdents[i]; i++) {
        WordStyle *wordStyle = WordSheetStyleForIdent(sheet,allIdents[i]);
        DFNode *element = wordStyle->element;

        if (WordStyleIsProtected(wordStyle)) {
            DFHashTableRemove(remainingSelectors,wordStyle->selector);
            continue;
        }

        if (!DFStringEquals(wordStyle->type,"paragraph") &&
            !DFStringEquals(wordStyle->type,"character") &&
            !DFStringEquals(wordStyle->type,"table"))
            continue;

        CSSStyle *cssStyle = CSSSheetLookupSelector(styleSheet,wordStyle->selector,0,0);
        if (cssStyle == NULL) {
            // Remove style
            WordSheetRemoveStyle(sheet,wordStyle);
            continue;
        }

        // Update style
        WordPutStyle(element,cssStyle,converter);
        updateDefault(cssStyle,element,styleSheet,converter);
        DFHashTableRemove(remainingSelectors,wordStyle->selector);
    }
    free(allIdents);

    // Sort the list of new styles, so that test output is deterministic
    const char **sortedSelectors = DFHashTableCopyKeys(remainingSelectors);
    DFSortStringsCaseInsensitive(sortedSelectors);

    // Add new styles. We do this in two stages - first creating the styles, and then setting their properties.
    // This is because the second stage depends on referenced styles (e.g. based on and next) to be already
    // present.
    for (int selIndex = 0; sortedSelectors[selIndex]; selIndex++) {
        const char *selector = sortedSelectors[selIndex];
        CSSStyle *style = CSSSheetLookupSelector(styleSheet,selector,0,0);
        const char *familyStr = NULL;

        StyleFamily family = WordStyleFamilyForSelector(selector);
        if (family == StyleFamilyParagraph)
            familyStr = "paragraph";
        else if (family == StyleFamilyCharacter)
            familyStr = "character";
        else if (family == StyleFamilyTable)
            familyStr = "table";
        else
            continue;

        char *styleId = WordStyleIdForStyle(style);
        char *name = WordStyleNameForStyle(style);
        if (name == NULL)
            name = xstrdup(styleId);;
        WordStyle *wordStyle = WordSheetAddStyle(sheet,familyStr,styleId,name,selector);
        DFCreateChildElement(wordStyle->element,WORD_QFORMAT);
        free(styleId);
        free(name);
    }

    for (int selIndex = 0; sortedSelectors[selIndex]; selIndex++) {
        const char *selector = sortedSelectors[selIndex];
        StyleFamily family = WordStyleFamilyForSelector(selector);
        if ((family != StyleFamilyParagraph) &&
            (family != StyleFamilyCharacter) &&
            (family != StyleFamilyTable))
            continue;

        CSSStyle *style = CSSSheetLookupSelector(styleSheet,selector,0,0);
        WordStyle *wordStyle = WordSheetStyleForSelector(converter->styles,selector);
        assert(wordStyle != NULL);

        CSSStyleAddDefaultHTMLProperties(style);
        // FIXME: language
        // FIXME: not covered by tests
        if ((style->headingLevel >= 1) && (style->headingLevel <= 6))
            CSSStyleSetNext(style,"p.Normal");

        WordPutStyle(wordStyle->element,style,converter);
        updateDefault(style,wordStyle->element,styleSheet,converter);
    }
    free(sortedSelectors);

    // Update body style (document defaults)
    updateDefaults(converter,styleSheet);

    updateBody(converter,styleSheet);

    DFHashTable *newConcreteNumIds = WordSheetFindUsedConcreteNumIds(sheet);
    const char **oldKeys = DFHashTableCopyKeys(oldConcreteNumIds);
    for (int oldIndex = 0; oldKeys[oldIndex]; oldIndex++) {
        const char *numId = oldKeys[oldIndex];
        if (DFHashTableLookup(newConcreteNumIds,numId) == NULL) {
            WordConcreteNum *concreteNum = WordNumberingConcreteWithId(converter->numbering,numId);
            if (concreteNum != NULL)
                WordNumberingRemoveConcrete(converter->numbering,concreteNum);
        }
    }
    free(oldKeys);
    DFHashTableRelease(remainingSelectors);
    DFHashTableRelease(oldConcreteNumIds);
    DFHashTableRelease(newConcreteNumIds);
}
Exemple #24
0
int WordConverterUpdateFromHTML(WordConverter *converter, DFError **error)
{
    if (converter->package->document == NULL) {
        DFErrorFormat(error,"document.xml not found");
        return 0;
    }

    DFNode *wordDocument = DFChildWithTag(converter->package->document->docNode,WORD_DOCUMENT);
    if (wordDocument == NULL) {
        DFErrorFormat(error,"word:document not found");
        return 0;
    }

    // FIXME: Need a more reliable way of telling whether this is a new document or not - it could be that the
    // document already existed (with styles set up) but did not have any content
    DFNode *wordBody = DFChildWithTag(wordDocument,WORD_BODY);
    int creating = ((wordBody == NULL) || (wordBody->first == NULL));

    converter->haveFields = Word_simplifyFields(converter->package);
    Word_mergeRuns(converter->package);

    assert(converter->package->styles);

    CSSSheetRelease(converter->styleSheet);
    converter->styleSheet = CSSSheetNew();

    char *cssText = HTMLCopyCSSText(converter->html);
    CSSSheetUpdateFromCSSText(converter->styleSheet,cssText);
    free(cssText);

    addMissingDefaultStyles(converter);
    CSSEnsureReferencedStylesPresent(converter->html,converter->styleSheet);
    if (creating)
        CSSSetHTMLDefaults(converter->styleSheet);
    CSSEnsureUnique(converter->styleSheet,converter->html,creating);

    CSSStyle *pageStyle = CSSSheetLookupElement(converter->styleSheet,"@page",NULL,0,0);
    CSSStyle *bodyStyle = CSSSheetLookupElement(converter->styleSheet,"body",NULL,1,0);
    CSSProperties *page = (pageStyle != NULL) ? CSSPropertiesRetain(CSSStyleRule(pageStyle)) : CSSPropertiesNew();
    CSSProperties *body = (bodyStyle != NULL) ? CSSPropertiesRetain(CSSStyleRule(bodyStyle)) : CSSPropertiesNew();

    if (CSSGet(body,"margin-left") == NULL)
        CSSPut(body,"margin-left","10%");
    if (CSSGet(body,"margin-right") == NULL)
        CSSPut(body,"margin-right","10%");
    if (CSSGet(body,"margin-top") == NULL)
        CSSPut(body,"margin-top","10%");
    if (CSSGet(body,"margin-bottom") == NULL)
        CSSPut(body,"margin-bottom","10%");

    WordSectionUpdateFromCSSPage(converter->mainSection,page,body);

    WordPutData put;
    put.conv = converter;
    put.numIdByHtmlId = DFHashTableNew((DFCopyFunction)strdup,free);
    put.htmlIdByNumId = DFHashTableNew((DFCopyFunction)strdup,free);

    // Make sure we update styles.xml from the CSS stylesheet *before* doing any conversion of the content,
    // since the latter requires a full mapping of CSS selectors to styleIds to be in place.
    WordUpdateStyles(converter,converter->styleSheet);

    Word_preProcessHTMLDoc(converter,converter->html);
    buildListMapFromHTML(&put,converter->html->docNode);
    updateListTypes(&put);
    WordBookmarks_removeCaptionBookmarks(converter->package->document);
    WordObjectsCollapseBookmarks(converter->objects);
    WordObjectsScan(converter->objects);
    Word_setupBookmarkLinks(&put);
    WordObjectsAnalyzeBookmarks(converter->objects,converter->styles);
    WordDocumentLens.put(&put,converter->html->root,wordDocument);
    WordObjectsExpandBookmarks(converter->objects);
    WordRemoveNbsps(converter->package->document);

    // Make sure the updateFields flag is set
    Word_updateSettings(converter->package,converter->haveFields);

    // Remove any abstract numbering definitions that are no longer referenced from concrete
    // numbering definitions
    WordNumberingRemoveUnusedAbstractNums(converter->numbering);

    // Remove any relationships and images that have been removed from the HTML file and no longer
    // have any other references pointing to them
    WordGarbageCollect(converter->package);

    CSSPropertiesRelease(page);
    CSSPropertiesRelease(body);
    DFHashTableRelease(put.numIdByHtmlId);
    DFHashTableRelease(put.htmlIdByNumId);

    return 1;
}
static void fixWordLists(DFNode *node, WordConverter *conv)
{
    for (DFNode *child = node->first; child != NULL; child = child->next)
        fixWordLists(child,conv);

    int haveParagraphs = 0;
    for (DFNode *child = node->first; child != NULL; child = child->next) {
        if (child->tag == WORD_P) {
            haveParagraphs = 1;
            break;
        }
    }

    if (!haveParagraphs)
        return;

    int createdHashTables = 0;
    DFHashTable *replacementNumIds = NULL;
    DFHashTable *itemNoByListKey = NULL;
    DFHashTable *lastNumIdByIlvl = NULL;
    DFHashTable *itemNoByIlvl = NULL;
    int maxIlvl = -1;

    for (DFNode *child = node->first; child != NULL; child = child->next) {
        if (child->tag != WORD_P)
            continue;
        DFNode *pPrElem = DFChildWithTag(child,WORD_PPR);
        DFNode *numPrElem = DFChildWithTag(pPrElem,WORD_NUMPR);
        DFNode *numIdElem = DFChildWithTag(numPrElem,WORD_NUMID);
        DFNode *ilvlElem = DFChildWithTag(numPrElem,WORD_ILVL);
        const char *numId = DFGetAttribute(numIdElem,WORD_VAL);
        const char *ilvl = DFGetAttribute(ilvlElem,WORD_VAL);

        if ((numId == NULL) || (atoi(numId) == 0))
            continue;

        if (!createdHashTables) {
            replacementNumIds = DFHashTableNew((DFCopyFunction)xstrdup,free);
            itemNoByListKey = DFHashTableNew((DFCopyFunction)xstrdup,free);
            lastNumIdByIlvl = DFHashTableNew((DFCopyFunction)xstrdup,free);
            itemNoByIlvl = DFHashTableNew((DFCopyFunction)xstrdup,free);
            createdHashTables = 1;
        }

        if (ilvl == NULL)
            ilvl = "0";;

        WordConcreteNum *concreteNum = WordNumberingConcreteWithId(conv->numbering,numId); // may be NULL
        WordNumLevel *numLevel = WordConcreteNumGetLevel(concreteNum,atoi(ilvl)); // may be NULL

        const char *levelStart = NULL;

        if (numLevel != NULL) {
            for (DFNode *lvlChild = numLevel->element->first; lvlChild != NULL; lvlChild = lvlChild->next) {
                switch (lvlChild->tag) {
                    case WORD_START:
                        levelStart = DFGetAttribute(lvlChild,WORD_VAL);
                        break;
                }
            }
        }

        char *listKey = DFFormatString("%s:%s",numId,ilvl);
        char *itemNo = DFStrDup(DFHashTableLookup(itemNoByListKey,listKey));
        if (itemNo == NULL) {
            itemNo = xstrdup("1");

            if ((levelStart != NULL) && (atoi(levelStart) > 1) && (atoi(ilvl) <= maxIlvl)) {
                const char *prevNumId = DFHashTableLookup(lastNumIdByIlvl,ilvl);
                const char *prevItemNo = DFHashTableLookup(itemNoByIlvl,ilvl);

                if ((prevNumId != NULL) && (prevItemNo != NULL)) {
                    DFHashTableAdd(replacementNumIds,numId,prevNumId);
                    free(itemNo);
                    itemNo = DFFormatString("%d",atoi(prevItemNo)+1);
                }
            }
        }
        else {
            int intValue = atoi(itemNo);
            free(itemNo);
            itemNo = DFFormatString("%d",intValue+1);
        }
        DFHashTableAdd(itemNoByListKey,listKey,itemNo);

        const char *replNumId = DFHashTableLookup(replacementNumIds,numId);
        if (replNumId != NULL) {
            numId = replNumId;
            DFSetAttribute(numIdElem,WORD_VAL,numId);
        }

        DFHashTableAdd(lastNumIdByIlvl,ilvl,numId);
        DFHashTableAdd(itemNoByIlvl,ilvl,itemNo);
        maxIlvl = atoi(ilvl);
        free(listKey);
        free(itemNo);
    }
    DFHashTableRelease(replacementNumIds);
    DFHashTableRelease(itemNoByListKey);
    DFHashTableRelease(lastNumIdByIlvl);
    DFHashTableRelease(itemNoByIlvl);
}
Exemple #26
0
static void collapseRecursive(DFNode *node, DFHashTable *bookmarksById)
{

    DFNode *next;
    for (DFNode *child = node->first; child != NULL; child = next) {
        next = child->next;

        switch (child->tag) {
            case WORD_BOOKMARKSTART:
            case WORD_BOOKMARKEND: {
                DFArray *startElements = DFArrayNew(NULL,NULL);
                DFArray *endElements = DFArrayNew(NULL,NULL);
                DFHashTable *startIds = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
                DFHashTable *endIds = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
                DFNode *n;
                for (n = child;
                     (n != NULL) && ((n->tag == WORD_BOOKMARKSTART) || (n->tag == WORD_BOOKMARKEND));
                     n = n->next) {

                    if (n->tag == WORD_BOOKMARKSTART) {
                        const char *idValue = DFGetAttribute(n,WORD_ID);
                        if (idValue == NULL)
                            idValue = "";

                        DFHashTableAdd(startIds,idValue,idValue);
                        DFArrayAppend(startElements,n);
                    }
                    else {
                        const char *idValue = DFGetAttribute(n,WORD_ID);
                        if (idValue == NULL)
                            idValue = "";

                        DFHashTableAdd(endIds,idValue,idValue);
                        DFArrayAppend(endElements,n);
                    }
                }
                next = n;

                DFArraySort(startElements,bookmarksById,compareStartElements);

                for (size_t endIndex = 0; endIndex < DFArrayCount(endElements); endIndex++) {
                    DFNode *elem = DFArrayItemAt(endElements,endIndex);
                    const char *endId = DFGetAttribute(elem,WORD_ID);
                    int found = 0;
                    DFNode *ancestor;
                    for (ancestor = elem->parent; (ancestor != NULL) && !found; ancestor = ancestor->parent) {
                        if ((ancestor->tag == WORD_BOOKMARK) && DFStringEquals(DFGetAttribute(ancestor,WORD_ID),endId)) {
                            found = 1;
                            break;
                        }
                    }

                    if (found) {
                        DFNode *before = ancestor->next;
                        DFNode *nnext;
                        for (DFNode *n = child; n != NULL; n = nnext) {
                            nnext = n->next;
                            DFInsertBefore(ancestor->parent,n,before);
                        }
                    }
                }

                size_t x = 0;
                while (x < DFArrayCount(startElements)) {
                    DFNode *element = DFArrayItemAt(startElements,x);
                    const char *bookmarkId = DFGetAttribute(element,WORD_ID);
                    if (bookmarkId == NULL)
                        bookmarkId = "";
                    if (DFHashTableLookup(endIds,bookmarkId) != NULL) {
                        element->tag = WORD_BOOKMARK;
                        DFArrayRemove(startElements,x);
                    }
                    else {
                        x++;
                    }
                }

                if (DFArrayCount(startElements) > 0) {
                    for (size_t i = 1; i < DFArrayCount(startElements); i++) {
                        DFNode *tempParent = DFArrayItemAt(startElements,i-1);
                        DFNode *tempChild = DFArrayItemAt(startElements,i);
                        DFAppendChild(tempParent,tempChild);
                    }

                    DFNode *last = DFArrayItemAt(startElements,DFArrayCount(startElements)-1);
                    while (next != NULL) {
                        DFNode *tempChild = next;
                        next = next->next;
                        DFAppendChild(last,tempChild);
                    }
                }

                for (size_t eIndex = 0; eIndex < DFArrayCount(startElements); eIndex++) {
                    DFNode *e = DFArrayItemAt(startElements,eIndex);
                    e->tag = WORD_BOOKMARK;
                }
                for (size_t eIndex = 0; eIndex < DFArrayCount(endElements); eIndex++) {
                    DFNode *e = DFArrayItemAt(endElements,eIndex);
                    DFRemoveNode(e);
                }

                if (DFArrayCount(startElements) > 0) {
                    DFNode *last = DFArrayItemAt(startElements,DFArrayCount(startElements)-1);
                    collapseRecursive(last,bookmarksById);
                }

                DFArrayRelease(startElements);
                DFArrayRelease(endElements);
                DFHashTableRelease(startIds);
                DFHashTableRelease(endIds);
                break;
            }
            default:
                collapseRecursive(child,bookmarksById);
                break;
        }
    }
}
Exemple #27
0
static DFHashTable *findReferences(DFDocument *doc)
{
    DFHashTable *references = DFHashTableNew((DFCopyFunction)DFArrayRetain,(DFFreeFunction)DFArrayRelease);
    findReferencesRecursive(doc->docNode,references);
    return references;
}