Fossil SCM

Correctly render the title of embedded Markdown documents that contain characters that are special to HTML: > " ' & <

drh 2025-03-07 20:14 trunk
Commit 0b24a45f49f9abbad03c794f25cc52b85ee1c2daba5e749b509963a6479d28ee
+1
--- src/doc.c
+++ src/doc.c
@@ -807,10 +807,11 @@
807807
}else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
808808
Blob tail = BLOB_INITIALIZER;
809809
markdown_to_html(pBody, &title, &tail);
810810
if( !isPopup ){
811811
if( blob_size(&title)>0 ){
812
+ markdown_dehtmlize_blob(&title);
812813
style_header("%s", blob_str(&title));
813814
}else{
814815
style_header("%s", zDefaultTitle);
815816
}
816817
}
817818
--- src/doc.c
+++ src/doc.c
@@ -807,10 +807,11 @@
807 }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
808 Blob tail = BLOB_INITIALIZER;
809 markdown_to_html(pBody, &title, &tail);
810 if( !isPopup ){
811 if( blob_size(&title)>0 ){
 
812 style_header("%s", blob_str(&title));
813 }else{
814 style_header("%s", zDefaultTitle);
815 }
816 }
817
--- src/doc.c
+++ src/doc.c
@@ -807,10 +807,11 @@
807 }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
808 Blob tail = BLOB_INITIALIZER;
809 markdown_to_html(pBody, &title, &tail);
810 if( !isPopup ){
811 if( blob_size(&title)>0 ){
812 markdown_dehtmlize_blob(&title);
813 style_header("%s", blob_str(&title));
814 }else{
815 style_header("%s", zDefaultTitle);
816 }
817 }
818
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -911,5 +911,62 @@
911911
html_renderer.opaque = &context;
912912
if( output_title ) blob_reset(output_title);
913913
blob_reset(output_body);
914914
markdown(output_body, input_markdown, &html_renderer);
915915
}
916
+
917
+/*
918
+** Undo HTML escapes in Blob p. In other words convert:
919
+**
920
+** & -> &
921
+** &lt; -> <
922
+** &gt; -> >
923
+** &quot; -> "
924
+** &#NNN; -> ascii character NNN
925
+*/
926
+void markdown_dehtmlize_blob(Blob *p){
927
+ char *z;
928
+ unsigned int j, k;
929
+
930
+ z = p->aData;
931
+ for(j=k=0; j<p->nUsed; j++){
932
+ char c = z[j];
933
+ if( c=='&' ){
934
+ if( z[j+1]=='#' && fossil_isdigit(z[j+2]) ){
935
+ int n = 3;
936
+ int x = z[j+2] - '0';
937
+ if( fossil_isdigit(z[j+3]) ){
938
+ x = x*10 + z[j+3] - '0';
939
+ n++;
940
+ if( fossil_isdigit(z[j+4]) ){
941
+ x = x*10 + z[j+4] - '0';
942
+ n++;
943
+ }
944
+ }
945
+ if( z[j+n]==';' ){
946
+ z[k++] = (char)x;
947
+ j += n;
948
+ }else{
949
+ z[k++] = c;
950
+ }
951
+ }else if( memcmp(&z[j],"&lt;",4)==0 ){
952
+ z[k++] = '<';
953
+ j += 3;
954
+ }else if( memcmp(&z[j],"&gt;",4)==0 ){
955
+ z[k++] = '>';
956
+ j += 3;
957
+ }else if( memcmp(&z[j],"&quot;",6)==0 ){
958
+ z[k++] = '"';
959
+ j += 5;
960
+ }else if( memcmp(&z[j],"&amp;",5)==0 ){
961
+ z[k++] = '&';
962
+ j += 4;
963
+ }else{
964
+ z[k++] = c;
965
+ }
966
+ }else{
967
+ z[k++] = c;
968
+ }
969
+ }
970
+ z[k] = 0;
971
+ p->nUsed = k;
972
+}
916973
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -911,5 +911,62 @@
911 html_renderer.opaque = &context;
912 if( output_title ) blob_reset(output_title);
913 blob_reset(output_body);
914 markdown(output_body, input_markdown, &html_renderer);
915 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
916
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -911,5 +911,62 @@
911 html_renderer.opaque = &context;
912 if( output_title ) blob_reset(output_title);
913 blob_reset(output_body);
914 markdown(output_body, input_markdown, &html_renderer);
915 }
916
917 /*
918 ** Undo HTML escapes in Blob p. In other words convert:
919 **
920 ** &amp; -> &
921 ** &lt; -> <
922 ** &gt; -> >
923 ** &quot; -> "
924 ** &#NNN; -> ascii character NNN
925 */
926 void markdown_dehtmlize_blob(Blob *p){
927 char *z;
928 unsigned int j, k;
929
930 z = p->aData;
931 for(j=k=0; j<p->nUsed; j++){
932 char c = z[j];
933 if( c=='&' ){
934 if( z[j+1]=='#' && fossil_isdigit(z[j+2]) ){
935 int n = 3;
936 int x = z[j+2] - '0';
937 if( fossil_isdigit(z[j+3]) ){
938 x = x*10 + z[j+3] - '0';
939 n++;
940 if( fossil_isdigit(z[j+4]) ){
941 x = x*10 + z[j+4] - '0';
942 n++;
943 }
944 }
945 if( z[j+n]==';' ){
946 z[k++] = (char)x;
947 j += n;
948 }else{
949 z[k++] = c;
950 }
951 }else if( memcmp(&z[j],"&lt;",4)==0 ){
952 z[k++] = '<';
953 j += 3;
954 }else if( memcmp(&z[j],"&gt;",4)==0 ){
955 z[k++] = '>';
956 j += 3;
957 }else if( memcmp(&z[j],"&quot;",6)==0 ){
958 z[k++] = '"';
959 j += 5;
960 }else if( memcmp(&z[j],"&amp;",5)==0 ){
961 z[k++] = '&';
962 j += 4;
963 }else{
964 z[k++] = c;
965 }
966 }else{
967 z[k++] = c;
968 }
969 }
970 z[k] = 0;
971 p->nUsed = k;
972 }
973

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button