Commit fbc18c5b authored by Tw's avatar Tw

markdown: fix json format parse issue

We can't use json meta parser's remaining buffered data as the markdown body
because it may not contain the entire original content.
Now we adopt the way like toml and yaml parser's way to extract the meta content
at first.

Also when spilting the meta data and content body, additional io.Copy is
unnecessary.

Fix issue #355
Signed-off-by: default avatarTw <tw19881113@gmail.com>
parent 4dbb4274
package markdown package markdown
import ( import (
"bufio"
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
...@@ -73,23 +71,20 @@ type JSONMetadataParser struct { ...@@ -73,23 +71,20 @@ type JSONMetadataParser struct {
// Parse the metadata // Parse the metadata
func (j *JSONMetadataParser) Parse(b []byte) ([]byte, error) { func (j *JSONMetadataParser) Parse(b []byte) ([]byte, error) {
b, markdown, err := extractMetadata(j, b)
if err != nil {
return markdown, err
}
m := make(map[string]interface{}) m := make(map[string]interface{})
// Read the preceding JSON object // Read the preceding JSON object
decoder := json.NewDecoder(bytes.NewReader(b)) decoder := json.NewDecoder(bytes.NewReader(b))
if err := decoder.Decode(&m); err != nil { if err := decoder.Decode(&m); err != nil {
return b, err return markdown, err
} }
j.metadata.load(m) j.metadata.load(m)
// Retrieve remaining bytes after decoding return markdown, nil
buf := make([]byte, len(b))
n, err := decoder.Buffered().Read(buf)
if err != nil {
return b, err
}
return buf[:n], nil
} }
// Metadata returns parsed metadata. It should be called // Metadata returns parsed metadata. It should be called
...@@ -183,43 +178,29 @@ func (y *YAMLMetadataParser) Closing() []byte { ...@@ -183,43 +178,29 @@ func (y *YAMLMetadataParser) Closing() []byte {
// It returns the metadata, the remaining bytes (markdown), and an error, if any. // It returns the metadata, the remaining bytes (markdown), and an error, if any.
func extractMetadata(parser MetadataParser, b []byte) (metadata []byte, markdown []byte, err error) { func extractMetadata(parser MetadataParser, b []byte) (metadata []byte, markdown []byte, err error) {
b = bytes.TrimSpace(b) b = bytes.TrimSpace(b)
reader := bufio.NewReader(bytes.NewBuffer(b)) openingLine := append(parser.Opening(), '\n')
closingLine := append(parser.Closing(), '\n')
// Read first line, which should indicate metadata or not if !bytes.HasPrefix(b, openingLine) {
line, err := reader.ReadBytes('\n')
if err != nil || !bytes.Equal(bytes.TrimSpace(line), parser.Opening()) {
return nil, b, fmt.Errorf("first line missing expected metadata identifier") return nil, b, fmt.Errorf("first line missing expected metadata identifier")
} }
metaStart := len(openingLine)
// buffer for metadata contents if _, ok := parser.(*JSONMetadataParser); ok {
metaBuf := bytes.Buffer{} metaStart = 0
// Read remaining lines until closing identifier is found
for {
line, err := reader.ReadBytes('\n')
if err != nil && err != io.EOF {
return nil, nil, err
} }
metaEnd := bytes.Index(b[metaStart:], closingLine)
// if closing identifier found, the remaining bytes must be markdown content if metaEnd == -1 {
if bytes.Equal(bytes.TrimSpace(line), parser.Closing()) {
break
}
// if file ended, by this point no closing identifier was found
if err == io.EOF {
return nil, nil, fmt.Errorf("metadata not closed ('%s' not found)", parser.Closing()) return nil, nil, fmt.Errorf("metadata not closed ('%s' not found)", parser.Closing())
} }
metaEnd += metaStart
metaBuf.Write(line) if _, ok := parser.(*JSONMetadataParser); ok {
metaBuf.WriteString("\r\n") metaEnd += len(closingLine)
} }
metadata = b[metaStart:metaEnd]
// By now, the rest of the buffer contains markdown content markdown = b[metaEnd:]
contentBuf := new(bytes.Buffer) if _, ok := parser.(*JSONMetadataParser); !ok {
io.Copy(contentBuf, reader) markdown = b[metaEnd+len(closingLine):]
}
return metaBuf.Bytes(), contentBuf.Bytes(), nil return metadata, markdown, nil
} }
// findParser finds the parser using line that contains opening identifier // findParser finds the parser using line that contains opening identifier
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment