// FIXME: Not covered by tests void DFMarkupCompatibilityProcessAttr(DFMarkupCompatibility *mc, Tag attr, const char *value, DFNameMap *map) { const char **tokens = DFStringTokenize(value,isspace); for (int tokIndex = 0; tokens[tokIndex]; tokIndex++) { const char *component = tokens[tokIndex]; char *prefix = NULL; char *localName = NULL; const char *colon = strchr(component,':'); if (colon != NULL) { size_t colonPos = colon - component; prefix = DFSubstring(component,0,colonPos); localName = DFSubstring(component,colonPos+1,strlen(component)); } else { prefix = xstrdup(component); localName = NULL; } const char *nsIdStr = NULL; // Find namespace ID for prefix for (int recordIndex = mc->depth-1; recordIndex >= 0; recordIndex--) { MCRecord *record = &mc->records[recordIndex]; if (record->namespaces != NULL) nsIdStr = DFHashTableLookup(record->namespaces,prefix); } if (nsIdStr != NULL) { NamespaceID nsId = atoi(nsIdStr); Tag tag = 0; const NamespaceDecl *nsDecl = DFNameMapNamespaceForID(map,nsId); if (localName != NULL) tag = DFNameMapTagForName(map,nsDecl->namespaceURI,localName); switch (attr) { case MC_IGNORABLE: addDeclToRecord(&mc->records[mc->depth-1],nsId,tag,MCActionIgnore); break; case MC_PROCESSCONTENT: addDeclToRecord(&mc->records[mc->depth-1],nsId,tag,MCActionProcessContent); break; case MC_MUSTUNDERSTAND: addDeclToRecord(&mc->records[mc->depth-1],nsId,tag,MCActionMustUnderstand); break; } } free(prefix); free(localName); } free(tokens); }
static char *trimmedSubstring(CSSParser *p, size_t start, size_t pos) { char *untrimmed = DFSubstring(p->chars,start,pos); char *trimmed = DFStringTrimWhitespace(untrimmed); free(untrimmed); return trimmed; }
static int processIncludes(TextPackage *package, const char *input, DFBuffer *output, const char *path, DFError **error) { int ok = 1; const char **lines = DFStringSplit(input,"\n",0); for (int lineno = 0; lines[lineno] && ok; lineno++) { const char *line = lines[lineno]; if (DFStringHasPrefix(line,"#include \"") && DFStringHasSuffix(line,"\"")) { char *inclRelPath = DFSubstring(line,10,strlen(line)-1); char *inclAbsPath = DFAppendPathComponent(path,inclRelPath); char *inclDirName = DFPathDirName(inclAbsPath); char *inclContent = DFStringReadFromFile(inclAbsPath,error); if (inclContent == NULL) { DFErrorFormat(error,"%s: %s",inclRelPath,DFErrorMessage(error)); ok = 0; } else if (!processIncludes(package,inclContent,output,inclDirName,error)) { ok = 0; } free(inclRelPath); free(inclAbsPath); free(inclDirName); free(inclContent); } else { DFBufferFormat(output,"%s\n",line); } } free(lines); return ok; }
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; }
DFArray *CSSParserContent(CSSParser *p) { DFArray *result = DFArrayNew((DFCopyFunction)ContentPartRetain,(DFFreeFunction)ContentPartRelease); matchWhitespace(p); while (p->pos < p->length) { size_t start = p->pos; switch (p->chars[p->pos]) { case '"': case '\'': { int invalid = 0; if (!matchString(p,&invalid)) return result; char *quotedValue = trimmedSubstring(p,start,p->pos); char *unquotedValue = DFUnquote(quotedValue); ContentPart *part = ContentPartNew(ContentPartString,unquotedValue,NULL); DFArrayAppend(result,part); ContentPartRelease(part); free(quotedValue); free(unquotedValue); if ((p->pos < p->length) && !matchWhitespace(p)) return result; break; } case 'C': case 'c': { if (matchSpecific(p,"counters(")) { // Not yet supported return result; } else if (matchSpecific(p,"counter(")) { size_t nameStart = p->pos; if (!matchIdent(p)) return result; char *name = DFSubstring(p->chars,nameStart,p->pos); char *type = NULL; if (match(p,',')) { size_t typeStart = p->pos; if (!matchIdent(p)) { free(name); free(type); return result; } type = DFSubstring(p->chars,typeStart,p->pos); } ContentPart *part = ContentPartNew(ContentPartCounter,name,type); DFArrayAppend(result,part); ContentPartRelease(part); if (!match(p,')')) { free(name); free(type); return result; } if ((p->pos < p->length) && !matchWhitespace(p)) { free(name); free(type); return result; } free(name); free(type); } else { return result; } break; } default: return result; } } return result; }
char *WordStyleIdForStyle(CSSStyle *style) { const char *selector = style->selector; char *resStyleId = NULL; if (!strcmp(selector,"table.Normal_Table")) return strdup("TableNormal"); if (!strcmp(selector,"table.Table_Grid")) return strdup("TableGrid"); if (!strcmp(selector,"span.Default_Paragraph_Font")) return strdup("DefaultParagraphFont"); if (!strcmp(selector,"p.List_Paragraph")) return strdup("ListParagraph"); int headingLevel = CSSSelectorHeadingLevel(selector); if (headingLevel != 0) { char *prefix = DFFormatString("heading_%d",headingLevel); if ((style->className != NULL) && DFStringHasPrefix(style->className,prefix)) { char *rest = DFSubstring(style->className,strlen(prefix),strlen(style->className)); char *result = DFFormatString("Heading%d%s",headingLevel,rest); free(rest); free(prefix); return result; } free(prefix); } if (!strcmp(selector,"span.Heading1Char")) return strdup("Heading1Char"); if (!strcmp(selector,"span.Heading2Char")) return strdup("Heading2Char"); if (!strcmp(selector,"span.Heading3Char")) return strdup("Heading3Char"); if (!strcmp(selector,"span.Heading4Char")) return strdup("Heading4Char"); if (!strcmp(selector,"span.Heading5Char")) return strdup("Heading5Char"); if (!strcmp(selector,"span.Heading6Char")) return strdup("Heading6Char"); if (!strcmp(selector,"span.Heading7Char")) return strdup("Heading7Char"); if (!strcmp(selector,"span.Heading8Char")) return strdup("Heading8Char"); if (!strcmp(selector,"span.Heading9Char")) return strdup("Heading9Char"); char *className = CSSSelectorCopyClassName(selector); switch (CSSSelectorGetTag(selector)) { case HTML_FIGURE: { resStyleId = DFStrDup("Figure"); break; } case HTML_CAPTION: { resStyleId = DFStrDup("Caption"); break; } case HTML_H1: case HTML_H2: case HTML_H3: case HTML_H4: case HTML_H5: case HTML_H6: { if ((className == NULL) || (strlen(className) == 0)) { int level = CSSSelectorHeadingLevel(selector); if ((level >= 1) && (level <= 6)) { // FIXME: we shouldn't rely on the specific word "Heading" here - instead using the localised name // FIXME: not covered by tests resStyleId = DFFormatString("Heading%d",level); } } else { resStyleId = DFStrDup(className); } break; } case HTML_P: resStyleId = DFStrDup(className); break; case HTML_SPAN: resStyleId = DFStrDup(className); break; case HTML_TABLE: resStyleId = DFStrDup(className); break; } free(className); if (resStyleId == NULL) { // Note: selector here may start with . (i.e. applies to all elements) // FIXME: not covered by tests resStyleId = strdup(selector); } return resStyleId; }
static void extractPrefixRecursive(DFNode *node, const char *counterName, DFBuffer *result, int *foundSeq, int *foundContent) { if (isSeqField(node)) { if (result->len > 0) DFBufferFormat(result," "); DFBufferFormat(result,"counter(%s)",counterName); *foundSeq = 1; DFRemoveNode(node); return; } if (node->tag == DOM_TEXT) { size_t valueLen = strlen(node->value); size_t pos = 0; if (*foundSeq) { size_t offset = 0; uint32_t ch; do { pos = offset; ch = DFNextChar(node->value,&offset); } while ((ch != 0) && (DFCharIsWhitespaceOrNewline(ch) || DFCharIsPunctuation(ch))); } else { pos = valueLen; } if (pos == valueLen) { if (result->len > 0) DFBufferFormat(result," "); char *quotedValue = DFQuote(node->value); DFBufferFormat(result,"%s",quotedValue); free(quotedValue); DFRemoveNode(node); if (*foundSeq) *foundContent = 1; return; } else if (pos > 0) { char *first = DFSubstring(node->value,0,pos); char *rest = DFSubstring(node->value,pos,valueLen); if (result->len > 0) DFBufferFormat(result," "); char *quotedFirst = DFQuote(first); DFBufferFormat(result,"%s",quotedFirst); free(quotedFirst); DFSetNodeValue(node,rest); if (*foundSeq) *foundContent = 1; free(first); free(rest); return; } } int wasEmpty = (node->first == NULL); DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; if (*foundContent) break; extractPrefixRecursive(child,counterName,result,foundSeq,foundContent); } int isEmpty = (node->first == NULL); if ((node->tag == HTML_SPAN) && isEmpty && !wasEmpty) DFRemoveNode(node); }