package native import ( "bytes" "crypto/sha1" "camlistore.org/third_party/github.com/ziutek/mymysql/mysql" "io" "time" ) // Integers func DecodeU16(buf []byte) uint16 { return uint16(buf[1])<<8 | uint16(buf[0]) } func readU16(rd io.Reader) uint16 { buf := make([]byte, 2) readFull(rd, buf) return DecodeU16(buf) } func DecodeU24(buf []byte) uint32 { return (uint32(buf[2])<<8|uint32(buf[1]))<<8 | uint32(buf[0]) } func readU24(rd io.Reader) uint32 { buf := make([]byte, 3) readFull(rd, buf) return DecodeU24(buf) } func DecodeU32(buf []byte) uint32 { return ((uint32(buf[3])<<8|uint32(buf[2]))<<8| uint32(buf[1]))<<8 | uint32(buf[0]) } func readU32(rd io.Reader) uint32 { buf := make([]byte, 4) readFull(rd, buf) return DecodeU32(buf) } func DecodeU64(buf []byte) (rv uint64) { for ii, vv := range buf { rv |= uint64(vv) << uint(ii*8) } return } func readU64(rd io.Reader) (rv uint64) { buf := make([]byte, 8) readFull(rd, buf) return DecodeU64(buf) } func EncodeU16(val uint16) []byte { return []byte{byte(val), byte(val >> 8)} } func writeU16(wr io.Writer, val uint16) { write(wr, EncodeU16(val)) } func EncodeU24(val uint32) []byte { return []byte{byte(val), byte(val >> 8), byte(val >> 16)} } func writeU24(wr io.Writer, val uint32) { write(wr, EncodeU24(val)) } func EncodeU32(val uint32) []byte { return []byte{byte(val), byte(val >> 8), byte(val >> 16), byte(val >> 24)} } func writeU32(wr io.Writer, val uint32) { write(wr, EncodeU32(val)) } func EncodeU64(val uint64) []byte { buf := make([]byte, 8) for ii := range buf { buf[ii] = byte(val >> uint(ii*8)) } return buf } func writeU64(wr io.Writer, val uint64) { write(wr, EncodeU64(val)) } // Variable length values func readNullLCB(rd io.Reader) (lcb uint64, null bool) { bb := readByte(rd) switch bb { case 251: null = true case 252: lcb = uint64(readU16(rd)) case 253: lcb = uint64(readU24(rd)) case 254: lcb = readU64(rd) default: lcb = uint64(bb) } return } func readLCB(rd io.Reader) uint64 { lcb, null := readNullLCB(rd) if null { panic(UNEXP_NULL_LCB_ERROR) } return lcb } func writeLCB(wr io.Writer, val uint64) { switch { case val <= 250: writeByte(wr, byte(val)) case val <= 0xffff: writeByte(wr, 252) writeU16(wr, uint16(val)) case val <= 0xffffff: writeByte(wr, 253) writeU24(wr, uint32(val)) default: writeByte(wr, 254) writeU64(wr, val) } } func lenLCB(val uint64) int { switch { case val <= 250: return 1 case val <= 0xffff: return 3 case val <= 0xffffff: return 4 } return 9 } func readNullBin(rd io.Reader) (buf []byte, null bool) { var l uint64 l, null = readNullLCB(rd) if null { return } buf = make([]byte, l) readFull(rd, buf) return } func readBin(rd io.Reader) []byte { buf, null := readNullBin(rd) if null { panic(UNEXP_NULL_LCS_ERROR) } return buf } func writeBin(wr io.Writer, buf []byte) { writeLCB(wr, uint64(len(buf))) write(wr, buf) } func lenBin(buf []byte) int { return lenLCB(uint64(len(buf))) + len(buf) } func readStr(rd io.Reader) (str string) { buf := readBin(rd) str = string(buf) return } func writeStr(wr io.Writer, str string) { writeLCB(wr, uint64(len(str))) writeString(wr, str) } func lenStr(str string) int { return lenLCB(uint64(len(str))) + len(str) } func writeLC(wr io.Writer, v interface{}) { switch val := v.(type) { case []byte: writeBin(wr, val) case *[]byte: writeBin(wr, *val) case string: writeStr(wr, val) case *string: writeStr(wr, *val) default: panic("Unknown data type for write as lenght coded string") } } func lenLC(v interface{}) int { switch val := v.(type) { case []byte: return lenBin(val) case *[]byte: return lenBin(*val) case string: return lenStr(val) case *string: return lenStr(*val) } panic("Unknown data type for write as lenght coded string") } func readNTB(rd io.Reader) (buf []byte) { bb := new(bytes.Buffer) for { ch := readByte(rd) if ch == 0 { return bb.Bytes() } bb.WriteByte(ch) } return } func writeNTB(wr io.Writer, buf []byte) { write(wr, buf) writeByte(wr, 0) } func readNTS(rd io.Reader) (str string) { buf := readNTB(rd) str = string(buf) return } func writeNTS(wr io.Writer, str string) { writeNTB(wr, []byte(str)) } func writeNT(wr io.Writer, v interface{}) { switch val := v.(type) { case []byte: writeNTB(wr, val) case string: writeNTS(wr, val) default: panic("Unknown type for write as null terminated data") } } // Date and time func readDuration(rd io.Reader) time.Duration { dlen := readByte(rd) switch dlen { case 251: // Null panic(UNEXP_NULL_TIME_ERROR) case 0: // 00:00:00 return 0 case 5, 8, 12: // Properly time length default: panic(WRONG_DATE_LEN_ERROR) } buf := make([]byte, dlen) readFull(rd, buf) tt := int64(0) switch dlen { case 12: // Nanosecond part tt += int64(DecodeU32(buf[8:])) fallthrough case 8: // HH:MM:SS part tt += int64(int(buf[5])*3600+int(buf[6])*60+int(buf[7])) * 1e9 fallthrough case 5: // Day part tt += int64(DecodeU32(buf[1:5])) * (24 * 3600 * 1e9) fallthrough } if buf[0] != 0 { tt = -tt } return time.Duration(tt) } func EncodeDuration(d time.Duration) []byte { buf := make([]byte, 13) if d < 0 { buf[1] = 1 d = -d } if ns := uint32(d % 1e9); ns != 0 { copy(buf[9:13], EncodeU32(ns)) // nanosecond buf[0] += 4 } d /= 1e9 if hms := int(d % (24 * 3600)); buf[0] != 0 || hms != 0 { buf[8] = byte(hms % 60) // second hms /= 60 buf[7] = byte(hms % 60) // minute buf[6] = byte(hms / 60) // hour buf[0] += 3 } if day := uint32(d / (24 * 3600)); buf[0] != 0 || day != 0 { copy(buf[2:6], EncodeU32(day)) // day buf[0] += 4 } buf[0]++ // For sign byte buf = buf[0 : buf[0]+1] return buf } func writeDuration(wr io.Writer, d time.Duration) { write(wr, EncodeDuration(d)) } func lenDuration(d time.Duration) int { if d == 0 { return 2 } if d%1e9 != 0 { return 13 } d /= 1e9 if d%(24*3600) != 0 { return 9 } return 6 } func readTime(rd io.Reader) time.Time { dlen := readByte(rd) switch dlen { case 251: // Null panic(UNEXP_NULL_DATE_ERROR) case 0: // return 0000-00-00 converted to time.Time zero return time.Time{} case 4, 7, 11: // Properly datetime length default: panic(WRONG_DATE_LEN_ERROR) } buf := make([]byte, dlen) readFull(rd, buf) var y, mon, d, h, m, s, n int switch dlen { case 11: // 2006-01-02 15:04:05.001004005 n = int(DecodeU32(buf[7:])) fallthrough case 7: // 2006-01-02 15:04:05 h = int(buf[4]) m = int(buf[5]) s = int(buf[6]) fallthrough case 4: // 2006-01-02 y = int(DecodeU16(buf[0:2])) mon = int(buf[2]) d = int(buf[3]) } return time.Date(y, time.Month(mon), d, h, m, s, n, time.Local) } func encodeNonzeroTime(y int16, mon, d, h, m, s byte, n uint32) []byte { buf := make([]byte, 12) switch { case n != 0: copy(buf[7:12], EncodeU32(n)) buf[0] += 4 fallthrough case s != 0 || m != 0 || h != 0: buf[7] = s buf[6] = m buf[5] = h buf[0] += 3 } buf[4] = d buf[3] = mon copy(buf[1:3], EncodeU16(uint16(y))) buf[0] += 4 buf = buf[0 : buf[0]+1] return buf } func EncodeTime(t time.Time) []byte { if t.IsZero() { return []byte{0} // MySQL zero } y, mon, d := t.Date() h, m, s := t.Clock() n := t.Nanosecond() return encodeNonzeroTime( int16(y), byte(mon), byte(d), byte(h), byte(m), byte(s), uint32(n), ) } func writeTime(wr io.Writer, t time.Time) { write(wr, EncodeTime(t)) } func lenTime(t time.Time) int { switch { case t.IsZero(): return 1 case t.Nanosecond() != 0: return 12 case t.Second() != 0 || t.Minute() != 0 || t.Hour() != 0: return 8 } return 5 } func readDate(rd io.Reader) mysql.Date { y, m, d := readTime(rd).Date() return mysql.Date{int16(y), byte(m), byte(d)} } func EncodeDate(d mysql.Date) []byte { if d.IsZero() { return []byte{0} // MySQL zero } return encodeNonzeroTime(d.Year, d.Month, d.Day, 0, 0, 0, 0) } func writeDate(wr io.Writer, d mysql.Date) { write(wr, EncodeDate(d)) } func lenDate(d mysql.Date) int { if d.IsZero() { return 1 } return 5 } // Borrowed from GoMySQL // SHA1(SHA1(SHA1(password)), scramble) XOR SHA1(password) func (my *Conn) encryptedPasswd() (out []byte) { // Convert password to byte array passbytes := []byte(my.passwd) // stage1_hash = SHA1(password) // SHA1 encode crypt := sha1.New() crypt.Write(passbytes) stg1Hash := crypt.Sum(nil) // token = SHA1(SHA1(stage1_hash), scramble) XOR stage1_hash // SHA1 encode again crypt.Reset() crypt.Write(stg1Hash) stg2Hash := crypt.Sum(nil) // SHA1 2nd hash and scramble crypt.Reset() crypt.Write(my.info.scramble) crypt.Write(stg2Hash) stg3Hash := crypt.Sum(nil) // XOR with first hash out = make([]byte, len(my.info.scramble)) for ii := range my.info.scramble { out[ii] = stg3Hash[ii] ^ stg1Hash[ii] } return } func escapeString(txt string) string { var ( esc string buf bytes.Buffer ) last := 0 for ii, bb := range txt { switch bb { case 0: esc = `\0` case '\n': esc = `\n` case '\r': esc = `\r` case '\\': esc = `\\` case '\'': esc = `\'` case '"': esc = `\"` case '\032': esc = `\Z` default: continue } io.WriteString(&buf, txt[last:ii]) io.WriteString(&buf, esc) last = ii + 1 } io.WriteString(&buf, txt[last:]) return buf.String() } func escapeQuotes(txt string) string { var buf bytes.Buffer last := 0 for ii, bb := range txt { if bb == '\'' { io.WriteString(&buf, txt[last:ii]) io.WriteString(&buf, `''`) last = ii + 1 } } io.WriteString(&buf, txt[last:]) return buf.String() }