//////////////////////////////////////////////////////////////////////////
// Реализация чтения DwgProps для AutoCAD 2004...2016 (возможно и дальше,
// если сохранится структура dwg-файла).
//////////////////////////////////////////////////////////////////////////
#include <io.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <malloc.h>
#include <stdlib.h>
#include <vector>
#include <string>
//
// Имена стандартных свойств чертежа
//
const char *stdPropNames[] = {
"title",
"subject",
"author",
"keywords",
"comments",
"lastSavedBy",
"revisionNumber",
"hyperlinkBase"
};
class DwgProps
{
struct record {
WORD len;
union {
char c[32767];
wchar_t w[32767];
};
};
public:
DwgProps() {
for (int i=0; i < sizeof(stdPropNames)/sizeof(stdPropNames[0]); i++) {
m_stdProps.push_back("");
}
memset(bTotalEditingTime,0,sizeof(bTotalEditingTime));
memset(bCreateDateTime,0,sizeof(bCreateDateTime));
memset(bModifiedDateTime,0,sizeof(bModifiedDateTime));
};
~DwgProps() {}
// data items
const char *title() const {return m_stdProps[0].c_str(); }
const char *subject() const {return m_stdProps[1].c_str(); }
const char *author() const {return m_stdProps[2].c_str(); }
const char *keywords() const {return m_stdProps[3].c_str(); }
const char *comments() const {return m_stdProps[4].c_str(); }
const char *lastSavedBy() const {return m_stdProps[5].c_str(); }
const char *revisionNumber() const {return m_stdProps[6].c_str(); }
const char *hyperlinkBase() const {return m_stdProps[7].c_str(); }
const char *customName(int idx) const {
return ((idx >= 0 && idx < (int)m_custPropNames.size())?m_custPropNames[idx].c_str():0);
}
const char *customValue(int idx) const {
return ((idx >= 0 && idx < (int)m_custPropValues.size())?m_custPropValues[idx].c_str():0);
}
const char *customValue(const char *name) const {
for (int i=0; i < (int)m_custPropNames.size(); i++) {
if (m_custPropNames[i] == name) return m_custPropValues[i].c_str();
}
return 0;
}
int customNumber() const { return (int) m_custPropNames.size(); }
ULONG inDwg() { return ReadDiffDate(bTotalEditingTime); }
SYSTEMTIME created() { return ReadDate(bCreateDateTime); }
SYSTEMTIME updated() { return ReadDate(bModifiedDateTime); }
const void DateToString(char *buf, SYSTEMTIME tm)
{
sprintf( buf,
"%d-%02d-%02d %02d:%02d:%02d.%03d",
tm.wYear, tm.wMonth, tm.wDay,
tm.wHour, tm.wMinute, tm.wSecond, tm.wMilliseconds);
}
const void DiffDateToString(char *buf, ULONG tDiff)
{
int days = tDiff / (24*60*60*1000);
tDiff -= days * (24*60*60*1000);
int hours = tDiff / (60*60*1000);
tDiff -= hours * (60*60*1000);
int minutes = tDiff / (60*1000);
tDiff -= minutes * (60*1000);
int seconds = tDiff / 1000;
tDiff -= seconds * (1000);
int mseconds = tDiff;
sprintf( buf,
"Days:%d Hours:%d Minutes:%d Seconds:%d Milliseconds:%d",
days, hours, minutes, seconds, mseconds);
}
int load(const char * fname)
{
bool unicode = false;
int h;
char buf[32767]; memset(buf,0,sizeof(buf));
if ((h = _open(fname,_O_BINARY|_O_RDONLY)) == -1)
return 0;
char ACADVER[7];
if (_read(h,ACADVER,sizeof(ACADVER)) <= 0) {
_close(h); return 0;
}
if (atoi(ACADVER+2) < 1018) { // AutoCAD R14,2000...2002 обрабатывать не будем
_close(h); return 0;
}
if (atoi(ACADVER+2) >= 1021) { // AutoCAD 2007... строки в Unicode
unicode = true;
}
// Указатель перемещаем на WORD, содержащий смещение DwgProps
if (_lseek(h,0x20,SEEK_SET) == -1) {
_close(h); return 0;
}
// Считываем смещение DwgProps
WORD offset_dwgprops = 0;
if (_read(h,&offset_dwgprops,sizeof(offset_dwgprops)) <= 0) {
_close(h); return 0;
}
long begin_offset = offset_dwgprops, cur_offset = offset_dwgprops;
// Устанавливаем указатель на начало DwgProps
if (_lseek(h,offset_dwgprops,SEEK_SET) == -1) {
_close(h); return 0;
}
// Теперь можно читать длины и сами строки:
record rec;
for (int i=0; i < sizeof(stdPropNames)/sizeof(stdPropNames[0]); i++) {
if (_read(h,&rec,sizeof(record)) == -1) {
_close(h); return 0;
}
if (unicode) {
WideCharToMultiByte(CP_ACP,0,rec.w,rec.len,buf,rec.len,0,NULL);
m_stdProps[i] = buf;
} else {
m_stdProps[i] = rec.c;
}
cur_offset += (rec.len*((unicode)?2:1) + sizeof(rec.len));
if (_lseek(h,cur_offset,SEEK_SET) == -1) {
_close(h); return 0;
}
}
if (_read(h,&bTotalEditingTime,sizeof(bTotalEditingTime)) == -1) {
_close(h); return 0;
}
if (_read(h,&bCreateDateTime,sizeof(bCreateDateTime)) == -1) {
_close(h); return 0;
}
if (_read(h,&bModifiedDateTime,sizeof(bModifiedDateTime)) == -1) {
_close(h); return 0;
}
cur_offset += (sizeof(bTotalEditingTime)+ sizeof(bCreateDateTime) + sizeof(bModifiedDateTime));
if (_lseek(h,cur_offset,SEEK_SET) == -1) {
_close(h); return 0;
}
// Читаем количество собственных (custom) переменных
WORD nCust = 0;
if (_read(h,&nCust,sizeof(nCust)) <= 0) { _close(h); return 0; }
cur_offset += sizeof(WORD);
for (int i=0; i < nCust; i++) {
// Считываем имя переменной
if (_read(h,&rec,sizeof(record)) == -1) {_close(h); return 0;}
if (unicode) {
WideCharToMultiByte(CP_ACP,0,rec.w,rec.len,buf,rec.len,0,NULL);
m_custPropNames.push_back(buf);
} else {
m_custPropNames.push_back(rec.c);
}
cur_offset += (rec.len*((unicode)?2:1) + sizeof(rec.len));
if (_lseek(h,cur_offset,SEEK_SET) == -1) {
_close(h); return 0;
}
if (_read(h,&rec,sizeof(record)) == -1) {_close(h); return 0;}
if (unicode) {
WideCharToMultiByte(CP_ACP,0,rec.w,rec.len,buf,rec.len,0,NULL);
m_custPropValues.push_back(buf);
} else {
m_custPropValues.push_back(rec.c);
}
cur_offset += (rec.len*((unicode)?2:1) + sizeof(rec.len));
if (_lseek(h,cur_offset,SEEK_SET) == -1) {_close(h); return 0;}
}
_close(h);
return 1;
}
private:
// data
std::vector<std::string> m_stdProps;
std::vector<std::string> m_custPropNames;
std::vector<std::string> m_custPropValues;
byte bTotalEditingTime[8];
byte bCreateDateTime[8];
byte bModifiedDateTime[8];
SYSTEMTIME minDate, maxDate;
//
// Преобразование даты/времени из юлианского календаря
//
SYSTEMTIME FromJulian(ULONG days)
{
FILETIME fmin = {0, 0} , fmax = {0x7fffffff, 0xffffffff} ;
FileTimeToSystemTime(&fmin, &minDate); FileTimeToSystemTime(&fmax, &maxDate);
SYSTEMTIME s; memset(&s,0,sizeof(s));
if (days < 0x1a4452) return minDate;
if (days > 0x51fe2c) return maxDate;
int j = days + 32044;
int g = j / 146097;
int dg = j % 146097;
int c = (((dg / 36524) + 1) * 3) / 4;
int dc = dg - (c * 36524);
int b = dc / 1461;
int db = dc % 1461;
int a = (((db / 365) + 1) * 3) / 4;
int da = db - (a * 365);
int y = (((g * 400) + (c * 100)) + (b * 4)) + a;
int m = (((da * 5) + 308) / 153) - 2;
int d = (da - (((m + 4) * 153) / 5)) + 0x7a;
int year = (y - 4800) + ((m + 2) / 12);
int month = ((m + 2) % 12) + 1;
int day = d + 1;
s.wYear = year;
s.wMonth = month;
s.wDay = day;
s.wHour = 2;
s.wMinute = 0;
s.wSecond = 0;
s.wDayOfWeek = 0;
s.wMilliseconds = 0;
return s;
}
//
// Добавление дробной части (миллисекунд)
//
SYSTEMTIME addMilliSecs(SYSTEMTIME s, double mseconds) {
FILETIME f; SystemTimeToFileTime(&s, &f);
ULARGE_INTEGER u;
memcpy(&u, &f, sizeof(u));
ULONGLONG mmsec = mseconds * 10000;
u.QuadPart += mmsec;
memcpy(&f, &u, sizeof(f));
FileTimeToSystemTime(&f, &s);
return s;
}
//
// Чтение даты/времени
//
const SYSTEMTIME ReadDate(byte *src)
{
ULONG days = *((ULONG *)(src)); src += 4;
ULONG fraction = *((ULONG *)(src)); src += 4;
SYSTEMTIME tm = FromJulian(days);
if (tm.wYear == maxDate.wYear)
return tm;
return addMilliSecs(tm,fraction);
}
//
// Чтение интервала редактирования
//
const ULONG ReadDiffDate(byte* src)
{
ULONG days = *((ULONG *)(src)); src += 4;
ULONG fraction = *((ULONG *)(src)); src += 4;
ULONG diff = days * 24 * 60 * 60 * 1000 + fraction;
return diff;
}
};
////-----------------------------------------
//// Пример использования класса DwgProps
////-----------------------------------------
//#include "stdafx.h"
//#include <conio.h>
//#include <stdio.h>
//#include <string.h>
//#include <wtypes.h>
//#include <time.h>
//#include "DwgProps.h"
//
//
//const char * valid(const char *s)
//{
// return s ? s : "";
//}
//
//void main(int argc, char *argv[])
//{
// DwgProps p;
//
// if ( argc < 2 )
// {
// fprintf(stderr, "Usage: dwgprops file [file ...]\n");
// return;
// }
//
// // loop over files
// for ( int f = 1; f < argc; f++ )
// {
// printf("%s\n", argv[f]);
//
// if ( p.load(argv[f]) )
// {
// // print list of tags
// printf(" Title: [%s]\n", valid(p.title()));
// printf(" Subject: [%s]\n", valid(p.subject()));
// printf(" Author: [%s]\n", valid(p.author()));
// printf(" Comments: [%s]\n", valid(p.comments()));
// printf(" Keywords: [%s]\n", valid(p.keywords()));
// printf(" HyperlinkBase: [%s]\n", valid(p.hyperlinkBase()));
// printf(" LastSavedBy: [%s]\n", valid(p.lastSavedBy()));
// printf(" RevisionNo.: [%s]\n", valid(p.revisionNumber()));
// char buffer[ 256 ];
// p.DiffDateToString(buffer, p.inDwg());
// printf(" Edit time: %s\n", buffer);
// p.DateToString(buffer, p.created());
// printf(" Created: [%s]\n", buffer);
// p.DateToString(buffer, p.updated());
// printf(" Updated: [%s]\n", buffer);
// for ( int i = 0; i < p.customNumber(); i++ ) {
// printf(" Custom Name[%d]: [%s]\n", i, valid(p.customName(i)));
// printf(" Custom Value[%d]: [%s]\n", i, valid(p.customValue(i)));
// }
// }
// }
//}