diff --git a/bplist_generator.go b/bplist_generator.go index 5b6513d16b9f081d01d43359b89dc3f95b0a0ecc..09ab71b1f4e647bcc63a91a2169a9bdfcb16fc6d 100644 --- a/bplist_generator.go +++ b/bplist_generator.go @@ -109,7 +109,7 @@ func (p *bplistGenerator) writePlistValue(pval cfValue) { case cfString: p.writeStringTag(string(pval)) case *cfNumber: - p.writeIntTag(pval.value) + p.writeIntTag(pval.signed, pval.value) case *cfReal: if pval.wide { p.writeRealTag(pval.value, 64) @@ -154,7 +154,7 @@ func (p *bplistGenerator) writeBoolTag(v bool) { binary.Write(p.writer, binary.BigEndian, tag) } -func (p *bplistGenerator) writeIntTag(n uint64) { +func (p *bplistGenerator) writeIntTag(signed bool, n uint64) { var tag uint8 var val interface{} switch { @@ -167,12 +167,25 @@ func (p *bplistGenerator) writeIntTag(n uint64) { case n <= uint64(0xffffffff): val = uint32(n) tag = bpTagInteger | 0x2 + case n > uint64(0x7fffffffffffffff) && !signed: + // 64-bit values are always *signed* in format 00. + // Any unsigned value that doesn't intersect with the signed + // range must be sign-extended and stored as a SInt128 + val = n + tag = bpTagInteger | 0x4 default: val = n tag = bpTagInteger | 0x3 } binary.Write(p.writer, binary.BigEndian, tag) + if tag&0xF == 0x4 { + // SInt128; in the absence of true 128-bit integers in Go, + // we'll just fake the top half. We only got here because + // we had an unsigned 64-bit int that didn't fit, + // so sign extend it with zeroes. + binary.Write(p.writer, binary.BigEndian, uint64(0)) + } binary.Write(p.writer, binary.BigEndian, val) } @@ -216,7 +229,7 @@ func (p *bplistGenerator) writeCountedTag(tag uint8, count uint64) { binary.Write(p.writer, binary.BigEndian, marker) if count >= 0xF { - p.writeIntTag(count) + p.writeIntTag(false, count) } } diff --git a/common_data_for_test.go b/common_data_for_test.go index 7ab295032f1ff7234249a45228be98abfe959ea4..973b09d8e9e1f441ce15286649066771f5ba2fa2 100644 --- a/common_data_for_test.go +++ b/common_data_for_test.go @@ -313,12 +313,12 @@ var tests = []TestData{ }, { Name: "Unsigned Integers of Increasing Size", - Value: []uint64{0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0xffffffff, 0xffffffffffffffff}, + Value: []uint64{0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0xffffffff, 0x7fffffffffffffff, 0xdeadbeeffacecafe}, Documents: map[int][]byte{ - OpenStepFormat: []byte(`(255,4095,65535,1048575,16777215,268435455,4294967295,18446744073709551615,)`), - GNUStepFormat: []byte(`(<*I255>,<*I4095>,<*I65535>,<*I1048575>,<*I16777215>,<*I268435455>,<*I4294967295>,<*I18446744073709551615>,)`), - XMLFormat: []byte(xmlPreamble + `<plist version="1.0"><array><integer>255</integer><integer>4095</integer><integer>65535</integer><integer>1048575</integer><integer>16777215</integer><integer>268435455</integer><integer>4294967295</integer><integer>18446744073709551615</integer></array></plist>`), - BinaryFormat: []byte{98, 112, 108, 105, 115, 116, 48, 48, 168, 1, 2, 3, 4, 5, 6, 7, 8, 16, 255, 17, 15, 255, 17, 255, 255, 18, 0, 15, 255, 255, 18, 0, 255, 255, 255, 18, 15, 255, 255, 255, 18, 255, 255, 255, 255, 19, 255, 255, 255, 255, 255, 255, 255, 255, 8, 17, 19, 22, 25, 30, 35, 40, 45, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54}, + OpenStepFormat: []byte(`(255,4095,65535,1048575,16777215,268435455,4294967295,9223372036854775807,16045690985305262846,)`), + GNUStepFormat: []byte(`(<*I255>,<*I4095>,<*I65535>,<*I1048575>,<*I16777215>,<*I268435455>,<*I4294967295>,<*I9223372036854775807>,<*I16045690985305262846>,)`), + XMLFormat: []byte(xmlPreamble + `<plist version="1.0"><array><integer>255</integer><integer>4095</integer><integer>65535</integer><integer>1048575</integer><integer>16777215</integer><integer>268435455</integer><integer>4294967295</integer><integer>9223372036854775807</integer><integer>16045690985305262846</integer></array></plist>`), + BinaryFormat: []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xa9, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0xff, 0x11, 0x0f, 0xff, 0x11, 0xff, 0xff, 0x12, 0x00, 0x0f, 0xff, 0xff, 0x12, 0x00, 0xff, 0xff, 0xff, 0x12, 0x0f, 0xff, 0xff, 0xff, 0x12, 0xff, 0xff, 0xff, 0xff, 0x13, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xca, 0xfe, 0x08, 0x12, 0x14, 0x17, 0x1a, 0x1f, 0x24, 0x29, 0x2e, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48}, }, }, { @@ -597,12 +597,12 @@ var tests = []TestData{ }, { Name: "Signed Integers", - Value: []int64{-1, -127, -255, -32767, -65535}, + Value: []int64{-1, -127, -255, -32767, -65535, -9223372036854775808}, Documents: map[int][]byte{ - OpenStepFormat: []byte(`(-1,-127,-255,-32767,-65535,)`), - GNUStepFormat: []byte(`(<*I-1>,<*I-127>,<*I-255>,<*I-32767>,<*I-65535>,)`), - XMLFormat: []byte(xmlPreamble + `<plist version="1.0"><array><integer>-1</integer><integer>-127</integer><integer>-255</integer><integer>-32767</integer><integer>-65535</integer></array></plist>`), - BinaryFormat: []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xa5, 0x1, 0x2, 0x3, 0x4, 0x5, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x1, 0x8, 0xe, 0x17, 0x20, 0x29, 0x32, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b}, + OpenStepFormat: []byte(`(-1,-127,-255,-32767,-65535,-9223372036854775808,)`), + GNUStepFormat: []byte(`(<*I-1>,<*I-127>,<*I-255>,<*I-32767>,<*I-65535>,<*I-9223372036854775808>,)`), + XMLFormat: []byte(xmlPreamble + `<plist version="1.0"><array><integer>-1</integer><integer>-127</integer><integer>-255</integer><integer>-32767</integer><integer>-65535</integer><integer>-9223372036854775808</integer></array></plist>`), + BinaryFormat: []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xa6, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x13, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x18, 0x21, 0x2a, 0x33, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45}, }, }, {