static void updateListTypes(WordPutData *put) { const char **htmlIds = DFHashTableCopyKeys(put->numIdByHtmlId); for (int i = 0; htmlIds[i]; i++) { const char *htmlId = htmlIds[i]; const char *numId = DFHashTableLookup(put->numIdByHtmlId,htmlId); WordConcreteNum *num = WordNumberingConcreteWithId(put->conv->numbering,numId); if (num == NULL) continue; // FIXME: remove entry from both maps so it is re-created DFNode *listNode = DFNodeForSeqNo(put->conv->html,(unsigned int)atoi(htmlId)); assert(listNode != NULL); const char *htmlType = DFGetAttribute(listNode,CONV_LISTTYPE); const char *htmlIlvl = DFGetAttribute(listNode,CONV_ILVL); WordNumLevel *level = WordConcreteNumGetLevel(num,atoi(htmlIlvl)); if (level == NULL) continue; // FIXME: remove entry from both maps so it is re-created const char *wordType = WordNumLevelToListStyleType(level); if (!DFStringEquals(wordType,htmlType)) { // Make a copy of numId, as it may be freed during the first call to DFHashTableRemove char *numIdCopy = strdup(numId); DFHashTableRemove(put->numIdByHtmlId,htmlId); DFHashTableRemove(put->htmlIdByNumId,numIdCopy); free(numIdCopy); if (num->referenceCount == 1) WordNumberingRemoveConcrete(put->conv->numbering,num); } } free(htmlIds); }
static int listProperties(WordConverter *conv, const char *numId, const char *ilvl, CSSProperties *properties) { WordConcreteNum *num = WordNumberingConcreteWithId(conv->numbering,numId); if (num == NULL) return 0;; WordNumLevel *level = WordConcreteNumGetLevel(num,atoi(ilvl)); if (level == NULL) return 0;; DFNode *pPr = DFChildWithTag(level->element,WORD_PPR); if (pPr == NULL) return 0;; const char *styleId = NULL; WordGetPPr(pPr,properties,&styleId,conv->mainSection); 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); }
static void Word_fixListSingle(WordConverter *conv, DFNode *node) { ListStack stack; bzero(&stack,sizeof(ListStack)); DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; int isListItem = 0; if (child->tag == HTML_P) { DFNode *elem = child; const char *numIdStr = DFGetAttribute(elem,WORD_NUMID); const char *ilvlStr = DFGetAttribute(elem,WORD_ILVL); DFRemoveAttribute(elem,WORD_NUMID); DFRemoveAttribute(elem,WORD_ILVL); // A numId of 0 means that there is no numbering applied to this paragraph if ((numIdStr != NULL) && (atoi(numIdStr) == 0)) { numIdStr = NULL; ilvlStr = NULL; } if ((numIdStr != NULL) && (ilvlStr != NULL)) { isListItem = 1; int numId = atoi(numIdStr); int ilvl = atoi(ilvlStr); ListDimensions dimensions = listIndent(conv,numIdStr,ilvlStr); // Find the list at the same ilvl, and check if it has the same numId. If not, we're // starting a new list. ListFrame *sameLevelFrame = NULL; for (ListFrame *frame = stack.top; frame != NULL; frame = frame->parent) { if (frame->ilvl == ilvl) sameLevelFrame = frame; } if ((sameLevelFrame != NULL) && (sameLevelFrame->numId != numId)) fixTrailingParagraphs(&stack,ilvl); else fixTrailingParagraphs(&stack,ilvl+1); if ((stack.top != NULL) && (stack.top->numId != numId)) ListStackPopToAboveIlvl(&stack,ilvl); else if ((stack.top != NULL) && (stack.top->ilvl > ilvl)) ListStackPopToAboveIlvl(&stack,ilvl+1); if ((stack.top == NULL) || (stack.top->numId != numId) || (stack.top->ilvl < ilvl)) { WordConcreteNum *num = WordNumberingConcreteWithId(conv->numbering,numIdStr); // may be NULL WordNumLevel *level = WordConcreteNumGetLevel(num,ilvl); // may be NULL const char *type = WordNumLevelToListStyleType(level); // may be NULL Tag tag; if (DFStringEquals(type,"disc") || DFStringEquals(type,"circle") || DFStringEquals(type,"square")) tag = HTML_UL; else tag = HTML_OL; DFNode *element = DFCreateElement(conv->html,tag); if (type != NULL) DFFormatAttribute(element,HTML_STYLE,"list-style-type: %s",type); if (stack.top != NULL) { DFNode *li; if (stack.top->element->last != NULL) li = stack.top->element->last; else li = DFCreateChildElement(stack.top->element,HTML_LI); DFAppendChild(li,element); } else { DFInsertBefore(node,element,child); } ListStackPushFrame(&stack,element,numId,ilvl,dimensions); } } } if (stack.top != NULL) { DFNode *li; if ((stack.top->element->last != NULL) && !isListItem) li = stack.top->element->last; else li = DFCreateChildElement(stack.top->element,HTML_LI); DFAppendChild(li,child); } } fixTrailingParagraphs(&stack,-1); while (stack.top != NULL) ListStackPop(&stack); }