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; }
static void buildListMapFromHTML(WordPutData *put, DFNode *node) { if (node->tag == HTML_P) { const char *htmlId = DFGetAttribute(node,CONV_LISTNUM); DFNode *conElem = (htmlId != NULL) ? WordConverterGetConcrete(put,node) : NULL; DFNode *pPrElem = (conElem != NULL) ? DFChildWithTag(conElem,WORD_PPR) : NULL; DFNode *numPrElem = (pPrElem != NULL) ? DFChildWithTag(pPrElem,WORD_NUMPR) : NULL; DFNode *numIdElem = (numPrElem != NULL) ? DFChildWithTag(numPrElem,WORD_NUMID) : NULL; const char *numId = (numIdElem != NULL) ? DFGetAttribute(numIdElem,WORD_VAL) : NULL; if (numId != NULL) { const char *existingHtmlId = DFHashTableLookup(put->htmlIdByNumId,numId); const char *existingNumId = DFHashTableLookup(put->numIdByHtmlId,htmlId); if ((existingHtmlId == NULL) && (existingNumId == NULL)) { DFHashTableAdd(put->htmlIdByNumId,numId,htmlId); DFHashTableAdd(put->numIdByHtmlId,htmlId,numId); WordConcreteNum *num = WordNumberingConcreteWithId(put->conv->numbering,numId); if (num != NULL) num->referenceCount++; } } } for (DFNode *child = node->first; child != NULL; child = child->next) buildListMapFromHTML(put,child); }
static int parsePackage(TextPackage *package, const char *string, const char *path, DFError **error) { DFBuffer *replaced = DFBufferNew(); if (!strcmp(path,"")) path = "."; if (!processIncludes(package,string,replaced,path,error)) { DFBufferRelease(replaced); return 0; } char *currentKey = strdup(""); DFBuffer *currentValue = DFBufferNew(); const char **lines = DFStringSplit(replaced->data,"\n",0); for (int lineno = 0; lines[lineno]; lineno++) { const char *line = lines[lineno]; if (!DFStringHasPrefix(line,"#")) { DFBufferFormat(currentValue,"%s\n",line); } else if (DFStringHasPrefix(line,"#item ")) { package->keys = (char **)realloc(package->keys,(package->nkeys+2)*sizeof(char *)); package->keys[package->nkeys++] = strdup(currentKey); package->keys[package->nkeys] = NULL; DFHashTableAdd(package->items,currentKey,currentValue->data); free(currentKey); DFBufferRelease(currentValue); currentKey = DFSubstring(line,6,strlen(line)); currentValue = DFBufferNew(); } else if (DFStringHasPrefix(line,"##")) { DFBufferFormat(currentValue,"%s\n",&line[1]); } else { DFErrorFormat(error,"Unknown command: %s on line %d",line,(lineno+1)); return 0; } } package->keys = (char **)realloc(package->keys,(package->nkeys+2)*sizeof(char *)); package->keys[package->nkeys++] = strdup(currentKey); package->keys[package->nkeys] = NULL; DFHashTableAdd(package->items,currentKey,currentValue->data); free(lines); free(currentKey); DFBufferRelease(currentValue); DFBufferRelease(replaced); return 1; }
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; }
void DFSetAttribute(DFNode *element, Tag tag, const char *value) { if (value == NULL) { DFRemoveAttribute(element,tag); return; } if (tag == HTML_ID) { const char *oldIdAttr = DFGetAttribute(element,HTML_ID); if (oldIdAttr != NULL) DFHashTableRemove(element->doc->nodesByIdAttr,oldIdAttr); DFHashTableAdd(element->doc->nodesByIdAttr,value,element); } // Is there an existing attribute with this tag? If so, replace it for (unsigned int i = 0; i < element->attrsCount; i++) { if (element->attrs[i].tag == tag) { element->attrs[i].value = DFCopyString(element->doc,value); return; } } // No existing attribute with this tag - add it if (element->attrsCount == element->attrsAlloc) { element->attrsAlloc = (element->attrsAlloc == 0) ? 8 : (2*element->attrsAlloc); element->attrs = (DFAttribute *)xrealloc(element->attrs,element->attrsAlloc*sizeof(DFAttribute)); } element->attrs[element->attrsCount].tag = tag; element->attrs[element->attrsCount].value = DFCopyString(element->doc,value); element->attrsCount++; }
static void NameMap_staticInit() { if (defaultNamespacesByURI != NULL) return; defaultNamespacesByURI = DFHashTableNew2(NULL,NULL,997); defaultTagsByNameURI = DFNameHashTableNew(); for (NamespaceID nsId = 1; nsId < PREDEFINED_NAMESPACE_COUNT; nsId++) { const NamespaceDecl *decl = &PredefinedNamespaces[nsId]; const char *key = (const char *)decl->namespaceURI; assert(DFHashTableLookup(defaultNamespacesByURI,key) == NULL); DFNamespaceInfo *ns = DFNamespaceInfoNew(nsId,decl->namespaceURI,decl->prefix); DFHashTableAdd(defaultNamespacesByURI,key,ns); } for (Tag tag = MIN_ELEMENT_TAG; tag < PREDEFINED_TAG_COUNT; tag++) { const TagDecl *tagDecl = &PredefinedTags[tag]; const NamespaceDecl *nsDecl = &PredefinedNamespaces[tagDecl->namespaceID]; DFNameHashTableAdd(defaultTagsByNameURI, tagDecl->localName, nsDecl->namespaceURI, tag, tagDecl->namespaceID); } }
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; }
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; }
static void findBookmarkSizes(DFNode *node, DFHashTable *bookmarksById, int *offset) { switch (node->tag) { case WORD_BOOKMARKSTART: case WORD_BOOKMARKEND: { const char *bookmarkId = DFGetAttribute(node,WORD_ID); if (bookmarkId == NULL) bookmarkId = ""; WordRawBookmark *bookmark = DFHashTableLookup(bookmarksById,bookmarkId); if (bookmark == NULL) { bookmark = WordRawBookmarkNew(); DFHashTableAdd(bookmarksById,bookmarkId,bookmark); } if (node->tag == WORD_BOOKMARKSTART) { bookmark->startElement = node; bookmark->startOffset = *offset; } else { bookmark->endElement = node; bookmark->endOffset = *offset; } break; } default: (*offset)++; break; } for (DFNode *child = node->first; child != NULL; child = child->next) { findBookmarkSizes(child,bookmarksById,offset); } }
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; }
static void ODFManifestParse(ODFManifest *manifest) { for (DFNode *child = manifest->doc->root; child != NULL; child = child->next) { if (child->tag == MF_FILE_ENTRY) { const char *path = DFGetAttribute(child,MF_FULL_PATH); if (path != NULL) DFHashTableAdd(manifest->entriesByPath,path,child); } } }
static void DFNameMapAddNamespace(DFNameMap *map, NamespaceID nsId, const char *URI, const char *prefix) { assert(DFHashTableLookup(defaultNamespacesByURI,(const char *)URI) == NULL); assert(DFHashTableLookup(map->namespacesByURI,(const char *)URI) == NULL); DFNamespaceInfo *ns = DFNamespaceInfoNew(nsId,URI,prefix); if (nsId >= PREDEFINED_NAMESPACE_COUNT) { DFHashTableAddInt(map->namespacesByID,nsId,ns); } DFHashTableAdd(map->namespacesByURI,(const char *)URI,ns); }
static void findReferences(DFHashTable *referencedIds, DFNode *node) { if (node->tag >= MIN_ELEMENT_TAG) { switch (node->tag) { case WORD_HYPERLINK: { const char *rId = DFGetAttribute(node,OREL_ID); if (rId != NULL) DFHashTableAdd(referencedIds,rId,""); break; } case DML_MAIN_BLIP: { const char *rId = DFGetAttribute(node,OREL_EMBED); if (rId != NULL) DFHashTableAdd(referencedIds,rId,""); break; } } } for (DFNode *child = node->first; child != NULL; child = child->next) findReferences(referencedIds,child); }
void CSSPut(CSSProperties *properties, const char *name, const char *value) { if (properties == NULL) return; assert(properties->retainCount > 0); if (value == NULL) DFHashTableRemove(properties->hashTable,name); else DFHashTableAdd(properties->hashTable,name,(void *)value); if (!properties->dirty) // Minimise KVO notifications properties->dirty = 1; DFCallbackInvoke(properties->changeCallbacks,properties,NULL); }
void ODFManifestAddEntry(ODFManifest *manifest, const char *path, const char *mediaType, const char *version) { DFNode *entry = DFHashTableLookup(manifest->entriesByPath,path); if (entry == NULL) { entry = DFCreateChildElement(manifest->doc->root,MF_FILE_ENTRY); DFHashTableAdd(manifest->entriesByPath,path,entry); } DFSetAttribute(entry,MF_FULL_PATH,path); DFSetAttribute(entry,MF_MEDIA_TYPE,mediaType); DFSetAttribute(entry,MF_VERSION,version); if (!strcmp(path,"") && (version != NULL)) DFSetAttribute(manifest->doc->root,MF_VERSION,version); }
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; }
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 void findReferencesRecursive(DFNode *node, DFHashTable *referencesById) { if (node->tag == HTML_A) { const char *href = DFGetAttribute(node,HTML_HREF); if ((href != NULL) && (href[0] == '#')) { const char *targetId = &href[1]; DFArray *links = DFHashTableLookup(referencesById,targetId); if (links == NULL) { links = DFArrayNew(NULL,NULL); DFHashTableAdd(referencesById,targetId,links); DFArrayRelease(links); } DFArrayAppend(links,node); } } for (DFNode *child = node->first; child != NULL; child = child->next) findReferencesRecursive(child,referencesById); }
static void parseDocumentRels(const char *documentPath, DFDocument *relsDoc, DFHashTable *rels, DFError **error) { if (relsDoc == NULL) return;; const char *basePrefix = (documentPath[0] == '/') ? "" : "/"; char *basePath = DFFormatString("%s%s",basePrefix,documentPath); for (DFNode *child = relsDoc->root->first; child != NULL; child = child->next) { if (child->tag != REL_RELATIONSHIP) continue; const char *type = DFGetAttribute(child,NULL_Type); const char *target = DFGetAttribute(child,NULL_TARGET); if ((type == NULL) || (target == NULL)) continue; char *absTarget = DFPathResolveAbsolute(basePath,target); DFHashTableAdd(rels,type,absTarget); free(absTarget); } free(basePath); }
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); }
static int addRelatedDoc(DFHashTable *parts, DFHashTable *documentRels, const char *relName, const char *filename, DFBuffer *output, DFHashTable *includeTypes, DFStorage *storage, DFError **error) { const char *relPath = DFHashTableLookup(documentRels,relName); if (relPath == NULL) return 1;; DFDocument *doc = DFParseXMLStorage(storage,relPath,error); if (doc == NULL) { DFErrorFormat(error,"%s: %s",relPath,DFErrorMessage(error)); return 0; } if (doc->root->first != NULL) { addStrippedSerializedDoc(output,doc,filename); DFHashTableAdd(includeTypes,relName,""); } DFDocumentRelease(doc); return 1; }
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); } } } }
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 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); }
void CSSSheetAddStyle(CSSSheet *sheet, CSSStyle *style) { assert(style->selector != NULL); DFHashTableAdd(sheet->_styles,style->selector,style); }
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); }
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; } } }