Skip to content

Commit 25cdcbc

Browse files
authored
Add Smile header decoding (#1)
1 parent f94d4ff commit 25cdcbc

13 files changed

+161
-1
lines changed

Makefile

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.PHONY: all
2+
all: fmt test
3+
4+
.PHONY: fmt
5+
fmt:
6+
go fmt ./...
7+
go mod tidy
8+
9+
.PHONY: test
10+
test:
11+
go test -race ./...

domain/header.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package domain
2+
3+
import (
4+
"errors"
5+
)
6+
7+
type Header struct {
8+
Version int
9+
RawBinaryPresent bool
10+
SharedStringValueEncodingEnabled bool
11+
SharedPropertyNameEncodingEnabled bool
12+
}
13+
14+
/*
15+
Header consists of:
16+
17+
Constant byte #0: 0x3A (ASCII ':')
18+
Constant byte #1: 0x29 (ASCII ')')
19+
Constant byte #2: 0x0A (ASCII linefeed, '\n')
20+
Variable byte #3, consisting of bits:
21+
Bits 4-7 (4 MSB): 4-bit version number; 0x00 for current version (note: it is possible that some bits may be reused if necessary)
22+
Bits 3: Reserved
23+
Bit 2 (mask 0x04) Whether '''raw binary''' (unescaped 8-bit) values may be present in content
24+
Bit 1 (mask 0x02): Whether '''shared String value''' checking was enabled during encoding -- if header missing, default value of "false" must be assumed for decoding (meaning parser need not store decoded String values for back referencing)
25+
Bit 0 (mask 0x01): Whether '''shared property name''' checking was enabled during encoding -- if header missing, default value of "true" must be assumed for decoding (meaning parser MUST store seen property names for possible back references)
26+
27+
And basically first 2 bytes form simple smiley and 3rd byte is a (Unix) linefeed: this to make command-line-tool based identification simple: choice of bytes is not significant beyond visual appearance. Fourth byte contains minimal versioning marker and additional configuration bits.
28+
*/
29+
func DecodeHeader(b []byte) (Header, error) {
30+
if len(b) < 4 {
31+
return Header{}, errors.New("smile format must begin with a 4-byte header")
32+
}
33+
34+
if b[0] != ':' || b[1] != ')' || b[2] != '\n' {
35+
return Header{}, errors.New("smile format must begin with the ':)' header followed by a newline")
36+
}
37+
38+
var flags uint8 = b[3]
39+
return Header{
40+
Version: int(flags >> 4),
41+
RawBinaryPresent: (0x04 & flags) != 0,
42+
SharedStringValueEncodingEnabled: (0x02 & flags) != 0,
43+
SharedPropertyNameEncodingEnabled: (0x01 & flags) != 0,
44+
}, nil
45+
}

domain/header_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package domain
2+
3+
import (
4+
"github.com/stretchr/testify/require"
5+
"github.com/zencoder/go-smile/testdata"
6+
"testing"
7+
)
8+
9+
func TestDecodeHeader(t *testing.T) {
10+
b := testdata.LoadJSONOrgSample1(t)
11+
12+
header, err := DecodeHeader(b)
13+
require.NoError(t, err)
14+
15+
require.Equal(
16+
t,
17+
Header{
18+
Version: 0,
19+
RawBinaryPresent: false,
20+
SharedStringValueEncodingEnabled: true,
21+
SharedPropertyNameEncodingEnabled: true,
22+
},
23+
header,
24+
)
25+
}
26+
27+
func TestDecodeHeaderWithoutData(t *testing.T) {
28+
_, err := DecodeHeader([]byte{})
29+
require.EqualError(t, err, "smile format must begin with a 4-byte header")
30+
}
31+
32+
func TestDecodeHeaderWithoutSmilieFails(t *testing.T) {
33+
_, err := DecodeHeader([]byte{':', '(', '\n', '1'})
34+
require.EqualError(t, err, "smile format must begin with the ':)' header followed by a newline")
35+
}

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/zencoder/go-smile
22

33
go 1.14
4+
5+
require github.com/stretchr/testify v1.6.1

go.sum

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
6+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7+
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
8+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
9+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
10+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
11+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
12+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package main
22

3-
func main() {
3+
import "fmt"
44

5+
func main() {
6+
fmt.Println("Hello World!")
57
}

testdata/json-org-sample1.smile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:)
2+
��glossary��titleOexample glossary�GlossDiv�A@S�GlossList��GlossEntry��IDCSGML�SortAs�GlossTermcStandard Generalized Markup Language�Acronym�AbbrevLISO 8879:1986�GlossDef��para�A meta-markup language, used to create markup languages such as DocBook.��GlossSeeAlso�BGMLBXML���GlossSeeEmarkup�����

testdata/json-org-sample2.smile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:)
2+
��menu��idCfile�valueCFile�popup��menuitem��BBNew�onclickMCreateNewDoc()��BCOpenEHOpenDoc()��BDCloseEICloseDoc()�����

testdata/json-org-sample3.smile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:)
2+
��widget��debugAon�window��titleYSample Konfabulator Widget�nameJmain_window�width$��height$���image��srcMImages/Sun.pngDCsun1�hOffset$��vOffset$��alignmentEcenter��text��dataIClick Here�size$��styleCboldDDtext1I$�J$�K�onMouseUphsun1.opacity = (sun1.opacity / 100) * 90;���

testdata/json-org-sample4.smile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:)
2+
��web-app��servlet���servlet-nameGcofaxCDS�servlet-classWorg.cofax.cds.CDSServlet�init-param��configGlossary:installationAtOPhiladelphia, PA�configGlossary:[email protected]�configGlossary:poweredByDCofax�configGlossary:poweredByIconP/images/cofax.gif�configGlossary:staticPathN/content/static�templateProcessorClassXorg.cofax.WysiwygTemplate�templateLoaderClass\org.cofax.FilesTemplateLoader�templatePathHtemplates�templateOverridePath �defaultListTemplateOlistTemplate.htm�defaultFileTemplateRarticleTemplate.htm�useJSP"�jspListTemplateOlistTemplate.jsp�jspFileTemplateRarticleTemplate.jsp�cachePackageTagsTrack$��cachePackageTagsStore$��cachePackageTagsRefresh$��cacheTemplatesTrack$��cacheTemplatesStore$��cacheTemplatesRefreshގcachePagesTrack$��cachePagesStore$��cachePagesRefreshԒcachePagesDirtyReadԗsearchEngineListTemplateWforSearchEnginesList.htm�searchEngineFileTemplateSforSearchEngines.htm�searchEngineRobotsDbPWEB-INF/robots.db�useDataStore#�dataStoreClassUorg.cofax.SqlDataStore�redirectionClassWorg.cofax.SqlRedirection�dataStoreNameDcofax�dataStoreDriverkcom.microsoft.jdbc.sqlserver.SQLServerDriver�dataStoreUrlzjdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon�dataStoreUserAsa�dataStorePasswordQdataStoreTestQuery�dataStoreTestQueryaSET NOCOUNT ON;select test='test';�dataStoreLogFilec/usr/local/tomcat/logs/datastore.log�dataStoreInitConnsԐdataStoreMaxConns$��dataStoreConnUsageLimit$��dataStoreLogLevelDdebug�maxUrlLength$����BIcofaxEmailCYorg.cofax.cds.EmailServletD��mailHostDmail1�mailHostOverrideDmail2���BIcofaxAdminCYorg.cofax.cds.AdminServlet��BJfileServletCXorg.cofax.cds.FileServlet��BIcofaxToolsC^org.cofax.cms.CofaxToolsServletD�LNtoolstemplates/�logŠlogLocationd/usr/local/tomcat/logs/CofaxTools.log�logMaxSize �dataLogŽdataLogLocationa/usr/local/tomcat/logs/dataLog.log�dataLogMaxSize �removePageCached/content/admin/remove?cache=pages&id=�removeTemplateCacheh/content/admin/remove?cache=templates&id=�fileTransferFolders/usr/local/tomcat/webapps/content/fileTransferFolder�lookInContext‹adminGroupIDȉbetaServer#����servlet-mapping��cofaxCDS@/�cofaxEmailR/cofaxutil/aemail/*�cofaxAdminG/admin/*�fileServletH/static/*�cofaxToolsG/tools/*��taglib��taglib-uriHcofax.tld�taglib-locationV/WEB-INF/tlds/cofax.tld���

testdata/json-org-sample5.smile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:)
2+
��menu��headerISVG Viewer�items���idCOpen��CFOpenNew�labelGOpen New�!�CEZoomInDFZoom In��CFZoomOutDGZoom Out��CKOriginalViewDLOriginal View�!�CFQuality��CDPause��CCMute�!�CCFindDFFind...��CHFindAgainDIFind Again��CCCopy��CHCopyAgainDICopy Again��CFCopySVGDGCopy SVG��CFViewSVGDGView SVG��CIViewSourceDJView Source��CESaveAsDFSave As�!�CCHelp��CDAboutDXAbout Adobe CVG Viewer...����

testdata/testdata.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package testdata
2+
3+
import (
4+
"github.com/stretchr/testify/require"
5+
"io/ioutil"
6+
"path/filepath"
7+
"runtime"
8+
"testing"
9+
)
10+
11+
func LoadJSONOrgSample1(t *testing.T) []byte {
12+
return LoadTestData(t, "json-org-sample1.smile")
13+
}
14+
15+
func LoadJSONOrgSample2(t *testing.T) []byte {
16+
return LoadTestData(t, "json-org-sample2.smile")
17+
}
18+
19+
func LoadJSONOrgSample3(t *testing.T) []byte {
20+
return LoadTestData(t, "json-org-sample3.smile")
21+
}
22+
23+
func LoadJSONOrgSample4(t *testing.T) []byte {
24+
return LoadTestData(t, "json-org-sample4.smile")
25+
}
26+
27+
func LoadUnicodeSample(t *testing.T) []byte {
28+
return LoadTestData(t, "unicode.smile")
29+
}
30+
31+
func LoadTestData(t *testing.T, filename string) []byte {
32+
_, testdataFile, _, _ := runtime.Caller(0)
33+
testdataDir := filepath.Dir(testdataFile)
34+
filename = filepath.Join(testdataDir, filename)
35+
36+
b, err := ioutil.ReadFile(filename)
37+
require.NoError(t, err, "Error reading test file %q", filename)
38+
39+
return b
40+
}

testdata/unicode.smile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:)
2+
��chilllllllllllllllllllllllld�Niñññññññññññññññññññññññño�child-jp�子供�child�Niño�
3+

0 commit comments

Comments
 (0)