作者 陈志颖

refactor:增加合伙人编号

正在显示 37 个修改的文件 包含 1645 行增加1662 行删除
appname = partnermg
runmode = "${RUN_MODE||dev}"
httpport = "${HTTP_PORT||8082}"
httpport = "${HTTP_PORT||8083}"
#开启监控
EnableAdmin = false
... ...
... ... @@ -4,7 +4,6 @@ go 1.14
require (
github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1
github.com/GeeTeam/gt3-golang-sdk v0.0.0-20200116043922-446ca8a507d2
github.com/Shopify/sarama v1.23.1
github.com/ajg/form v1.5.1 // indirect
github.com/astaxie/beego v1.12.2
... ...
... ... @@ -17,7 +17,7 @@ type CreatePartnerInfoCommand struct {
// 状态(1:启用或者0:禁用)
Status int `json:"status"`
// 合伙类别
PartnerCategory []int64 `json:"partnerCategory,omitempty"`
PartnerCategory []*domain.PartnerCategory `json:"partnerCategory,omitempty"`
//合作时间
CooperateTime time.Time `json:"cooperateTime"`
// 区域
... ... @@ -26,6 +26,8 @@ type CreatePartnerInfoCommand struct {
Salesman []domain.Salesman `json:"salesman,omitempty"`
//公司id
CompanyId int64 `json:"companyId"`
//备注
Remark string `json:"remark"`
}
func (command CreatePartnerInfoCommand) ValidateCommand() error {
... ...
/**
@author: stevechan
@date: 2020/12/29
@note:
**/
package command
import (
"gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/lib"
)
// 移除合伙人
type RemovePartnerInfoCommand struct {
// 合伙人Id
Id int64 `json:"id" valid:"Required"`
}
func (command *RemovePartnerInfoCommand) ValidateCommand() error {
if command.Id == 0 {
return lib.ThrowError(lib.ARG_ERROR, "合伙人id错误")
}
return nil
}
... ...
... ... @@ -13,7 +13,7 @@ type UpdatePartnerInfoCommand struct {
// 状态(1:启用或者0:禁用)
Status int `json:"status"`
// 合伙类别 (1.研发合伙人 2.业务合伙人 3.事业)
PartnerCategory []int64 `json:"partnerCategory,omitempty"`
PartnerCategory []*domain.PartnerCategory `json:"partnerCategory,omitempty"`
// 区域
RegionInfo *domain.RegionInfo `json:"regionInfo"`
//关联业务员
... ... @@ -22,6 +22,8 @@ type UpdatePartnerInfoCommand struct {
CooperateTime time.Time `json:"cooperateTime"`
//公司id
CompanyId int64 `json:"companyId"`
//备注
Remark string `json:"remark"`
}
func (command *UpdatePartnerInfoCommand) ValidateCommand() error {
... ...
... ... @@ -2,12 +2,13 @@ package query
type ListPartnerInfoQuery struct {
// 合伙人类别
Partnertype int `json:"partnerType"`
PartnerType int `json:"partnerType"`
//所属区域
RegionInfo string `json:"regionInfo"`
// 合伙人姓名
PartnerName string `json:"partnerName"`
CompanyId int64 `json:"companyId"`
// 公司id
CompanyId int64 `json:"companyId"`
// 查询偏离量
Offset int `json:"offset"`
// 查询限制
... ... @@ -15,6 +16,5 @@ type ListPartnerInfoQuery struct {
}
func (q *ListPartnerInfoQuery) ValidateQuery() error {
return nil
}
... ...
... ... @@ -21,7 +21,13 @@ func NewPartnerInfoService(options map[string]interface{}) *PartnerInfoService {
return newPartnerInfoService
}
// CreatePartnerInfo 创建合伙人
/**
* @Author SteveChan
* @Description //TODO 创建合伙人,判断编号是否重复
* @Date 15:42 2020/12/29
* @Param
* @return
**/
func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.CreatePartnerInfoCommand) (data *domain.PartnerInfo, err error) {
var (
transactionContext, _ = factory.CreateTransactionContext(nil)
... ... @@ -35,16 +41,17 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
defer func() {
transactionContext.RollbackTransaction()
}()
//检查账号是否存在
var (
partnerinfoDao *dao.PartnerInfoDao
partnerInfoDao *dao.PartnerInfoDao
)
if partnerinfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
if partnerInfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
}
ok, err := partnerinfoDao.PartnerAccountExist(cmd.Account, cmd.CompanyId)
ok, err := partnerInfoDao.PartnerAccountExist(cmd.Account, cmd.CompanyId)
if err != nil {
return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
}
... ... @@ -55,7 +62,7 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
var (
partnerInfoRepository domain.PartnerInfoRepository
categoryRepository domain.PartnerCategoryRepository
categorys []domain.PartnerCategory
categories []domain.PartnerCategory
)
if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
"transactionContext": transactionContext,
... ... @@ -67,13 +74,18 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
}); err != nil {
return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
}
_, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
Ids: cmd.PartnerCategory,
var ids []int64
for _, partnerCategory := range cmd.PartnerCategory {
ids = append(ids, partnerCategory.Id)
}
_, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
Ids: ids,
})
if err != nil {
e := fmt.Sprintf("获取合伙人分类数据失败:%s", err)
return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
}
newPartnerInfo := domain.PartnerInfo{
Partner: domain.Partner{
Account: cmd.Account,
... ... @@ -86,7 +98,7 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
Salesman: cmd.Salesman,
CooperateTime: cmd.CooperateTime,
CompanyId: cmd.CompanyId,
PartnerCategoryInfos: categorys,
PartnerCategoryInfos: categories,
}
if err = partnerInfoRepository.Save(&newPartnerInfo); err != nil {
return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
... ... @@ -106,7 +118,13 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
return &newPartnerInfo, nil
}
// GetPartnerInfo 返回合伙人
/**
* @Author SteveChan
* @Description //TODO 返回合伙人,增加合伙人编号字段
* @Date 15:43 2020/12/29
* @Param
* @return
**/
func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerInfoQuery) (data *domain.PartnerInfo, err error) {
var (
transactionContext, _ = factory.CreateTransactionContext(nil)
... ... @@ -123,7 +141,7 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI
var (
PartnerInfoRepository domain.PartnerInfoRepository
categoryRepository domain.PartnerCategoryRepository
categorys []domain.PartnerCategory
categories []domain.PartnerCategory
partnerData *domain.PartnerInfo
)
if PartnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
... ... @@ -145,19 +163,19 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI
}); err != nil {
return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
}
categoryIds := []int64{}
var categoryIds []int64
for _, v := range partnerData.PartnerCategoryInfos {
categoryIds = append(categoryIds, v.Id)
}
if len(categoryIds) > 0 {
_, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
_, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
Ids: categoryIds,
})
if err != nil {
return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
}
}
partnerData.PartnerCategoryInfos = categorys
partnerData.PartnerCategoryInfos = categories
err = transactionContext.CommitTransaction()
return partnerData, nil
}
... ... @@ -191,15 +209,20 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd
}); err != nil {
return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
}
var ids []int64
for _, partnerCategory := range cmd.PartnerCategory {
ids = append(ids, partnerCategory.Id)
}
_, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
Ids: cmd.PartnerCategory,
Ids: ids,
})
if err != nil {
e := fmt.Sprintf("获取合伙人分类数据失败:%s", err)
return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
}
partnerInfo, err := partnerInfoRepository.FindOne(domain.PartnerFindOneQuery{
UserId: cmd.Id, CompanyId: cmd.CompanyId,
UserId: cmd.Id,
CompanyId: cmd.CompanyId,
})
if err != nil {
return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
... ... @@ -246,14 +269,13 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
return 0, nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
}
defer func() {
transactionContext.RollbackTransaction()
}()
var (
partnerInfoRepository domain.PartnerInfoRepository
categoryRepository domain.PartnerCategoryRepository
categorys []domain.PartnerCategory
categories []domain.PartnerCategory
)
if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
"transactionContext": transactionContext,
... ... @@ -271,8 +293,8 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
PartnerName: listPartnerInfoQuery.PartnerName,
CompanyId: listPartnerInfoQuery.CompanyId,
}
if listPartnerInfoQuery.Partnertype > 0 {
queryOption.PartnerCategory = []int{listPartnerInfoQuery.Partnertype}
if listPartnerInfoQuery.PartnerType > 0 {
queryOption.PartnerCategory = []int{listPartnerInfoQuery.PartnerType}
}
// RegionInfo
if len(listPartnerInfoQuery.RegionInfo) > 0 {
... ... @@ -284,18 +306,18 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
if count, err = partnerInfoRepository.CountAll(queryOption); err != nil {
return 0, nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
}
_, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{})
_, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{})
if err != nil {
return count, partnerInfos, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
}
categorysMap := make(map[int64]domain.PartnerCategory)
for i := range categorys {
categorysMap[categorys[i].Id] = categorys[i]
categoriesMap := make(map[int64]domain.PartnerCategory)
for i := range categories {
categoriesMap[categories[i].Id] = categories[i]
}
for i := range partnerInfos {
categoryInPartner := []domain.PartnerCategory{}
var categoryInPartner []domain.PartnerCategory
for _, vv := range partnerInfos[i].PartnerCategoryInfos {
if categoryData, ok := categorysMap[vv.Id]; ok {
if categoryData, ok := categoriesMap[vv.Id]; ok {
categoryInPartner = append(categoryInPartner, categoryData)
}
}
... ... @@ -307,6 +329,30 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
return count, partnerInfos, nil
}
/**
* @Author SteveChan
* @Description //TODO 移除合伙人
* @Date 16:40 2020/12/29
* @Param
* @return
**/
func (PartnerInfoService *PartnerInfoService) RemovePartnerInfo(cmd command.RemovePartnerInfoCommand) (err error) {
var (
transactionContext, _ = factory.CreateTransactionContext(nil)
)
if err = cmd.ValidateCommand(); err != nil {
return application.ThrowError(application.ARG_ERROR, err.Error())
}
if err = transactionContext.StartTransaction(); err != nil {
return err
}
defer func() {
transactionContext.RollbackTransaction()
}()
return nil
}
func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPartnerInfoCommand) (err error) {
if len(cmd.Ids) == 0 {
return nil
... ... @@ -324,14 +370,14 @@ func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPar
transactionContext.RollbackTransaction()
}()
var (
partnerinfoDao *dao.PartnerInfoDao
partnerInfoDao *dao.PartnerInfoDao
)
if partnerinfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
if partnerInfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
"transactionContext": transactionContext,
}); err != nil {
return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
}
err = partnerinfoDao.UpdatePartnerStatus(cmd.Ids, cmd.CompanyId, cmd.Status)
err = partnerInfoDao.UpdatePartnerStatus(cmd.Ids, cmd.CompanyId, cmd.Status)
if err != nil {
e := fmt.Sprintf("更新合伙人(id=%v)的数据失败;%s", cmd.Ids, err)
return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
... ...
... ... @@ -8,14 +8,14 @@ var LOG_LEVEL = "debug"
var LOG_File = "./logs/partnermg.log"
var (
UCENTER_HOST = "https://suplus-ucenter-dev.fjmaimaimai.com" //统一用户中心地址
UCENTER_HOST = "https://suplus-ucenter-test.fjmaimaimai.com" //统一用户中心地址
UCENTER_SECRET = "cykbjnfqgctn"
UCENTER_APP_KEY = "39aefef9e22744a3b2d2d3791824ae7b"
UCENTER_CHECK_ALT = "rsF0pL!6DwjBO735"
)
var (
BUSINESS_ADMIN_HOST = "http://suplus-business-admin-dev.fjmaimaimai.com" //企业平台的地址
BUSINESS_ADMIN_HOST = "http://suplus-business-admin-test.fjmaimaimai.com" //企业平台的地址
)
func init() {
... ... @@ -34,9 +34,7 @@ func init() {
if os.Getenv("UCENTER_CHECK_ALT") != "" {
UCENTER_CHECK_ALT = os.Getenv("UCENTER_CHECK_ALT")
}
if os.Getenv("BUSINESS_ADMIN_HOST") != "" {
BUSINESS_ADMIN_HOST = os.Getenv("BUSINESS_ADMIN_HOST")
}
}
... ...
... ... @@ -14,7 +14,7 @@ var KafkaCfg KafkaConfig
func init() {
KafkaCfg = KafkaConfig{
Servers: []string{""},
Servers: []string{"127.0.0.1:9092"},
ConsumerId: "partnermg_local",
}
if os.Getenv("KAFKA_HOST") != "" {
... ...
... ... @@ -2,7 +2,7 @@ package constant
import "os"
var POSTGRESQL_DB_NAME = "partner_dev"
var POSTGRESQL_DB_NAME = "partner_test"
var POSTGRESQL_USER = "postgres"
var POSTGRESQL_PASSWORD = "eagle1010"
var POSTGRESQL_HOST = "114.55.200.59"
... ...
... ... @@ -114,7 +114,7 @@ type OrderBase struct {
DataFrom OrderDataFrom `json:"dataFrom"`
//备注
Remark OrderBaseRemark `json:"remark"`
//合伙人类型
PartnerCategory PartnerCategory `json:"partnerCategory"`
}
... ...
... ... @@ -6,6 +6,8 @@ type PartnerCategory struct {
Id int64 `json:"id"`
// 名称
Name string `json:"name,omitempty"`
// 合伙人编码
Code string `json:"code"`
}
type PartnerCategoryFindQuery struct {
... ...
... ... @@ -48,6 +48,8 @@ type PartnerInfo struct {
PartnerCategory int `json:"partnerCategory"`
//公司id
CompanyId int64 `json:"companyId"`
//备注
Remark string `json:"remark"`
}
func (p *PartnerInfo) IsUsable() bool {
... ... @@ -78,5 +80,6 @@ type PartnerInfoRepository interface {
Save(dm *PartnerInfo) error
FindOne(queryOptions PartnerFindOneQuery) (*PartnerInfo, error)
Find(queryOptions PartnerFindQuery) ([]PartnerInfo, error)
Remove(Id int64) error
CountAll(queryOptions PartnerFindQuery) (int, error)
}
... ...
... ... @@ -42,3 +42,14 @@ func (dao PartnerInfoDao) UpdatePartnerStatus(ids []int64, companyId int64, stat
Update()
return err
}
/**
* @Author SteveChan
* @Description //TODO 编号查重
* @Date 17:55 2020/12/28
* @Param
* @return
**/
func (dao PartnerInfoDao) CheckDuplication() {
}
... ...
... ... @@ -7,4 +7,6 @@ type PartnerCategoryInfo struct {
Id int64
// 名称
Name string
// 合伙人编码
Code string
}
... ...
... ... @@ -36,6 +36,8 @@ type PartnerInfo struct {
PartnerCategoryInfos []domain.PartnerCategory
//公司id
CompanyId int64
//备注
Remark string
}
var _ pg.BeforeUpdateHook = (*PartnerInfo)(nil)
... ...
... ... @@ -12,21 +12,6 @@ type PartnerCategoryRepository struct {
transactionContext *transaction.TransactionContext
}
func (repository PartnerCategoryRepository) transformPgModelToDomainModel(m *models.PartnerCategoryInfo) (domain.PartnerCategory, error) {
pc := domain.PartnerCategory{
Id: m.Id,
Name: m.Name,
}
return pc, nil
}
func NewPartnerCategoryRepository(transactionContext *transaction.TransactionContext) (*PartnerCategoryRepository, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
}
return &PartnerCategoryRepository{transactionContext: transactionContext}, nil
}
func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCategoryFindQuery) (int, []domain.PartnerCategory, error) {
tx := repository.transactionContext.PgTx
var (
... ... @@ -48,3 +33,19 @@ func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCate
}
return cnt, partnerCategoryInfos, nil
}
func (repository PartnerCategoryRepository) transformPgModelToDomainModel(m *models.PartnerCategoryInfo) (domain.PartnerCategory, error) {
pc := domain.PartnerCategory{
Id: m.Id,
Name: m.Name,
Code: m.Code,
}
return pc, nil
}
func NewPartnerCategoryRepository(transactionContext *transaction.TransactionContext) (*PartnerCategoryRepository, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
}
return &PartnerCategoryRepository{transactionContext: transactionContext}, nil
}
... ...
... ... @@ -18,50 +18,18 @@ var (
_ domain.PartnerInfoRepository = (*PartnerInfoRepository)(nil)
)
func (repository *PartnerInfoRepository) transformPgModelToDomainModel(partnerInfoModel *models.PartnerInfo) (domain.PartnerInfo, error) {
m := domain.PartnerInfo{
Partner: domain.Partner{
Id: partnerInfoModel.Id,
PartnerName: partnerInfoModel.PartnerName,
Account: partnerInfoModel.Account,
},
PartnerCategory: partnerInfoModel.PartnerCategory,
Password: partnerInfoModel.Password,
Status: partnerInfoModel.Status,
CreateAt: partnerInfoModel.CreateAt,
Salesman: partnerInfoModel.Salesman,
RegionInfo: partnerInfoModel.RegionInfo,
CooperateTime: partnerInfoModel.CooperateTime,
CompanyId: partnerInfoModel.CompanyId,
}
p := []domain.PartnerCategory{}
for _, v := range partnerInfoModel.PartnerCategoryInfos {
catagory := domain.PartnerCategory{
Id: v.Id,
}
p = append(p, catagory)
}
m.PartnerCategoryInfos = p
return m, nil
}
func NewPartnerInfoRepository(transactionContext *transaction.TransactionContext) (*PartnerInfoRepository, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
}
return &PartnerInfoRepository{transactionContext: transactionContext}, nil
}
func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
var (
err error
tx = repository.transactionContext.PgTx
)
categorys := []domain.PartnerCategory{}
var categories []domain.PartnerCategory
for _, v := range dm.PartnerCategoryInfos {
categorys = append(categorys, domain.PartnerCategory{
Id: v.Id,
categories = append(categories, domain.PartnerCategory{
Id: v.Id,
Name: v.Name,
Code: v.Code,
})
}
m := &models.PartnerInfo{
... ... @@ -75,7 +43,8 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
RegionInfo: dm.RegionInfo,
CooperateTime: dm.CooperateTime,
CompanyId: dm.CompanyId,
PartnerCategoryInfos: categorys,
PartnerCategoryInfos: categories,
Remark: dm.Remark,
}
if m.Id == 0 {
err = tx.Insert(m)
... ... @@ -86,7 +55,7 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
} else {
_, err = tx.Model(m).WherePK().
Column("partner_name", "account", "password", "status", "partner_category", "salesman",
"region_info", "cooperate_time", "update_at", "partner_category_infos").
"region_info", "cooperate_time", "update_at", "partner_category_infos, remark").
Update()
if err != nil {
return err
... ... @@ -124,7 +93,7 @@ func (repository *PartnerInfoRepository) FindOne(queryOptions domain.PartnerFind
func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuery) ([]domain.PartnerInfo, error) {
db := repository.transactionContext.PgTx
partnerModels := []models.PartnerInfo{}
var partnerModels []models.PartnerInfo
query := db.Model(&partnerModels)
if len(queryOption.PartnerName) > 0 {
query = query.Where("partner_name like ?", "%"+queryOption.PartnerName+"%")
... ... @@ -174,7 +143,28 @@ func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuer
return partnerReturn, nil
}
func (repository PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQuery) (int, error) {
/**
* @Author SteveChan
* @Description //TODO 移除合伙人
* @Date 15:33 2020/12/29
* @Param
* @return
**/
func (repository *PartnerInfoRepository) Remove(id int64) error {
var (
err error
tx = repository.transactionContext.PgTx
)
m := &models.PartnerInfo{
Id: id,
}
_, err = tx.Model(m).
Where("id=?", id).
Delete()
return err
}
func (repository *PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQuery) (int, error) {
db := repository.transactionContext.PgTx
partnerModels := models.PartnerInfo{}
query := db.Model(&partnerModels)
... ... @@ -202,3 +192,40 @@ func (repository PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQ
cnt, err := query.Count()
return cnt, err
}
func (repository *PartnerInfoRepository) transformPgModelToDomainModel(partnerInfoModel *models.PartnerInfo) (domain.PartnerInfo, error) {
m := domain.PartnerInfo{
Partner: domain.Partner{
Id: partnerInfoModel.Id,
PartnerName: partnerInfoModel.PartnerName,
Account: partnerInfoModel.Account,
},
PartnerCategory: partnerInfoModel.PartnerCategory,
Password: partnerInfoModel.Password,
Status: partnerInfoModel.Status,
CreateAt: partnerInfoModel.CreateAt,
Salesman: partnerInfoModel.Salesman,
RegionInfo: partnerInfoModel.RegionInfo,
CooperateTime: partnerInfoModel.CooperateTime,
CompanyId: partnerInfoModel.CompanyId,
Remark: partnerInfoModel.Remark,
}
var p []domain.PartnerCategory
for _, v := range partnerInfoModel.PartnerCategoryInfos {
category := domain.PartnerCategory{
Id: v.Id,
Name: v.Name,
Code: v.Code,
}
p = append(p, category)
}
m.PartnerCategoryInfos = p
return m, nil
}
func NewPartnerInfoRepository(transactionContext *transaction.TransactionContext) (*PartnerInfoRepository, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
}
return &PartnerInfoRepository{transactionContext: transactionContext}, nil
}
... ...
... ... @@ -35,14 +35,14 @@ func (c *PartnerInfoController) Prepare() {
func (c *PartnerInfoController) CreatePartnerInfo() {
//用与适配前端定义的数据结构
type Parameter struct {
PartnerName string `json:"partnerName"`
PartnerType []int64 `json:"partnerType"`
Area string `json:"area"`
Account string `json:"account"`
State int `json:"state"`
CooperationTime string `json:"cooperationTime"`
SalesmanName string `json:"salesmanName"`
Phone string `json:"phone"`
PartnerName string `json:"partnerName"`
PartnerType []*domain.PartnerCategory `json:"partnerType"`
Area string `json:"area"`
Account string `json:"account"`
State int `json:"state"`
CooperationTime string `json:"cooperationTime"`
SalesmanName string `json:"salesmanName"`
Phone string `json:"phone"`
}
var (
param Parameter
... ... @@ -103,13 +103,13 @@ func (c *PartnerInfoController) CreatePartnerInfo() {
func (c *PartnerInfoController) UpdatePartnerInfo() {
//用与适配前端定义的数据结构
type Parameter struct {
ID int64 `json:"id"`
PartnerType []int64 `json:"partnerType"`
Area string `json:"area"`
State int `json:"state"`
CooperationTime string `json:"cooperationTime"`
SalesmanName string `json:"salesmanName"`
Phone string `json:"phone"`
ID int64 `json:"id"`
PartnerType []*domain.PartnerCategory `json:"partnerType"`
Area string `json:"area"`
State int `json:"state"`
CooperationTime string `json:"cooperationTime"`
SalesmanName string `json:"salesmanName"`
Phone string `json:"phone"`
}
var (
param Parameter
... ... @@ -195,11 +195,12 @@ func (c *PartnerInfoController) GetPartnerInfo() {
rspResult["salesmanName"] = partnerInfo.Salesman[0].Name
rspResult["phone"] = partnerInfo.Salesman[0].Telephone
}
partnerTypes := []map[string]interface{}{}
var partnerTypes []map[string]interface{}
for _, v := range partnerInfo.PartnerCategoryInfos {
m := map[string]interface{}{
"id": v.Id,
"name": v.Name,
"code": v.Code,
}
partnerTypes = append(partnerTypes, m)
}
... ... @@ -208,6 +209,17 @@ func (c *PartnerInfoController) GetPartnerInfo() {
return
}
/**
* @Author SteveChan
* @Description //TODO 移除合伙人
* @Date 15:31 2020/12/29
* @Param
* @return
**/
func (c *PartnerInfoController) RemovePartnerInfo() {
}
//PartnerInfoSetState 合伙人批量禁用.启用
func (c *PartnerInfoController) PartnerInfoSetState() {
//用与适配前端定义的数据结构
... ... @@ -224,19 +236,19 @@ func (c *PartnerInfoController) PartnerInfoSetState() {
c.ResponseError(errors.New("json数据解析失败"))
return
}
comanyId := c.GetUserCompany()
companyId := c.GetUserCompany()
var cmd partnerInfoCmd.StatusPartnerInfoCommand
switch param.Status {
case 0:
cmd = partnerInfoCmd.StatusPartnerInfoCommand{
Ids: param.Id,
CompanyId: comanyId,
CompanyId: companyId,
Status: domain.PARTNER_STATUS_NO,
}
case 1:
cmd = partnerInfoCmd.StatusPartnerInfoCommand{
Ids: param.Id,
CompanyId: comanyId,
CompanyId: companyId,
Status: domain.PARTNER_STATUS_YES,
}
default:
... ... @@ -256,7 +268,7 @@ func (c *PartnerInfoController) PartnerInfoSetState() {
//ListPartnerInfo 合伙人列表
func (c *PartnerInfoController) ListPartnerInfo() {
type Parameter struct {
Partnertype int `json:"partnerType"`
PartnerType int `json:"partnerType"`
Area string `json:"area"`
PartnerName string `json:"partnerName"`
PageSize int `json:"pageSize"`
... ... @@ -280,7 +292,7 @@ func (c *PartnerInfoController) ListPartnerInfo() {
}
companyId := c.GetUserCompany()
query := partnerQuery.ListPartnerInfoQuery{
Partnertype: param.Partnertype,
PartnerType: param.PartnerType,
PartnerName: param.PartnerName,
RegionInfo: param.Area,
Limit: param.PageSize,
... ... @@ -294,7 +306,7 @@ func (c *PartnerInfoController) ListPartnerInfo() {
c.ResponseError(err)
return
}
resp := []map[string]interface{}{}
var resp []map[string]interface{}
indexBegin := query.Offset
for i := range partners {
m := map[string]interface{}{
... ...
... ... @@ -32,7 +32,7 @@ func (c *UserController) ListUser() {
//用与适配前端定义的数据结构
type Paramter struct {
SearchText string `json:"searchText"`
PageSize int `json::"pageSize"`
PageSize int `json:"pageSize"`
PageNumber int `json:"pageNumber"`
}
var (
... ...
... ... @@ -23,6 +23,7 @@ func init() {
beego.NSRouter("/edit", &controllers.PartnerInfoController{}, "POST:UpdatePartnerInfo"),
beego.NSRouter("/detail", &controllers.PartnerInfoController{}, "POST:GetPartnerInfo"),
beego.NSRouter("/batchDisabled", &controllers.PartnerInfoController{}, "POST:PartnerInfoSetState"),
beego.NSRouter("/:id", &controllers.PartnerInfoController{}, "DELETE:RemovePartnerInfo"),
),
beego.NSNamespace("/dividends",
beego.NSRouter("/list", &controllers.OrderDividendController{}, "POST:PageListOrderDividend"),
... ...
... ... @@ -51,6 +51,7 @@ func (c *MessageConsumer) ConsumeClaim(groupSession sarama.ConsumerGroupSession,
}
if err = topicHandle(message); err != nil {
logs.Error("Message claimed: kafka消息处理错误 topic =", message.Topic, message.Offset, err)
}
groupSession.MarkMessage(message, "")
}
... ...
... ... @@ -30,6 +30,9 @@ func init() {
if runEnv == "partnermg_prd" {
initHandleRoutersProd()
}
if runEnv == "partnermg_dev" {
initHandleRoutersDev()
}
}
func initHandleRoutersTest() {
... ... @@ -39,3 +42,7 @@ func initHandleRoutersTest() {
func initHandleRoutersProd() {
TopicHandleRouters["xiangmi_project"] = handles.DataFromXiangMi
}
func initHandleRoutersDev() {
TopicHandleRouters["xiangmi_project_dev"] = handles.DataFromXiangMi
}
\ No newline at end of file
... ...
package geetest
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
type GeetestLib struct {
CaptchaID string
PrivateKey string
Client *http.Client
}
type FailbackRegisterRespnse struct {
Success int `json:"success"`
GT string `json:"gt"`
Challenge string `json:"challenge"`
NewCaptcha int `json:"new_captcha"`
}
const (
geetestHost = "http://api.geetest.com"
registerURL = geetestHost + "/register.php"
validateURL = geetestHost + "/validate.php"
)
func MD5Encode(input string) string {
md5Instant := md5.New()
md5Instant.Write([]byte(input))
return hex.EncodeToString(md5Instant.Sum(nil))
}
// 初始化 GeetestLib
func NewGeetestLib(capthcaID string, privateKey string, timeOut time.Duration) (geetest GeetestLib){
client := &http.Client{Timeout: timeOut}
geetest = GeetestLib{capthcaID, privateKey, client}
return
}
func (g *GeetestLib) getFailBackRegisterResponse(success int, challenge string) []byte {
if challenge == "" {
challenge = hex.EncodeToString(md5.New().Sum(nil))
}
response := FailbackRegisterRespnse{
success,
g.CaptchaID,
challenge,
1,
}
res, _ := json.Marshal(response)
return res
}
func (g *GeetestLib) do(req *http.Request) (body []byte, err error) {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
var resp *http.Response
if resp, err = g.Client.Do(req); err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode >= http.StatusInternalServerError {
err = errors.New("http status code 5xx")
return
}
if body, err = ioutil.ReadAll(resp.Body); err != nil {
return
}
return
}
func (g *GeetestLib) PreProcess(userID string, userIP string) (int8, []byte) {
params := url.Values{}
params.Add("gt", g.CaptchaID)
params.Add("new_captcha", "1")
if userID != "" {
params.Add("user_id", userID)
}
if userIP != "" {
params.Add("ip_adress", userIP)
}
req, _ := http.NewRequest("GET", registerURL+"?"+params.Encode(), nil)
body, err := g.do(req)
if err != nil {
return 0, g.getFailBackRegisterResponse(0, "")
}
challenge := string(body)
if len(challenge) != 32 {
return 0, g.getFailBackRegisterResponse(0, "")
} else {
challenge = MD5Encode(challenge + g.PrivateKey)
return 1, g.getFailBackRegisterResponse(1, challenge)
}
}
func (g *GeetestLib) checkParas(challenge string, validate string, seccode string) bool {
if challenge == "" || validate == "" || seccode == "" {
return false
}
return true
}
func (g *GeetestLib) checkSuccessRes(challenge string, validate string) bool {
return MD5Encode(g.PrivateKey+"geetest"+challenge) == validate
}
func (g *GeetestLib) checkFailbackRes(challenge string, validate string) bool {
return MD5Encode(challenge) == validate
}
func (g *GeetestLib) SuccessValidate(challenge string, validate string, seccode string, userID string, userIP string) bool {
if !g.checkParas(challenge, validate, seccode) {
return false
}
if !g.checkSuccessRes(challenge, validate) {
return false
}
params := url.Values{}
params.Add("seccode", seccode)
params.Add("challenge", challenge)
params.Add("captchaid", g.CaptchaID)
params.Add("sdk", "golang_v1.0.0")
if userID != "" {
params.Add("user_id", userID)
}
if userIP != "" {
params.Add("ip_adress", userIP)
}
req, _ := http.NewRequest("POST", validateURL, strings.NewReader(params.Encode()))
body, err := g.do(req)
if err != nil {
return false
}
res := string(body)
return res == MD5Encode(seccode)
}
func (g *GeetestLib) FailbackValidate(challenge string, validate string, seccode string) bool {
if !g.checkParas(challenge, validate, seccode) {
return false
}
if !g.checkFailbackRes(challenge, validate) {
return false
}
return true
}
language: go
go:
- 1.2
- stable
language: go
go:
- 1.2
- stable
- tip
\ No newline at end of file
... ...
A reader for Microsoft's Compound File Binary File Format.
Example usage:
file, _ := os.Open("test/test.doc")
defer file.Close()
doc, err := mscfb.New(file)
if err != nil {
log.Fatal(err)
}
for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
buf := make([]byte, 512)
i, _ := doc.Read(buf)
if i > 0 {
fmt.Println(buf[:i])
}
fmt.Println(entry.Name)
}
The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by early MS software such as MS Office. See [http://msdn.microsoft.com/en-us/library/dd942138.aspx](http://msdn.microsoft.com/en-us/library/dd942138.aspx) for more details
Install with `go get github.com/richardlehane/mscfb`
A reader for Microsoft's Compound File Binary File Format.
Example usage:
file, _ := os.Open("test/test.doc")
defer file.Close()
doc, err := mscfb.New(file)
if err != nil {
log.Fatal(err)
}
for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
buf := make([]byte, 512)
i, _ := doc.Read(buf)
if i > 0 {
fmt.Println(buf[:i])
}
fmt.Println(entry.Name)
}
The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by early MS software such as MS Office. See [http://msdn.microsoft.com/en-us/library/dd942138.aspx](http://msdn.microsoft.com/en-us/library/dd942138.aspx) for more details
Install with `go get github.com/richardlehane/mscfb`
[![Build Status](https://travis-ci.org/richardlehane/mscfb.png?branch=master)](https://travis-ci.org/richardlehane/mscfb)
\ No newline at end of file
... ...
// +build gofuzz
// fuzzing with https://github.com/dvyukov/go-fuzz
package mscfb
import (
"bytes"
"io"
)
func Fuzz(data []byte) int {
doc, err := New(bytes.NewReader(data))
if err != nil {
if doc != nil {
panic("doc != nil on error " + err.Error())
}
return 0
}
buf := &bytes.Buffer{}
for entry, err := doc.Next(); ; entry, err = doc.Next() {
if err != nil {
if err == io.EOF {
return 1
}
if entry != nil {
panic("entry != nil on error " + err.Error())
}
}
buf.Reset()
buf.ReadFrom(entry)
}
return 1
}
// +build gofuzz
// fuzzing with https://github.com/dvyukov/go-fuzz
package mscfb
import (
"bytes"
"io"
)
func Fuzz(data []byte) int {
doc, err := New(bytes.NewReader(data))
if err != nil {
if doc != nil {
panic("doc != nil on error " + err.Error())
}
return 0
}
buf := &bytes.Buffer{}
for entry, err := doc.Next(); ; entry, err = doc.Next() {
if err != nil {
if err == io.EOF {
return 1
}
if entry != nil {
panic("entry != nil on error " + err.Error())
}
}
buf.Reset()
buf.ReadFrom(entry)
}
return 1
}
... ...
// Copyright 2013 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package mscfb implements a reader for Microsoft's Compound File Binary File Format (http://msdn.microsoft.com/en-us/library/dd942138.aspx).
//
// The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by many
// early MS software such as MS Office.
//
// Example:
// file, _ := os.Open("test/test.doc")
// defer file.Close()
// doc, err := mscfb.New(file)
// if err != nil {
// log.Fatal(err)
// }
// for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
// buf := make([]byte, 512)
// i, _ := entry.Read(buf)
// if i > 0 {
// fmt.Println(buf[:i])
// }
// fmt.Println(entry.Name)
// }
package mscfb
import (
"encoding/binary"
"io"
"strconv"
"time"
)
func fileOffset(ss, sn uint32) int64 {
return int64((sn + 1) * ss)
}
const (
signature uint64 = 0xE11AB1A1E011CFD0
miniStreamSectorSize uint32 = 64
miniStreamCutoffSize int64 = 4096
dirEntrySize uint32 = 128 //128 bytes
)
const (
maxRegSect uint32 = 0xFFFFFFFA // Maximum regular sector number
difatSect uint32 = 0xFFFFFFFC //Specifies a DIFAT sector in the FAT
fatSect uint32 = 0xFFFFFFFD // Specifies a FAT sector in the FAT
endOfChain uint32 = 0xFFFFFFFE // End of linked chain of sectors
freeSect uint32 = 0xFFFFFFFF // Speficies unallocated sector in the FAT, Mini FAT or DIFAT
maxRegStreamID uint32 = 0xFFFFFFFA // maximum regular stream ID
noStream uint32 = 0xFFFFFFFF // empty pointer
)
const lenHeader int = 8 + 16 + 10 + 6 + 12 + 8 + 16 + 109*4
type headerFields struct {
signature uint64
_ [16]byte //CLSID - ignore, must be null
minorVersion uint16 //Version number for non-breaking changes. This field SHOULD be set to 0x003E if the major version field is either 0x0003 or 0x0004.
majorVersion uint16 //Version number for breaking changes. This field MUST be set to either 0x0003 (version 3) or 0x0004 (version 4).
_ [2]byte //byte order - ignore, must be little endian
sectorSize uint16 //This field MUST be set to 0x0009, or 0x000c, depending on the Major Version field. This field specifies the sector size of the compound file as a power of 2. If Major Version is 3, then the Sector Shift MUST be 0x0009, specifying a sector size of 512 bytes. If Major Version is 4, then the Sector Shift MUST be 0x000C, specifying a sector size of 4096 bytes.
_ [2]byte // ministream sector size - ignore, must be 64 bytes
_ [6]byte // reserved - ignore, not used
numDirectorySectors uint32 //This integer field contains the count of the number of directory sectors in the compound file. If Major Version is 3, then the Number of Directory Sectors MUST be zero. This field is not supported for version 3 compound files.
numFatSectors uint32 //This integer field contains the count of the number of FAT sectors in the compound file.
directorySectorLoc uint32 //This integer field contains the starting sector number for the directory stream.
_ [4]byte // transaction - ignore, not used
_ [4]byte // mini stream size cutooff - ignore, must be 4096 bytes
miniFatSectorLoc uint32 //This integer field contains the starting sector number for the mini FAT.
numMiniFatSectors uint32 //This integer field contains the count of the number of mini FAT sectors in the compound file.
difatSectorLoc uint32 //This integer field contains the starting sector number for the DIFAT.
numDifatSectors uint32 //This integer field contains the count of the number of DIFAT sectors in the compound file.
initialDifats [109]uint32 //The first 109 difat sectors are included in the header
}
func makeHeader(b []byte) *headerFields {
h := &headerFields{}
h.signature = binary.LittleEndian.Uint64(b[:8])
h.minorVersion = binary.LittleEndian.Uint16(b[24:26])
h.majorVersion = binary.LittleEndian.Uint16(b[26:28])
h.sectorSize = binary.LittleEndian.Uint16(b[30:32])
h.numDirectorySectors = binary.LittleEndian.Uint32(b[40:44])
h.numFatSectors = binary.LittleEndian.Uint32(b[44:48])
h.directorySectorLoc = binary.LittleEndian.Uint32(b[48:52])
h.miniFatSectorLoc = binary.LittleEndian.Uint32(b[60:64])
h.numMiniFatSectors = binary.LittleEndian.Uint32(b[64:68])
h.difatSectorLoc = binary.LittleEndian.Uint32(b[68:72])
h.numDifatSectors = binary.LittleEndian.Uint32(b[72:76])
var idx int
for i := 76; i < 512; i = i + 4 {
h.initialDifats[idx] = binary.LittleEndian.Uint32(b[i : i+4])
idx++
}
return h
}
type header struct {
*headerFields
difats []uint32
miniFatLocs []uint32
miniStreamLocs []uint32 // chain of sectors containing the ministream
}
func (r *Reader) setHeader() error {
buf, err := r.readAt(0, lenHeader)
if err != nil {
return err
}
r.header = &header{headerFields: makeHeader(buf)}
// sanity check - check signature
if r.header.signature != signature {
return Error{ErrFormat, "bad signature", int64(r.header.signature)}
}
// check for legal sector size
if r.header.sectorSize == 0x0009 || r.header.sectorSize == 0x000c {
r.sectorSize = uint32(1 << r.header.sectorSize)
} else {
return Error{ErrFormat, "illegal sector size", int64(r.header.sectorSize)}
}
// check for DIFAT overflow
if r.header.numDifatSectors > 0 {
sz := (r.sectorSize / 4) - 1
if int(r.header.numDifatSectors*sz+109) < 0 {
return Error{ErrFormat, "DIFAT int overflow", int64(r.header.numDifatSectors)}
}
if r.header.numDifatSectors*sz+109 > r.header.numFatSectors+sz {
return Error{ErrFormat, "num DIFATs exceeds FAT sectors", int64(r.header.numDifatSectors)}
}
}
// check for mini FAT overflow
if r.header.numMiniFatSectors > 0 {
if int(r.sectorSize/4*r.header.numMiniFatSectors) < 0 {
return Error{ErrFormat, "mini FAT int overflow", int64(r.header.numMiniFatSectors)}
}
if r.header.numMiniFatSectors > r.header.numFatSectors*(r.sectorSize/miniStreamSectorSize) {
return Error{ErrFormat, "num mini FATs exceeds FAT sectors", int64(r.header.numFatSectors)}
}
}
return nil
}
func (r *Reader) setDifats() error {
r.header.difats = r.header.initialDifats[:]
// return early if no extra DIFAT sectors
if r.header.numDifatSectors == 0 {
return nil
}
sz := (r.sectorSize / 4) - 1
n := make([]uint32, 109, r.header.numDifatSectors*sz+109)
copy(n, r.header.difats)
r.header.difats = n
off := r.header.difatSectorLoc
for i := 0; i < int(r.header.numDifatSectors); i++ {
buf, err := r.readAt(fileOffset(r.sectorSize, off), int(r.sectorSize))
if err != nil {
return Error{ErrFormat, "error setting DIFAT(" + err.Error() + ")", int64(off)}
}
for j := 0; j < int(sz); j++ {
r.header.difats = append(r.header.difats, binary.LittleEndian.Uint32(buf[j*4:j*4+4]))
}
off = binary.LittleEndian.Uint32(buf[len(buf)-4:])
}
return nil
}
// set the ministream FAT and sector slices in the header
func (r *Reader) setMiniStream() error {
// do nothing if there is no ministream
if r.direntries[0].startingSectorLoc == endOfChain || r.header.miniFatSectorLoc == endOfChain || r.header.numMiniFatSectors == 0 {
return nil
}
// build a slice of minifat sectors (akin to the DIFAT slice)
c := int(r.header.numMiniFatSectors)
r.header.miniFatLocs = make([]uint32, c)
r.header.miniFatLocs[0] = r.header.miniFatSectorLoc
for i := 1; i < c; i++ {
loc, err := r.findNext(r.header.miniFatLocs[i-1], false)
if err != nil {
return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(r.header.miniFatLocs[i-1])}
}
r.header.miniFatLocs[i] = loc
}
// build a slice of ministream sectors
c = int(r.sectorSize / 4 * r.header.numMiniFatSectors)
r.header.miniStreamLocs = make([]uint32, 0, c)
sn := r.direntries[0].startingSectorLoc
var err error
for sn != endOfChain {
r.header.miniStreamLocs = append(r.header.miniStreamLocs, sn)
sn, err = r.findNext(sn, false)
if err != nil {
return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(sn)}
}
}
return nil
}
func (r *Reader) readAt(offset int64, length int) ([]byte, error) {
if r.slicer {
b, err := r.ra.(slicer).Slice(offset, length)
if err != nil {
return nil, Error{ErrRead, "slicer read error (" + err.Error() + ")", offset}
}
return b, nil
}
if length > len(r.buf) {
return nil, Error{ErrRead, "read length greater than read buffer", int64(length)}
}
if _, err := r.ra.ReadAt(r.buf[:length], offset); err != nil {
return nil, Error{ErrRead, err.Error(), offset}
}
return r.buf[:length], nil
}
func (r *Reader) getOffset(sn uint32, mini bool) (int64, error) {
if mini {
num := r.sectorSize / 64
sec := int(sn / num)
if sec >= len(r.header.miniStreamLocs) {
return 0, Error{ErrRead, "minisector number is outside minisector range", int64(sec)}
}
dif := sn % num
return int64((r.header.miniStreamLocs[sec]+1)*r.sectorSize + dif*64), nil
}
return fileOffset(r.sectorSize, sn), nil
}
// check the FAT sector for the next sector in a chain
func (r *Reader) findNext(sn uint32, mini bool) (uint32, error) {
entries := r.sectorSize / 4
index := int(sn / entries) // find position in DIFAT or minifat array
var sect uint32
if mini {
if index < 0 || index >= len(r.header.miniFatLocs) {
return 0, Error{ErrRead, "minisector index is outside miniFAT range", int64(index)}
}
sect = r.header.miniFatLocs[index]
} else {
if index < 0 || index >= len(r.header.difats) {
return 0, Error{ErrRead, "FAT index is outside DIFAT range", int64(index)}
}
sect = r.header.difats[index]
}
fatIndex := sn % entries // find position within FAT or MiniFAT sector
offset := fileOffset(r.sectorSize, sect) + int64(fatIndex*4)
buf, err := r.readAt(offset, 4)
if err != nil {
return 0, Error{ErrRead, "bad read finding next sector (" + err.Error() + ")", offset}
}
return binary.LittleEndian.Uint32(buf), nil
}
// Reader provides sequential access to the contents of a MS compound file (MSCFB)
type Reader struct {
slicer bool
sectorSize uint32
buf []byte
header *header
File []*File // File is an ordered slice of final directory entries.
direntries []*File // unordered raw directory entries
entry int
ra io.ReaderAt
wa io.WriterAt
}
// New returns a MSCFB reader
func New(ra io.ReaderAt) (*Reader, error) {
r := &Reader{ra: ra}
if _, ok := ra.(slicer); ok {
r.slicer = true
} else {
r.buf = make([]byte, lenHeader)
}
if err := r.setHeader(); err != nil {
return nil, err
}
// resize the buffer to 4096 if sector size isn't 512
if !r.slicer && int(r.sectorSize) > len(r.buf) {
r.buf = make([]byte, r.sectorSize)
}
if err := r.setDifats(); err != nil {
return nil, err
}
if err := r.setDirEntries(); err != nil {
return nil, err
}
if err := r.setMiniStream(); err != nil {
return nil, err
}
if err := r.traverse(); err != nil {
return nil, err
}
return r, nil
}
// ID returns the CLSID (class ID) field from the root directory entry
func (r *Reader) ID() string {
return r.File[0].ID()
}
// Created returns the created field from the root directory entry
func (r *Reader) Created() time.Time {
return r.File[0].Created()
}
// Modified returns the last modified field from the root directory entry
func (r *Reader) Modified() time.Time {
return r.File[0].Modified()
}
// Next iterates to the next directory entry.
// This isn't necessarily an adjacent *File within the File slice, but is based on the Left Sibling, Right Sibling and Child information in directory entries.
func (r *Reader) Next() (*File, error) {
r.entry++
if r.entry >= len(r.File) {
return nil, io.EOF
}
return r.File[r.entry], nil
}
// Read the current directory entry
func (r *Reader) Read(b []byte) (n int, err error) {
if r.entry >= len(r.File) {
return 0, io.EOF
}
return r.File[r.entry].Read(b)
}
// Debug provides granular information from an mscfb file to assist with debugging
func (r *Reader) Debug() map[string][]uint32 {
ret := map[string][]uint32{
"sector size": []uint32{r.sectorSize},
"mini fat locs": r.header.miniFatLocs,
"mini stream locs": r.header.miniStreamLocs,
"directory sector": []uint32{r.header.directorySectorLoc},
"mini stream start/size": []uint32{r.File[0].startingSectorLoc, binary.LittleEndian.Uint32(r.File[0].streamSize[:])},
}
for f, err := r.Next(); err == nil; f, err = r.Next() {
ret[f.Name+" start/size"] = []uint32{f.startingSectorLoc, binary.LittleEndian.Uint32(f.streamSize[:])}
}
return ret
}
const (
// ErrFormat reports issues with the MSCFB's header structures
ErrFormat = iota
// ErrRead reports issues attempting to read MSCFB streams
ErrRead
// ErrSeek reports seek issues
ErrSeek
// ErrWrite reports write issues
ErrWrite
// ErrTraverse reports issues attempting to traverse the child-parent-sibling relations
// between MSCFB storage objects
ErrTraverse
)
type Error struct {
typ int
msg string
val int64
}
func (e Error) Error() string {
return "mscfb: " + e.msg + "; " + strconv.FormatInt(e.val, 10)
}
// Typ gives the type of MSCFB error
func (e Error) Typ() int {
return e.typ
}
// Slicer interface avoids a copy by obtaining a byte slice directly from the underlying reader
type slicer interface {
Slice(offset int64, length int) ([]byte, error)
}
// Copyright 2013 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package mscfb implements a reader for Microsoft's Compound File Binary File Format (http://msdn.microsoft.com/en-us/library/dd942138.aspx).
//
// The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by many
// early MS software such as MS Office.
//
// Example:
// file, _ := os.Open("test/test.doc")
// defer file.Close()
// doc, err := mscfb.New(file)
// if err != nil {
// log.Fatal(err)
// }
// for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
// buf := make([]byte, 512)
// i, _ := entry.Read(buf)
// if i > 0 {
// fmt.Println(buf[:i])
// }
// fmt.Println(entry.Name)
// }
package mscfb
import (
"encoding/binary"
"io"
"strconv"
"time"
)
func fileOffset(ss, sn uint32) int64 {
return int64((sn + 1) * ss)
}
const (
signature uint64 = 0xE11AB1A1E011CFD0
miniStreamSectorSize uint32 = 64
miniStreamCutoffSize int64 = 4096
dirEntrySize uint32 = 128 //128 bytes
)
const (
maxRegSect uint32 = 0xFFFFFFFA // Maximum regular sector number
difatSect uint32 = 0xFFFFFFFC //Specifies a DIFAT sector in the FAT
fatSect uint32 = 0xFFFFFFFD // Specifies a FAT sector in the FAT
endOfChain uint32 = 0xFFFFFFFE // End of linked chain of sectors
freeSect uint32 = 0xFFFFFFFF // Speficies unallocated sector in the FAT, Mini FAT or DIFAT
maxRegStreamID uint32 = 0xFFFFFFFA // maximum regular stream ID
noStream uint32 = 0xFFFFFFFF // empty pointer
)
const lenHeader int = 8 + 16 + 10 + 6 + 12 + 8 + 16 + 109*4
type headerFields struct {
signature uint64
_ [16]byte //CLSID - ignore, must be null
minorVersion uint16 //Version number for non-breaking changes. This field SHOULD be set to 0x003E if the major version field is either 0x0003 or 0x0004.
majorVersion uint16 //Version number for breaking changes. This field MUST be set to either 0x0003 (version 3) or 0x0004 (version 4).
_ [2]byte //byte order - ignore, must be little endian
sectorSize uint16 //This field MUST be set to 0x0009, or 0x000c, depending on the Major Version field. This field specifies the sector size of the compound file as a power of 2. If Major Version is 3, then the Sector Shift MUST be 0x0009, specifying a sector size of 512 bytes. If Major Version is 4, then the Sector Shift MUST be 0x000C, specifying a sector size of 4096 bytes.
_ [2]byte // ministream sector size - ignore, must be 64 bytes
_ [6]byte // reserved - ignore, not used
numDirectorySectors uint32 //This integer field contains the count of the number of directory sectors in the compound file. If Major Version is 3, then the Number of Directory Sectors MUST be zero. This field is not supported for version 3 compound files.
numFatSectors uint32 //This integer field contains the count of the number of FAT sectors in the compound file.
directorySectorLoc uint32 //This integer field contains the starting sector number for the directory stream.
_ [4]byte // transaction - ignore, not used
_ [4]byte // mini stream size cutooff - ignore, must be 4096 bytes
miniFatSectorLoc uint32 //This integer field contains the starting sector number for the mini FAT.
numMiniFatSectors uint32 //This integer field contains the count of the number of mini FAT sectors in the compound file.
difatSectorLoc uint32 //This integer field contains the starting sector number for the DIFAT.
numDifatSectors uint32 //This integer field contains the count of the number of DIFAT sectors in the compound file.
initialDifats [109]uint32 //The first 109 difat sectors are included in the header
}
func makeHeader(b []byte) *headerFields {
h := &headerFields{}
h.signature = binary.LittleEndian.Uint64(b[:8])
h.minorVersion = binary.LittleEndian.Uint16(b[24:26])
h.majorVersion = binary.LittleEndian.Uint16(b[26:28])
h.sectorSize = binary.LittleEndian.Uint16(b[30:32])
h.numDirectorySectors = binary.LittleEndian.Uint32(b[40:44])
h.numFatSectors = binary.LittleEndian.Uint32(b[44:48])
h.directorySectorLoc = binary.LittleEndian.Uint32(b[48:52])
h.miniFatSectorLoc = binary.LittleEndian.Uint32(b[60:64])
h.numMiniFatSectors = binary.LittleEndian.Uint32(b[64:68])
h.difatSectorLoc = binary.LittleEndian.Uint32(b[68:72])
h.numDifatSectors = binary.LittleEndian.Uint32(b[72:76])
var idx int
for i := 76; i < 512; i = i + 4 {
h.initialDifats[idx] = binary.LittleEndian.Uint32(b[i : i+4])
idx++
}
return h
}
type header struct {
*headerFields
difats []uint32
miniFatLocs []uint32
miniStreamLocs []uint32 // chain of sectors containing the ministream
}
func (r *Reader) setHeader() error {
buf, err := r.readAt(0, lenHeader)
if err != nil {
return err
}
r.header = &header{headerFields: makeHeader(buf)}
// sanity check - check signature
if r.header.signature != signature {
return Error{ErrFormat, "bad signature", int64(r.header.signature)}
}
// check for legal sector size
if r.header.sectorSize == 0x0009 || r.header.sectorSize == 0x000c {
r.sectorSize = uint32(1 << r.header.sectorSize)
} else {
return Error{ErrFormat, "illegal sector size", int64(r.header.sectorSize)}
}
// check for DIFAT overflow
if r.header.numDifatSectors > 0 {
sz := (r.sectorSize / 4) - 1
if int(r.header.numDifatSectors*sz+109) < 0 {
return Error{ErrFormat, "DIFAT int overflow", int64(r.header.numDifatSectors)}
}
if r.header.numDifatSectors*sz+109 > r.header.numFatSectors+sz {
return Error{ErrFormat, "num DIFATs exceeds FAT sectors", int64(r.header.numDifatSectors)}
}
}
// check for mini FAT overflow
if r.header.numMiniFatSectors > 0 {
if int(r.sectorSize/4*r.header.numMiniFatSectors) < 0 {
return Error{ErrFormat, "mini FAT int overflow", int64(r.header.numMiniFatSectors)}
}
if r.header.numMiniFatSectors > r.header.numFatSectors*(r.sectorSize/miniStreamSectorSize) {
return Error{ErrFormat, "num mini FATs exceeds FAT sectors", int64(r.header.numFatSectors)}
}
}
return nil
}
func (r *Reader) setDifats() error {
r.header.difats = r.header.initialDifats[:]
// return early if no extra DIFAT sectors
if r.header.numDifatSectors == 0 {
return nil
}
sz := (r.sectorSize / 4) - 1
n := make([]uint32, 109, r.header.numDifatSectors*sz+109)
copy(n, r.header.difats)
r.header.difats = n
off := r.header.difatSectorLoc
for i := 0; i < int(r.header.numDifatSectors); i++ {
buf, err := r.readAt(fileOffset(r.sectorSize, off), int(r.sectorSize))
if err != nil {
return Error{ErrFormat, "error setting DIFAT(" + err.Error() + ")", int64(off)}
}
for j := 0; j < int(sz); j++ {
r.header.difats = append(r.header.difats, binary.LittleEndian.Uint32(buf[j*4:j*4+4]))
}
off = binary.LittleEndian.Uint32(buf[len(buf)-4:])
}
return nil
}
// set the ministream FAT and sector slices in the header
func (r *Reader) setMiniStream() error {
// do nothing if there is no ministream
if r.direntries[0].startingSectorLoc == endOfChain || r.header.miniFatSectorLoc == endOfChain || r.header.numMiniFatSectors == 0 {
return nil
}
// build a slice of minifat sectors (akin to the DIFAT slice)
c := int(r.header.numMiniFatSectors)
r.header.miniFatLocs = make([]uint32, c)
r.header.miniFatLocs[0] = r.header.miniFatSectorLoc
for i := 1; i < c; i++ {
loc, err := r.findNext(r.header.miniFatLocs[i-1], false)
if err != nil {
return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(r.header.miniFatLocs[i-1])}
}
r.header.miniFatLocs[i] = loc
}
// build a slice of ministream sectors
c = int(r.sectorSize / 4 * r.header.numMiniFatSectors)
r.header.miniStreamLocs = make([]uint32, 0, c)
sn := r.direntries[0].startingSectorLoc
var err error
for sn != endOfChain {
r.header.miniStreamLocs = append(r.header.miniStreamLocs, sn)
sn, err = r.findNext(sn, false)
if err != nil {
return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(sn)}
}
}
return nil
}
func (r *Reader) readAt(offset int64, length int) ([]byte, error) {
if r.slicer {
b, err := r.ra.(slicer).Slice(offset, length)
if err != nil {
return nil, Error{ErrRead, "slicer read error (" + err.Error() + ")", offset}
}
return b, nil
}
if length > len(r.buf) {
return nil, Error{ErrRead, "read length greater than read buffer", int64(length)}
}
if _, err := r.ra.ReadAt(r.buf[:length], offset); err != nil {
return nil, Error{ErrRead, err.Error(), offset}
}
return r.buf[:length], nil
}
func (r *Reader) getOffset(sn uint32, mini bool) (int64, error) {
if mini {
num := r.sectorSize / 64
sec := int(sn / num)
if sec >= len(r.header.miniStreamLocs) {
return 0, Error{ErrRead, "minisector number is outside minisector range", int64(sec)}
}
dif := sn % num
return int64((r.header.miniStreamLocs[sec]+1)*r.sectorSize + dif*64), nil
}
return fileOffset(r.sectorSize, sn), nil
}
// check the FAT sector for the next sector in a chain
func (r *Reader) findNext(sn uint32, mini bool) (uint32, error) {
entries := r.sectorSize / 4
index := int(sn / entries) // find position in DIFAT or minifat array
var sect uint32
if mini {
if index < 0 || index >= len(r.header.miniFatLocs) {
return 0, Error{ErrRead, "minisector index is outside miniFAT range", int64(index)}
}
sect = r.header.miniFatLocs[index]
} else {
if index < 0 || index >= len(r.header.difats) {
return 0, Error{ErrRead, "FAT index is outside DIFAT range", int64(index)}
}
sect = r.header.difats[index]
}
fatIndex := sn % entries // find position within FAT or MiniFAT sector
offset := fileOffset(r.sectorSize, sect) + int64(fatIndex*4)
buf, err := r.readAt(offset, 4)
if err != nil {
return 0, Error{ErrRead, "bad read finding next sector (" + err.Error() + ")", offset}
}
return binary.LittleEndian.Uint32(buf), nil
}
// Reader provides sequential access to the contents of a MS compound file (MSCFB)
type Reader struct {
slicer bool
sectorSize uint32
buf []byte
header *header
File []*File // File is an ordered slice of final directory entries.
direntries []*File // unordered raw directory entries
entry int
ra io.ReaderAt
wa io.WriterAt
}
// New returns a MSCFB reader
func New(ra io.ReaderAt) (*Reader, error) {
r := &Reader{ra: ra}
if _, ok := ra.(slicer); ok {
r.slicer = true
} else {
r.buf = make([]byte, lenHeader)
}
if err := r.setHeader(); err != nil {
return nil, err
}
// resize the buffer to 4096 if sector size isn't 512
if !r.slicer && int(r.sectorSize) > len(r.buf) {
r.buf = make([]byte, r.sectorSize)
}
if err := r.setDifats(); err != nil {
return nil, err
}
if err := r.setDirEntries(); err != nil {
return nil, err
}
if err := r.setMiniStream(); err != nil {
return nil, err
}
if err := r.traverse(); err != nil {
return nil, err
}
return r, nil
}
// ID returns the CLSID (class ID) field from the root directory entry
func (r *Reader) ID() string {
return r.File[0].ID()
}
// Created returns the created field from the root directory entry
func (r *Reader) Created() time.Time {
return r.File[0].Created()
}
// Modified returns the last modified field from the root directory entry
func (r *Reader) Modified() time.Time {
return r.File[0].Modified()
}
// Next iterates to the next directory entry.
// This isn't necessarily an adjacent *File within the File slice, but is based on the Left Sibling, Right Sibling and Child information in directory entries.
func (r *Reader) Next() (*File, error) {
r.entry++
if r.entry >= len(r.File) {
return nil, io.EOF
}
return r.File[r.entry], nil
}
// Read the current directory entry
func (r *Reader) Read(b []byte) (n int, err error) {
if r.entry >= len(r.File) {
return 0, io.EOF
}
return r.File[r.entry].Read(b)
}
// Debug provides granular information from an mscfb file to assist with debugging
func (r *Reader) Debug() map[string][]uint32 {
ret := map[string][]uint32{
"sector size": []uint32{r.sectorSize},
"mini fat locs": r.header.miniFatLocs,
"mini stream locs": r.header.miniStreamLocs,
"directory sector": []uint32{r.header.directorySectorLoc},
"mini stream start/size": []uint32{r.File[0].startingSectorLoc, binary.LittleEndian.Uint32(r.File[0].streamSize[:])},
}
for f, err := r.Next(); err == nil; f, err = r.Next() {
ret[f.Name+" start/size"] = []uint32{f.startingSectorLoc, binary.LittleEndian.Uint32(f.streamSize[:])}
}
return ret
}
const (
// ErrFormat reports issues with the MSCFB's header structures
ErrFormat = iota
// ErrRead reports issues attempting to read MSCFB streams
ErrRead
// ErrSeek reports seek issues
ErrSeek
// ErrWrite reports write issues
ErrWrite
// ErrTraverse reports issues attempting to traverse the child-parent-sibling relations
// between MSCFB storage objects
ErrTraverse
)
type Error struct {
typ int
msg string
val int64
}
func (e Error) Error() string {
return "mscfb: " + e.msg + "; " + strconv.FormatInt(e.val, 10)
}
// Typ gives the type of MSCFB error
func (e Error) Typ() int {
return e.typ
}
// Slicer interface avoids a copy by obtaining a byte slice directly from the underlying reader
type slicer interface {
Slice(offset int64, length int) ([]byte, error)
}
... ...
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"strconv"
)
//The CURRENCY type specifies currency information. It is represented as an 8-byte integer, scaled by 10,000, to give a fixed-point number with 15 digits to the left of the decimal point, and four digits to the right. This representation provides a range of 922337203685477.5807 to –922337203685477.5808. For example, $5.25 is stored as the value 52500.
type Currency int64
func (c Currency) String() string {
return "$" + strconv.FormatFloat(float64(c)/10000, 'f', -1, 64)
}
func (c Currency) Type() string {
return "Currency"
}
func (c Currency) Length() int {
return 8
}
func MakeCurrency(b []byte) (Type, error) {
if len(b) < 8 {
return Currency(0), ErrType
}
return Currency(binary.LittleEndian.Uint64(b[:8])), nil
}
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"strconv"
)
//The CURRENCY type specifies currency information. It is represented as an 8-byte integer, scaled by 10,000, to give a fixed-point number with 15 digits to the left of the decimal point, and four digits to the right. This representation provides a range of 922337203685477.5807 to –922337203685477.5808. For example, $5.25 is stored as the value 52500.
type Currency int64
func (c Currency) String() string {
return "$" + strconv.FormatFloat(float64(c)/10000, 'f', -1, 64)
}
func (c Currency) Type() string {
return "Currency"
}
func (c Currency) Length() int {
return 8
}
func MakeCurrency(b []byte) (Type, error) {
if len(b) < 8 {
return Currency(0), ErrType
}
return Currency(binary.LittleEndian.Uint64(b[:8])), nil
}
... ...
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"time"
)
// http://msdn.microsoft.com/en-us/library/cc237601.aspx
type Date float64
func (d Date) Time() time.Time {
start := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
day := float64(time.Hour * 24)
dur := time.Duration(day * float64(d))
return start.Add(dur)
}
func (d Date) String() string {
return d.Time().String()
}
func (d Date) Type() string {
return "Date"
}
func (d Date) Length() int {
return 8
}
func MakeDate(b []byte) (Type, error) {
if len(b) < 8 {
return Date(0), ErrType
}
return Date(binary.LittleEndian.Uint64(b[:8])), nil
}
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"time"
)
// http://msdn.microsoft.com/en-us/library/cc237601.aspx
type Date float64
func (d Date) Time() time.Time {
start := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
day := float64(time.Hour * 24)
dur := time.Duration(day * float64(d))
return start.Add(dur)
}
func (d Date) String() string {
return d.Time().String()
}
func (d Date) Type() string {
return "Date"
}
func (d Date) Length() int {
return 8
}
func MakeDate(b []byte) (Type, error) {
if len(b) < 8 {
return Date(0), ErrType
}
return Date(binary.LittleEndian.Uint64(b[:8])), nil
}
... ...
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"math"
"math/big"
)
// http://msdn.microsoft.com/en-us/library/cc237603.aspx
type Decimal struct {
res [2]byte
scale byte
sign byte
high32 uint32
low64 uint64
}
func (d Decimal) Type() string {
return "Decimal"
}
func (d Decimal) Length() int {
return 16
}
func (d Decimal) String() string {
h, l, b := new(big.Int), new(big.Int), new(big.Int)
l.SetUint64(d.low64)
h.Lsh(big.NewInt(int64(d.high32)), 64)
b.Add(h, l)
q, f, r := new(big.Rat), new(big.Rat), new(big.Rat)
q.SetFloat64(math.Pow10(int(d.scale)))
r.Quo(f.SetInt(b), q)
if d.sign == 0x80 {
r.Neg(r)
}
return r.FloatString(20)
}
func MakeDecimal(b []byte) (Type, error) {
if len(b) < 16 {
return Decimal{}, ErrType
}
return Decimal{
res: [2]byte{b[0], b[1]},
scale: b[2],
sign: b[3],
high32: binary.LittleEndian.Uint32(b[4:8]),
low64: binary.LittleEndian.Uint64(b[8:16]),
}, nil
}
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"math"
"math/big"
)
// http://msdn.microsoft.com/en-us/library/cc237603.aspx
type Decimal struct {
res [2]byte
scale byte
sign byte
high32 uint32
low64 uint64
}
func (d Decimal) Type() string {
return "Decimal"
}
func (d Decimal) Length() int {
return 16
}
func (d Decimal) String() string {
h, l, b := new(big.Int), new(big.Int), new(big.Int)
l.SetUint64(d.low64)
h.Lsh(big.NewInt(int64(d.high32)), 64)
b.Add(h, l)
q, f, r := new(big.Rat), new(big.Rat), new(big.Rat)
q.SetFloat64(math.Pow10(int(d.scale)))
r.Quo(f.SetInt(b), q)
if d.sign == 0x80 {
r.Neg(r)
}
return r.FloatString(20)
}
func MakeDecimal(b []byte) (Type, error) {
if len(b) < 16 {
return Decimal{}, ErrType
}
return Decimal{
res: [2]byte{b[0], b[1]},
scale: b[2],
sign: b[3],
high32: binary.LittleEndian.Uint32(b[4:8]),
low64: binary.LittleEndian.Uint64(b[8:16]),
}, nil
}
... ...
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"time"
)
// Win FILETIME type
// http://msdn.microsoft.com/en-us/library/cc230324.aspx
type FileTime struct {
Low uint32 // Windows FILETIME structure
High uint32 // Windows FILETIME structure
}
const (
tick uint64 = 10000000
gregToUnix uint64 = 11644473600
)
func winToUnix(low, high uint32) int64 {
gregTime := ((uint64(high) << 32) + uint64(low)) / tick
if gregTime < gregToUnix {
return 0
}
return int64(gregTime - gregToUnix)
}
func (f FileTime) Time() time.Time {
return time.Unix(winToUnix(f.Low, f.High), 0)
}
func (f FileTime) String() string {
return f.Time().String()
}
func (f FileTime) Type() string {
return "FileTime"
}
func (f FileTime) Length() int {
return 8
}
func MakeFileTime(b []byte) (Type, error) {
if len(b) < 8 {
return FileTime{}, ErrType
}
return MustFileTime(b), nil
}
func MustFileTime(b []byte) FileTime {
return FileTime{
Low: binary.LittleEndian.Uint32(b[:4]),
High: binary.LittleEndian.Uint32(b[4:8]),
}
}
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"time"
)
// Win FILETIME type
// http://msdn.microsoft.com/en-us/library/cc230324.aspx
type FileTime struct {
Low uint32 // Windows FILETIME structure
High uint32 // Windows FILETIME structure
}
const (
tick uint64 = 10000000
gregToUnix uint64 = 11644473600
)
func winToUnix(low, high uint32) int64 {
gregTime := ((uint64(high) << 32) + uint64(low)) / tick
if gregTime < gregToUnix {
return 0
}
return int64(gregTime - gregToUnix)
}
func (f FileTime) Time() time.Time {
return time.Unix(winToUnix(f.Low, f.High), 0)
}
func (f FileTime) String() string {
return f.Time().String()
}
func (f FileTime) Type() string {
return "FileTime"
}
func (f FileTime) Length() int {
return 8
}
func MakeFileTime(b []byte) (Type, error) {
if len(b) < 8 {
return FileTime{}, ErrType
}
return MustFileTime(b), nil
}
func MustFileTime(b []byte) FileTime {
return FileTime{
Low: binary.LittleEndian.Uint32(b[:4]),
High: binary.LittleEndian.Uint32(b[4:8]),
}
}
... ...
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"encoding/hex"
"errors"
"strings"
)
// Win GUID and UUID type
// http://msdn.microsoft.com/en-us/library/cc230326.aspx
type Guid struct {
DataA uint32
DataB uint16
DataC uint16
DataD [8]byte
}
func (g Guid) String() string {
buf := make([]byte, 8)
binary.BigEndian.PutUint32(buf[:4], g.DataA)
binary.BigEndian.PutUint16(buf[4:6], g.DataB)
binary.BigEndian.PutUint16(buf[6:], g.DataC)
return strings.ToUpper("{" +
hex.EncodeToString(buf[:4]) +
"-" +
hex.EncodeToString(buf[4:6]) +
"-" +
hex.EncodeToString(buf[6:]) +
"-" +
hex.EncodeToString(g.DataD[:2]) +
"-" +
hex.EncodeToString(g.DataD[2:]) +
"}")
}
func (g Guid) Type() string {
return "Guid"
}
func (g Guid) Length() int {
return 16
}
func GuidFromString(str string) (Guid, error) {
gerr := "Invalid GUID: expecting in format {F29F85E0-4FF9-1068-AB91-08002B27B3D9}, got " + str
if len(str) != 38 {
return Guid{}, errors.New(gerr + "; bad length, should be 38 chars")
}
trimmed := strings.Trim(str, "{}")
parts := strings.Split(trimmed, "-")
if len(parts) != 5 {
return Guid{}, errors.New(gerr + "; expecting should five '-' separators")
}
buf, err := hex.DecodeString(strings.Join(parts, ""))
if err != nil {
return Guid{}, errors.New(gerr + "; error decoding hex: " + err.Error())
}
return makeGuid(buf, binary.BigEndian), nil
}
func MakeGuid(b []byte) (Type, error) {
if len(b) < 16 {
return Guid{}, ErrType
}
return makeGuid(b, binary.LittleEndian), nil
}
func makeGuid(b []byte, order binary.ByteOrder) Guid {
g := Guid{
DataA: order.Uint32(b[:4]),
DataB: order.Uint16(b[4:6]),
DataC: order.Uint16(b[6:8]),
DataD: [8]byte{},
}
copy(g.DataD[:], b[8:])
return g
}
func MustGuidFromString(str string) Guid {
g, err := GuidFromString(str)
if err != nil {
panic(err)
}
return g
}
func MustGuid(b []byte) Guid {
return makeGuid(b, binary.LittleEndian)
}
func GuidFromName(n string) (Guid, error) {
n = strings.ToLower(n)
buf, err := charConvert([]byte(n))
if err != nil {
return Guid{}, err
}
return makeGuid(buf, binary.LittleEndian), nil
}
func charConvert(in []byte) ([]byte, error) {
if len(in) != 26 {
return nil, errors.New("invalid GUID: expecting 26 characters")
}
out := make([]byte, 16)
var idx, shift uint
var b byte
for _, v := range in {
this, ok := characterMapping[v]
if !ok {
return nil, errors.New("invalid Guid: invalid character")
}
b = b | this<<shift
if shift >= 3 {
out[idx] = b
idx++
b = this >> (8 - shift) // write any remainder back to b, or 0 if shift is 3
}
shift = shift + 5
if shift > 7 {
shift = shift - 8
}
}
return out, nil
}
const (
charA byte = iota
charB
charC
charD
charE
charF
charG
charH
charI
charJ
charK
charL
charM
charN
charO
charP
charQ
charR
charS
charT
charU
charV
charW
charX
charY
charZ
char0
char1
char2
char3
char4
char5
)
var characterMapping = map[byte]byte{
'a': charA,
'b': charB,
'c': charC,
'd': charD,
'e': charE,
'f': charF,
'g': charG,
'h': charH,
'i': charI,
'j': charJ,
'k': charK,
'l': charL,
'm': charM,
'n': charN,
'o': charO,
'p': charP,
'q': charQ,
'r': charR,
's': charS,
't': charT,
'u': charU,
'v': charV,
'w': charW,
'x': charX,
'y': charY,
'z': charZ,
'0': char0,
'1': char1,
'2': char2,
'3': char3,
'4': char4,
'5': char5,
}
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"encoding/hex"
"errors"
"strings"
)
// Win GUID and UUID type
// http://msdn.microsoft.com/en-us/library/cc230326.aspx
type Guid struct {
DataA uint32
DataB uint16
DataC uint16
DataD [8]byte
}
func (g Guid) String() string {
buf := make([]byte, 8)
binary.BigEndian.PutUint32(buf[:4], g.DataA)
binary.BigEndian.PutUint16(buf[4:6], g.DataB)
binary.BigEndian.PutUint16(buf[6:], g.DataC)
return strings.ToUpper("{" +
hex.EncodeToString(buf[:4]) +
"-" +
hex.EncodeToString(buf[4:6]) +
"-" +
hex.EncodeToString(buf[6:]) +
"-" +
hex.EncodeToString(g.DataD[:2]) +
"-" +
hex.EncodeToString(g.DataD[2:]) +
"}")
}
func (g Guid) Type() string {
return "Guid"
}
func (g Guid) Length() int {
return 16
}
func GuidFromString(str string) (Guid, error) {
gerr := "Invalid GUID: expecting in format {F29F85E0-4FF9-1068-AB91-08002B27B3D9}, got " + str
if len(str) != 38 {
return Guid{}, errors.New(gerr + "; bad length, should be 38 chars")
}
trimmed := strings.Trim(str, "{}")
parts := strings.Split(trimmed, "-")
if len(parts) != 5 {
return Guid{}, errors.New(gerr + "; expecting should five '-' separators")
}
buf, err := hex.DecodeString(strings.Join(parts, ""))
if err != nil {
return Guid{}, errors.New(gerr + "; error decoding hex: " + err.Error())
}
return makeGuid(buf, binary.BigEndian), nil
}
func MakeGuid(b []byte) (Type, error) {
if len(b) < 16 {
return Guid{}, ErrType
}
return makeGuid(b, binary.LittleEndian), nil
}
func makeGuid(b []byte, order binary.ByteOrder) Guid {
g := Guid{
DataA: order.Uint32(b[:4]),
DataB: order.Uint16(b[4:6]),
DataC: order.Uint16(b[6:8]),
DataD: [8]byte{},
}
copy(g.DataD[:], b[8:])
return g
}
func MustGuidFromString(str string) Guid {
g, err := GuidFromString(str)
if err != nil {
panic(err)
}
return g
}
func MustGuid(b []byte) Guid {
return makeGuid(b, binary.LittleEndian)
}
func GuidFromName(n string) (Guid, error) {
n = strings.ToLower(n)
buf, err := charConvert([]byte(n))
if err != nil {
return Guid{}, err
}
return makeGuid(buf, binary.LittleEndian), nil
}
func charConvert(in []byte) ([]byte, error) {
if len(in) != 26 {
return nil, errors.New("invalid GUID: expecting 26 characters")
}
out := make([]byte, 16)
var idx, shift uint
var b byte
for _, v := range in {
this, ok := characterMapping[v]
if !ok {
return nil, errors.New("invalid Guid: invalid character")
}
b = b | this<<shift
if shift >= 3 {
out[idx] = b
idx++
b = this >> (8 - shift) // write any remainder back to b, or 0 if shift is 3
}
shift = shift + 5
if shift > 7 {
shift = shift - 8
}
}
return out, nil
}
const (
charA byte = iota
charB
charC
charD
charE
charF
charG
charH
charI
charJ
charK
charL
charM
charN
charO
charP
charQ
charR
charS
charT
charU
charV
charW
charX
charY
charZ
char0
char1
char2
char3
char4
char5
)
var characterMapping = map[byte]byte{
'a': charA,
'b': charB,
'c': charC,
'd': charD,
'e': charE,
'f': charF,
'g': charG,
'h': charH,
'i': charI,
'j': charJ,
'k': charK,
'l': charL,
'm': charM,
'n': charN,
'o': charO,
'p': charP,
'q': charQ,
'r': charR,
's': charS,
't': charT,
'u': charU,
'v': charV,
'w': charW,
'x': charX,
'y': charY,
'z': charZ,
'0': char0,
'1': char1,
'2': char2,
'3': char3,
'4': char4,
'5': char5,
}
... ...
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"strings"
"unicode/utf16"
)
func nullTerminated(s string) string {
return s[:strings.Index(s, "\x00")]
}
type UnicodeString []uint16
func (s UnicodeString) Type() string {
return "UnicodeString"
}
func (s UnicodeString) Length() int {
return 4 + len(s)*2
}
func (s UnicodeString) String() string {
if len(s) == 0 {
return ""
}
return nullTerminated(string(utf16.Decode(s)))
}
func MakeUnicode(b []byte) (Type, error) {
if len(b) < 4 {
return UnicodeString{}, ErrType
}
l := int(binary.LittleEndian.Uint32(b[:4]))
if l == 0 {
return UnicodeString{}, nil
}
if len(b) < l*2+4 {
return UnicodeString{}, ErrType
}
s := make(UnicodeString, l)
for i := range s {
start := i*2 + 4
s[i] = binary.LittleEndian.Uint16(b[start : start+2])
}
return s, nil
}
type CodeString struct {
id CodePageID
Chars []byte
}
func (s *CodeString) SetId(i CodePageID) {
s.id = i
}
func (s *CodeString) Encoding() string {
return CodePageIDs[s.id]
}
func (s *CodeString) Type() string {
return "CodeString"
}
func (s *CodeString) Length() int {
return 4 + len(s.Chars)
}
func (s *CodeString) String() string {
if len(s.Chars) == 0 {
return ""
}
if s.id == 1200 {
chars := make([]uint16, len(s.Chars)/2)
for i := range chars {
chars[i] = binary.LittleEndian.Uint16(s.Chars[i*2 : i*2+2])
}
return nullTerminated(string(utf16.Decode(chars)))
}
return nullTerminated(string(s.Chars))
}
func MakeCodeString(b []byte) (Type, error) {
if len(b) < 4 {
return &CodeString{}, ErrType
}
s := &CodeString{}
l := int(binary.LittleEndian.Uint32(b[:4]))
if l == 0 {
return s, nil
}
if len(b) < l+4 {
return s, ErrType
}
s.Chars = make([]byte, l)
copy(s.Chars, b[4:l+4])
return s, nil
}
type CodePageID uint16
var CodePageIDs map[CodePageID]string = map[CodePageID]string{
37: "IBM037 - IBM EBCDIC US-Canada",
437: "IBM437 - OEM United States",
500: "IBM500 - IBM EBCDIC International",
708: "ASMO-708 - Arabic (ASMO 708)",
709: "Arabic (ASMO-449+, BCON V4)",
710: "Arabic - Transparent Arabic",
720: "DOS-720 - Arabic (Transparent ASMO); Arabic (DOS)",
737: "ibm737 - OEM Greek (formerly 437G); Greek (DOS)",
775: "ibm775 - OEM Baltic; Baltic (DOS)",
850: "ibm850 - OEM Multilingual Latin 1; Western European (DOS)",
852: "ibm852 - OEM Latin 2; Central European (DOS)",
855: "IBM855 - OEM Cyrillic (primarily Russian)",
857: "ibm857 - OEM Turkish; Turkish (DOS)",
858: "IBM00858 - OEM Multilingual Latin 1 + Euro symbol",
860: "IBM860 - OEM Portuguese; Portuguese (DOS)",
861: "ibm861 - OEM Icelandic; Icelandic (DOS)",
862: "DOS-862 - OEM Hebrew; Hebrew (DOS)",
863: "IBM863 - OEM French Canadian; French Canadian (DOS)",
864: "IBM864 - OEM Arabic; Arabic (864)",
865: "IBM865 - OEM Nordic; Nordic (DOS)",
866: "cp866 - OEM Russian; Cyrillic (DOS)",
869: "ibm869 - OEM Modern Greek; Greek, Modern (DOS)",
870: "IBM870 - IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2",
874: "windows-874 - ANSI/OEM Thai (ISO 8859-11); Thai (Windows)",
875: "cp875 - IBM EBCDIC Greek Modern",
932: "shift_jis - ANSI/OEM Japanese; Japanese (Shift-JIS)",
936: "gb2312 - ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)",
949: "ks_c_5601-1987 - ANSI/OEM Korean (Unified Hangul Code)",
950: "big5 - ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)",
1026: "IBM1026 - IBM EBCDIC Turkish (Latin 5)",
1047: "IBM01047 - BM EBCDIC Latin 1/Open System",
1140: "IBM01140 - IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)",
1141: "IBM01141 - IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)",
1142: "IBM01142 - IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)",
1143: "IBM01143 - IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)",
1144: "IBM01144 - IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)",
1145: "IBM01145 - IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)",
1146: "IBM01146 - IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)",
1147: "IBM01147 - IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)",
1148: "IBM01148 - IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)",
1149: "IBM01149 - IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)",
1200: "utf-16 - Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications",
1201: "unicodeFFFE - Unicode UTF-16, big endian byte order; available only to managed applications",
1250: "windows-1250 - ANSI Central European; Central European (Windows)",
1251: "windows-1251 - ANSI Cyrillic; Cyrillic (Windows)",
1252: "windows-1252 - ANSI Latin 1; Western European (Windows)",
1253: "windows-1253 - ANSI Greek; Greek (Windows)",
1254: "windows-1254 - ANSI Turkish; Turkish (Windows)",
1255: "windows-1255 - ANSI Hebrew; Hebrew (Windows)",
1256: "windows-1256 - ANSI Arabic; Arabic (Windows)",
1257: "windows-1257 - ANSI Baltic; Baltic (Windows)",
1258: "windows-1258 - ANSI/OEM Vietnamese; Vietnamese (Windows)",
1361: "Johab - Korean (Johab)",
10000: "macintosh - MAC Roman; Western European (Mac)",
10001: "x-mac-japanese - Japanese (Mac)",
10002: "x-mac-chinesetrad - MAC Traditional Chinese (Big5); Chinese Traditional (Mac)",
10003: "x-mac-korean - Korean (Mac)",
10004: "x-mac-arabic - Arabic (Mac)",
10005: "x-mac-hebrew - Hebrew (Mac)",
10006: "x-mac-greek - Greek (Mac)",
10007: "x-mac-cyrillic - Cyrillic (Mac)",
10008: "x-mac-chinesesimp - MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)",
10010: "x-mac-romanian - Romanian (Mac)",
10017: "x-mac-ukrainian - Ukrainian (Mac)",
10021: "x-mac-thai - Thai (Mac)",
10029: "x-mac-ce - MAC Latin 2; Central European (Mac)",
10079: "x-mac-icelandic - Icelandic (Mac)",
10081: "x-mac-turkish - Turkish (Mac)",
10082: "x-mac-croatian - Croatian (Mac)",
12000: "utf-32 - Unicode UTF-32, little endian byte order; available only to managed applications",
12001: "utf-32BE - Unicode UTF-32, big endian byte order; available only to managed applications",
20000: "x-Chinese_CNS - CNS Taiwan; Chinese Traditional (CNS)",
20001: "x-cp20001 - TCA Taiwan",
20002: "x_Chinese-Eten - Eten Taiwan; Chinese Traditional (Eten)",
20003: "x-cp20003 - IBM5550 Taiwan",
20004: "x-cp20004 - TeleText Taiwan",
20005: "x-cp20005 - Wang Taiwan",
20105: "x-IA5 - IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)",
20106: "x-IA5-German - IA5 German (7-bit)",
20107: "x-IA5-Swedish - IA5 Swedish (7-bit)",
20108: "x-IA5-Norwegian - IA5 Norwegian (7-bit)",
20127: "us-ascii - US-ASCII (7-bit)",
20261: "x-cp20261 - T.61",
20269: "x-cp20269 - ISO 6937 Non-Spacing Accent",
20273: "IBM273 - IBM EBCDIC Germany",
20277: "IBM277 - IBM EBCDIC Denmark-Norway",
20278: "IBM278 - IBM EBCDIC Finland-Sweden",
20280: "IBM280 - IBM EBCDIC Italy",
20284: "IBM284 - IBM EBCDIC Latin America-Spain",
20285: "IBM285 - IBM EBCDIC United Kingdom",
20290: "IBM290 - IBM EBCDIC Japanese Katakana Extended",
20297: "IBM297 - IBM EBCDIC France",
20420: "IBM420 - IBM EBCDIC Arabic",
20423: "IBM423 - IBM EBCDIC Greek",
20424: "IBM424 - IBM EBCDIC Hebrew",
20833: "x-EBCDIC-KoreanExtended - IBM EBCDIC Korean Extended",
20838: "IBM-Thai - IBM EBCDIC Thai",
20866: "koi8-r - Russian (KOI8-R); Cyrillic (KOI8-R)",
20871: "IBM871 - IBM EBCDIC Icelandic",
20880: "IBM880 - IBM EBCDIC Cyrillic Russian",
20905: "IBM905 - IBM EBCDIC Turkish",
20924: "IBM00924 - IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)",
20932: "EUC-JP - Japanese (JIS 0208-1990 and 0212-1990)",
20936: "x-cp20936 - Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)",
20949: "x-cp20949 - Korean Wansung",
21025: "cp1025 - IBM EBCDIC Cyrillic Serbian-Bulgarian",
21027: "(deprecated)",
21866: "koi8-u - Ukrainian (KOI8-U); Cyrillic (KOI8-U)",
28591: "iso-8859-1 - ISO 8859-1 Latin 1; Western European (ISO)",
28592: "iso-8859-2 - ISO 8859-2 Central European; Central European (ISO)",
28593: "iso-8859-3 - ISO 8859-3 Latin 3",
28594: "iso-8859-4 - ISO 8859-4 Baltic",
28595: "iso-8859-5 - ISO 8859-5 Cyrillic",
28596: "iso-8859-6 - ISO 8859-6 Arabic",
28597: "iso-8859-7 - ISO 8859-7 Greek",
28598: "iso-8859-8 - ISO 8859-8 Hebrew; Hebrew (ISO-Visual)",
28599: "iso-8859-9 - ISO 8859-9 Turkish",
28603: "iso-8859-13 - ISO 8859-13 Estonian",
28605: "iso-8859-15 - ISO 8859-15 Latin 9",
29001: "x-Europa - Europa 3",
38598: "iso-8859-8-i - ISO 8859-8 Hebrew; Hebrew (ISO-Logical)",
50220: "iso-2022-jp - ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)",
50221: "csISO2022JP - ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)",
50222: "iso-2022-jp - ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)",
50225: "iso-2022-kr - ISO 2022 Korean",
50227: "x-cp50227 - ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)",
50229: "ISO 2022 - Traditional Chinese",
50930: "EBCDIC - Japanese (Katakana) Extended",
50931: "EBCDIC - US-Canada and Japanese",
50933: "EBCDIC - Korean Extended and Korean",
50935: "EBCDIC - Simplified Chinese Extended and Simplified Chinese",
50936: "EBCDIC - Simplified Chinese",
50937: "EBCDIC - US-Canada and Traditional Chinese",
50939: "EBCDIC - Japanese (Latin) Extended and Japanese",
51932: "euc-jp - EUC Japanese",
51936: "EUC-CN - EUC Simplified Chinese; Chinese Simplified (EUC)",
51949: "euc-kr - EUC Korean",
51950: "EUC - Traditional Chinese",
52936: "hz-gb-2312 - HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)",
54936: "GB18030 - Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)",
57002: "x-iscii-de - ISCII Devanagari",
57003: "x-iscii-be - ISCII Bengali",
57004: "x-iscii-ta - ISCII Tamil",
57005: "x-iscii-te - ISCII Telugu",
57006: "x-iscii-as - ISCII Assamese",
57007: "x-iscii-or - ISCII Oriya",
57008: "x-iscii-ka - ISCII Kannada",
57009: "x-iscii-ma - ISCII Malayalam",
57010: "x-iscii-gu - ISCII Gujarati",
57011: "x-iscii-pa - ISCII Punjabi",
65000: "utf-7 - Unicode (UTF-7)",
65001: "utf-8 - Unicode (UTF-8)",
}
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"strings"
"unicode/utf16"
)
func nullTerminated(s string) string {
return s[:strings.Index(s, "\x00")]
}
type UnicodeString []uint16
func (s UnicodeString) Type() string {
return "UnicodeString"
}
func (s UnicodeString) Length() int {
return 4 + len(s)*2
}
func (s UnicodeString) String() string {
if len(s) == 0 {
return ""
}
return nullTerminated(string(utf16.Decode(s)))
}
func MakeUnicode(b []byte) (Type, error) {
if len(b) < 4 {
return UnicodeString{}, ErrType
}
l := int(binary.LittleEndian.Uint32(b[:4]))
if l == 0 {
return UnicodeString{}, nil
}
if len(b) < l*2+4 {
return UnicodeString{}, ErrType
}
s := make(UnicodeString, l)
for i := range s {
start := i*2 + 4
s[i] = binary.LittleEndian.Uint16(b[start : start+2])
}
return s, nil
}
type CodeString struct {
id CodePageID
Chars []byte
}
func (s *CodeString) SetId(i CodePageID) {
s.id = i
}
func (s *CodeString) Encoding() string {
return CodePageIDs[s.id]
}
func (s *CodeString) Type() string {
return "CodeString"
}
func (s *CodeString) Length() int {
return 4 + len(s.Chars)
}
func (s *CodeString) String() string {
if len(s.Chars) == 0 {
return ""
}
if s.id == 1200 {
chars := make([]uint16, len(s.Chars)/2)
for i := range chars {
chars[i] = binary.LittleEndian.Uint16(s.Chars[i*2 : i*2+2])
}
return nullTerminated(string(utf16.Decode(chars)))
}
return nullTerminated(string(s.Chars))
}
func MakeCodeString(b []byte) (Type, error) {
if len(b) < 4 {
return &CodeString{}, ErrType
}
s := &CodeString{}
l := int(binary.LittleEndian.Uint32(b[:4]))
if l == 0 {
return s, nil
}
if len(b) < l+4 {
return s, ErrType
}
s.Chars = make([]byte, l)
copy(s.Chars, b[4:l+4])
return s, nil
}
type CodePageID uint16
var CodePageIDs map[CodePageID]string = map[CodePageID]string{
37: "IBM037 - IBM EBCDIC US-Canada",
437: "IBM437 - OEM United States",
500: "IBM500 - IBM EBCDIC International",
708: "ASMO-708 - Arabic (ASMO 708)",
709: "Arabic (ASMO-449+, BCON V4)",
710: "Arabic - Transparent Arabic",
720: "DOS-720 - Arabic (Transparent ASMO); Arabic (DOS)",
737: "ibm737 - OEM Greek (formerly 437G); Greek (DOS)",
775: "ibm775 - OEM Baltic; Baltic (DOS)",
850: "ibm850 - OEM Multilingual Latin 1; Western European (DOS)",
852: "ibm852 - OEM Latin 2; Central European (DOS)",
855: "IBM855 - OEM Cyrillic (primarily Russian)",
857: "ibm857 - OEM Turkish; Turkish (DOS)",
858: "IBM00858 - OEM Multilingual Latin 1 + Euro symbol",
860: "IBM860 - OEM Portuguese; Portuguese (DOS)",
861: "ibm861 - OEM Icelandic; Icelandic (DOS)",
862: "DOS-862 - OEM Hebrew; Hebrew (DOS)",
863: "IBM863 - OEM French Canadian; French Canadian (DOS)",
864: "IBM864 - OEM Arabic; Arabic (864)",
865: "IBM865 - OEM Nordic; Nordic (DOS)",
866: "cp866 - OEM Russian; Cyrillic (DOS)",
869: "ibm869 - OEM Modern Greek; Greek, Modern (DOS)",
870: "IBM870 - IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2",
874: "windows-874 - ANSI/OEM Thai (ISO 8859-11); Thai (Windows)",
875: "cp875 - IBM EBCDIC Greek Modern",
932: "shift_jis - ANSI/OEM Japanese; Japanese (Shift-JIS)",
936: "gb2312 - ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)",
949: "ks_c_5601-1987 - ANSI/OEM Korean (Unified Hangul Code)",
950: "big5 - ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)",
1026: "IBM1026 - IBM EBCDIC Turkish (Latin 5)",
1047: "IBM01047 - BM EBCDIC Latin 1/Open System",
1140: "IBM01140 - IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)",
1141: "IBM01141 - IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)",
1142: "IBM01142 - IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)",
1143: "IBM01143 - IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)",
1144: "IBM01144 - IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)",
1145: "IBM01145 - IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)",
1146: "IBM01146 - IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)",
1147: "IBM01147 - IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)",
1148: "IBM01148 - IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)",
1149: "IBM01149 - IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)",
1200: "utf-16 - Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications",
1201: "unicodeFFFE - Unicode UTF-16, big endian byte order; available only to managed applications",
1250: "windows-1250 - ANSI Central European; Central European (Windows)",
1251: "windows-1251 - ANSI Cyrillic; Cyrillic (Windows)",
1252: "windows-1252 - ANSI Latin 1; Western European (Windows)",
1253: "windows-1253 - ANSI Greek; Greek (Windows)",
1254: "windows-1254 - ANSI Turkish; Turkish (Windows)",
1255: "windows-1255 - ANSI Hebrew; Hebrew (Windows)",
1256: "windows-1256 - ANSI Arabic; Arabic (Windows)",
1257: "windows-1257 - ANSI Baltic; Baltic (Windows)",
1258: "windows-1258 - ANSI/OEM Vietnamese; Vietnamese (Windows)",
1361: "Johab - Korean (Johab)",
10000: "macintosh - MAC Roman; Western European (Mac)",
10001: "x-mac-japanese - Japanese (Mac)",
10002: "x-mac-chinesetrad - MAC Traditional Chinese (Big5); Chinese Traditional (Mac)",
10003: "x-mac-korean - Korean (Mac)",
10004: "x-mac-arabic - Arabic (Mac)",
10005: "x-mac-hebrew - Hebrew (Mac)",
10006: "x-mac-greek - Greek (Mac)",
10007: "x-mac-cyrillic - Cyrillic (Mac)",
10008: "x-mac-chinesesimp - MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)",
10010: "x-mac-romanian - Romanian (Mac)",
10017: "x-mac-ukrainian - Ukrainian (Mac)",
10021: "x-mac-thai - Thai (Mac)",
10029: "x-mac-ce - MAC Latin 2; Central European (Mac)",
10079: "x-mac-icelandic - Icelandic (Mac)",
10081: "x-mac-turkish - Turkish (Mac)",
10082: "x-mac-croatian - Croatian (Mac)",
12000: "utf-32 - Unicode UTF-32, little endian byte order; available only to managed applications",
12001: "utf-32BE - Unicode UTF-32, big endian byte order; available only to managed applications",
20000: "x-Chinese_CNS - CNS Taiwan; Chinese Traditional (CNS)",
20001: "x-cp20001 - TCA Taiwan",
20002: "x_Chinese-Eten - Eten Taiwan; Chinese Traditional (Eten)",
20003: "x-cp20003 - IBM5550 Taiwan",
20004: "x-cp20004 - TeleText Taiwan",
20005: "x-cp20005 - Wang Taiwan",
20105: "x-IA5 - IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)",
20106: "x-IA5-German - IA5 German (7-bit)",
20107: "x-IA5-Swedish - IA5 Swedish (7-bit)",
20108: "x-IA5-Norwegian - IA5 Norwegian (7-bit)",
20127: "us-ascii - US-ASCII (7-bit)",
20261: "x-cp20261 - T.61",
20269: "x-cp20269 - ISO 6937 Non-Spacing Accent",
20273: "IBM273 - IBM EBCDIC Germany",
20277: "IBM277 - IBM EBCDIC Denmark-Norway",
20278: "IBM278 - IBM EBCDIC Finland-Sweden",
20280: "IBM280 - IBM EBCDIC Italy",
20284: "IBM284 - IBM EBCDIC Latin America-Spain",
20285: "IBM285 - IBM EBCDIC United Kingdom",
20290: "IBM290 - IBM EBCDIC Japanese Katakana Extended",
20297: "IBM297 - IBM EBCDIC France",
20420: "IBM420 - IBM EBCDIC Arabic",
20423: "IBM423 - IBM EBCDIC Greek",
20424: "IBM424 - IBM EBCDIC Hebrew",
20833: "x-EBCDIC-KoreanExtended - IBM EBCDIC Korean Extended",
20838: "IBM-Thai - IBM EBCDIC Thai",
20866: "koi8-r - Russian (KOI8-R); Cyrillic (KOI8-R)",
20871: "IBM871 - IBM EBCDIC Icelandic",
20880: "IBM880 - IBM EBCDIC Cyrillic Russian",
20905: "IBM905 - IBM EBCDIC Turkish",
20924: "IBM00924 - IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)",
20932: "EUC-JP - Japanese (JIS 0208-1990 and 0212-1990)",
20936: "x-cp20936 - Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)",
20949: "x-cp20949 - Korean Wansung",
21025: "cp1025 - IBM EBCDIC Cyrillic Serbian-Bulgarian",
21027: "(deprecated)",
21866: "koi8-u - Ukrainian (KOI8-U); Cyrillic (KOI8-U)",
28591: "iso-8859-1 - ISO 8859-1 Latin 1; Western European (ISO)",
28592: "iso-8859-2 - ISO 8859-2 Central European; Central European (ISO)",
28593: "iso-8859-3 - ISO 8859-3 Latin 3",
28594: "iso-8859-4 - ISO 8859-4 Baltic",
28595: "iso-8859-5 - ISO 8859-5 Cyrillic",
28596: "iso-8859-6 - ISO 8859-6 Arabic",
28597: "iso-8859-7 - ISO 8859-7 Greek",
28598: "iso-8859-8 - ISO 8859-8 Hebrew; Hebrew (ISO-Visual)",
28599: "iso-8859-9 - ISO 8859-9 Turkish",
28603: "iso-8859-13 - ISO 8859-13 Estonian",
28605: "iso-8859-15 - ISO 8859-15 Latin 9",
29001: "x-Europa - Europa 3",
38598: "iso-8859-8-i - ISO 8859-8 Hebrew; Hebrew (ISO-Logical)",
50220: "iso-2022-jp - ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)",
50221: "csISO2022JP - ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)",
50222: "iso-2022-jp - ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)",
50225: "iso-2022-kr - ISO 2022 Korean",
50227: "x-cp50227 - ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)",
50229: "ISO 2022 - Traditional Chinese",
50930: "EBCDIC - Japanese (Katakana) Extended",
50931: "EBCDIC - US-Canada and Japanese",
50933: "EBCDIC - Korean Extended and Korean",
50935: "EBCDIC - Simplified Chinese Extended and Simplified Chinese",
50936: "EBCDIC - Simplified Chinese",
50937: "EBCDIC - US-Canada and Traditional Chinese",
50939: "EBCDIC - Japanese (Latin) Extended and Japanese",
51932: "euc-jp - EUC Japanese",
51936: "EUC-CN - EUC Simplified Chinese; Chinese Simplified (EUC)",
51949: "euc-kr - EUC Korean",
51950: "EUC - Traditional Chinese",
52936: "hz-gb-2312 - HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)",
54936: "GB18030 - Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)",
57002: "x-iscii-de - ISCII Devanagari",
57003: "x-iscii-be - ISCII Bengali",
57004: "x-iscii-ta - ISCII Tamil",
57005: "x-iscii-te - ISCII Telugu",
57006: "x-iscii-as - ISCII Assamese",
57007: "x-iscii-or - ISCII Oriya",
57008: "x-iscii-ka - ISCII Kannada",
57009: "x-iscii-ma - ISCII Malayalam",
57010: "x-iscii-gu - ISCII Gujarati",
57011: "x-iscii-pa - ISCII Punjabi",
65000: "utf-7 - Unicode (UTF-7)",
65001: "utf-8 - Unicode (UTF-8)",
}
... ...
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"errors"
)
// MakeVariant is defined in vectorArray.go. It calls Evaluate, which refers to the MakeTypes map, so must add at runtime
func init() { MakeTypes[VT_VARIANT] = MakeVariant }
var (
ErrType = errors.New("msoleps: error coercing byte stream to type")
ErrUnknownType = errors.New("msoleps: unknown type error")
)
type Type interface {
String() string
Type() string
Length() int
}
const (
vector uint16 = iota + 1
array
)
func Evaluate(b []byte) (Type, error) {
if len(b) < 4 {
return I1(0), ErrType
}
id := TypeID(binary.LittleEndian.Uint16(b[:2]))
f, ok := MakeTypes[id]
if !ok {
return I1(0), ErrUnknownType
}
switch binary.LittleEndian.Uint16(b[2:4]) {
case vector:
return MakeVector(f, b[4:])
case array:
return MakeArray(f, b[4:])
}
return f(b[4:])
}
type TypeID uint16
const (
VT_EMPTY TypeID = iota // 0x00
VT_NULL
VT_I2
VT_I4
VT_R4
VT_R8
VT_CY
VT_DATE
VT_BSTR
_
VT_ERROR
VT_BOOL
VT_VARIANT
_
VT_DECIMAL
_
VT_I1
VT_U1
VT_UI2
VT_UI4
VT_I8
VT_UI8
VT_INT
VT_UINT //0x17
_ = iota + 5
VT_LPSTR //0x1E
VT_LPWSTR
VT_FILETIME = iota + 0x25 // 0x40
VT_BLOB
VT_STREAM
VT_STORAGE
VT_STREAMED_OBJECT
VT_STORED_OBJECT
VT_BLOB_OBJECT
VT_CF
VT_CLSID
VT_VERSIONED_STREAM // 0x49
)
type MakeType func([]byte) (Type, error)
var MakeTypes map[TypeID]MakeType = map[TypeID]MakeType{
VT_I2: MakeI2,
VT_I4: MakeI4,
VT_R4: MakeR4,
VT_R8: MakeR8,
VT_CY: MakeCurrency,
VT_DATE: MakeDate,
VT_BSTR: MakeCodeString,
VT_BOOL: MakeBool,
VT_DECIMAL: MakeDecimal,
VT_I1: MakeI1,
VT_U1: MakeUI1,
VT_UI2: MakeUI2,
VT_UI4: MakeUI4,
VT_I8: MakeI8,
VT_UI8: MakeUI8,
VT_INT: MakeI4,
VT_UINT: MakeUI4,
VT_LPSTR: MakeCodeString,
VT_LPWSTR: MakeUnicode,
VT_FILETIME: MakeFileTime,
VT_CLSID: MakeGuid,
}
// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
"errors"
)
// MakeVariant is defined in vectorArray.go. It calls Evaluate, which refers to the MakeTypes map, so must add at runtime
func init() { MakeTypes[VT_VARIANT] = MakeVariant }
var (
ErrType = errors.New("msoleps: error coercing byte stream to type")
ErrUnknownType = errors.New("msoleps: unknown type error")
)
type Type interface {
String() string
Type() string
Length() int
}
const (
vector uint16 = iota + 1
array
)
func Evaluate(b []byte) (Type, error) {
if len(b) < 4 {
return I1(0), ErrType
}
id := TypeID(binary.LittleEndian.Uint16(b[:2]))
f, ok := MakeTypes[id]
if !ok {
return I1(0), ErrUnknownType
}
switch binary.LittleEndian.Uint16(b[2:4]) {
case vector:
return MakeVector(f, b[4:])
case array:
return MakeArray(f, b[4:])
}
return f(b[4:])
}
type TypeID uint16
const (
VT_EMPTY TypeID = iota // 0x00
VT_NULL
VT_I2
VT_I4
VT_R4
VT_R8
VT_CY
VT_DATE
VT_BSTR
_
VT_ERROR
VT_BOOL
VT_VARIANT
_
VT_DECIMAL
_
VT_I1
VT_U1
VT_UI2
VT_UI4
VT_I8
VT_UI8
VT_INT
VT_UINT //0x17
_ = iota + 5
VT_LPSTR //0x1E
VT_LPWSTR
VT_FILETIME = iota + 0x25 // 0x40
VT_BLOB
VT_STREAM
VT_STORAGE
VT_STREAMED_OBJECT
VT_STORED_OBJECT
VT_BLOB_OBJECT
VT_CF
VT_CLSID
VT_VERSIONED_STREAM // 0x49
)
type MakeType func([]byte) (Type, error)
var MakeTypes map[TypeID]MakeType = map[TypeID]MakeType{
VT_I2: MakeI2,
VT_I4: MakeI4,
VT_R4: MakeR4,
VT_R8: MakeR8,
VT_CY: MakeCurrency,
VT_DATE: MakeDate,
VT_BSTR: MakeCodeString,
VT_BOOL: MakeBool,
VT_DECIMAL: MakeDecimal,
VT_I1: MakeI1,
VT_U1: MakeUI1,
VT_UI2: MakeUI2,
VT_UI4: MakeUI4,
VT_I8: MakeI8,
VT_UI8: MakeUI8,
VT_INT: MakeI4,
VT_UINT: MakeUI4,
VT_LPSTR: MakeCodeString,
VT_LPWSTR: MakeUnicode,
VT_FILETIME: MakeFileTime,
VT_CLSID: MakeGuid,
}
... ...
// Copyright 2015 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
)
type Vector []Type
func (v Vector) String() string {
return ""
}
func (v Vector) Type() string {
if len(v) > 0 {
return "Vector of " + v[0].Type()
}
return "Vector (empty)"
}
func (v Vector) Length() int {
ret := 4
for _, t := range v {
ret += t.Length()
}
return ret
}
func MakeVector(f MakeType, b []byte) (Type, error) {
if len(b) < 4 {
return Vector{}, ErrType
}
l := int(binary.LittleEndian.Uint32(b[:4]))
v := make(Vector, l)
place := 4
for i := 0; i < l; i++ {
t, err := f(b[place:])
if err != nil {
return Vector{}, ErrType
}
v[i] = t
place += t.Length()
}
return v, nil
}
type Array [][]Type
func (a Array) String() string {
return ""
}
func (a Array) Type() string {
if len(a) > 0 && len(a[0]) > 0 {
return "Array of " + a[0][0].Type()
}
return "Array (empty)"
}
func (a Array) Length() int {
return 0
}
func MakeArray(f MakeType, b []byte) (Type, error) {
return Array{}, nil
}
type Variant struct {
t Type
}
func (v Variant) String() string {
return "Typed Property Value containing " + v.t.String()
}
func (v Variant) Type() string {
return "Typed Property Value containing " + v.t.Type()
}
func (v Variant) Length() int {
return 4 + v.t.Length()
}
func MakeVariant(b []byte) (Type, error) {
t, err := Evaluate(b)
if err != nil {
return Variant{}, err
}
return Variant{t}, nil
}
// Copyright 2015 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"encoding/binary"
)
type Vector []Type
func (v Vector) String() string {
return ""
}
func (v Vector) Type() string {
if len(v) > 0 {
return "Vector of " + v[0].Type()
}
return "Vector (empty)"
}
func (v Vector) Length() int {
ret := 4
for _, t := range v {
ret += t.Length()
}
return ret
}
func MakeVector(f MakeType, b []byte) (Type, error) {
if len(b) < 4 {
return Vector{}, ErrType
}
l := int(binary.LittleEndian.Uint32(b[:4]))
v := make(Vector, l)
place := 4
for i := 0; i < l; i++ {
t, err := f(b[place:])
if err != nil {
return Vector{}, ErrType
}
v[i] = t
place += t.Length()
}
return v, nil
}
type Array [][]Type
func (a Array) String() string {
return ""
}
func (a Array) Type() string {
if len(a) > 0 && len(a[0]) > 0 {
return "Array of " + a[0][0].Type()
}
return "Array (empty)"
}
func (a Array) Length() int {
return 0
}
func MakeArray(f MakeType, b []byte) (Type, error) {
return Array{}, nil
}
type Variant struct {
t Type
}
func (v Variant) String() string {
return "Typed Property Value containing " + v.t.String()
}
func (v Variant) Type() string {
return "Typed Property Value containing " + v.t.Type()
}
func (v Variant) Length() int {
return 4 + v.t.Length()
}
func MakeVariant(b []byte) (Type, error) {
t, err := Evaluate(b)
if err != nil {
return Variant{}, err
}
return Variant{t}, nil
}
... ...
... ... @@ -3,9 +3,6 @@
github.com/360EntSecGroup-Skylar/excelize/v2
# github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798
github.com/DataDog/zstd
# github.com/GeeTeam/gt3-golang-sdk v0.0.0-20200116043922-446ca8a507d2
## explicit
github.com/GeeTeam/gt3-golang-sdk/geetest
# github.com/Shopify/sarama v1.23.1
## explicit
github.com/Shopify/sarama
... ...