HRESULT CHeader::Parse(const Byte *p) { UInt32 haderSize = Get32(p + 8); if (haderSize < 0x74) return S_FALSE; Version = Get32(p + 0x0C); Flags = Get32(p + 0x10); if (!IsSupported()) return S_FALSE; UInt32 chunkSize = Get32(p + 0x14); if (chunkSize != kChunkSize && chunkSize != 0) return S_FALSE; memcpy(Guid, p + 0x18, 16); PartNumber = Get16(p + 0x28); NumParts = Get16(p + 0x2A); int offset = 0x2C; if (IsNewVersion()) { NumImages = Get32(p + offset); offset += 4; } GetResource(p + offset, OffsetResource); GetResource(p + offset + 0x18, XmlResource); GetResource(p + offset + 0x30, MetadataResource); /* if (IsNewVersion()) { if (haderSize < 0xD0) return S_FALSE; IntegrityResource.Parse(p + offset + 0x4C); BootIndex = Get32(p + 0x48); } */ return S_OK; }
void Assert16(const char *title, u16 x, u16 y) { u16 resx = Get16(); u16 resy = Get16(); if (resx != x || resy != y) { assertFailed_ = true; printf("%s: Failed %d, %d != expected %d, %d\n", title, resx, resy, x, y); } }
/* * For use by other reformatters: find a specific resource. * * Returns "true" on success, "false" on failure. */ /*static*/ bool ReformatResourceFork::GetResource(const uint8_t* srcBuf, long srcLen, uint16_t resourceType, uint32_t resourceID, const uint8_t** pResource, long* pResourceLen) { /* read the file header */ long rFileVersion, rFileToMap, rFileMapSize; bool littleEndian; bool result; result = ReadHeader(srcBuf, srcLen, &rFileVersion, &rFileToMap, &rFileMapSize, &littleEndian); if (!result) return false; /* move to start of resource map */ const uint8_t* mapPtr; long mapToIndex, mapIndexSize, mapIndexUsed; mapPtr = srcBuf + rFileToMap; mapToIndex = Get16(mapPtr + 0x0e, littleEndian); mapIndexSize = Get32(mapPtr + 0x14, littleEndian); mapIndexUsed = Get32(mapPtr + 0x18, littleEndian); /* find the appropriate entry */ const uint8_t* indexPtr = mapPtr + mapToIndex; int i; for (i = 0; i < mapIndexSize; i++) { uint16_t resType; uint32_t resID; resType = Get16(indexPtr + 0x00, littleEndian); if (resType == 0) break; // should happen when i == mapIndexUsed resID = Get32(indexPtr + 0x02, littleEndian); if (resType == resourceType && resID == resourceID) { LOGI("Found resource with type=0x%04x id=0x%04x", resType, resID); *pResource = srcBuf + Get32(indexPtr + 0x06, littleEndian); *pResourceLen = Get32(indexPtr + 0x0c, littleEndian); if (*pResource + *pResourceLen > srcBuf+srcLen) { LOGI(" Bad bounds on resource"); DebugBreak(); return false; } return true; } indexPtr += kRsrcMapEntryLen; } LOGI("Resource not found (type=0x%04x id=0x%04x)", resourceType, resourceID); return false; }
static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size, const UString &prefix, CObjectVector<CItem> &items) { for (;;) { if (pos + 8 > size) return S_FALSE; const Byte *p = base + pos; UInt64 length = Get64(p); if (length == 0) return S_OK; if (pos + 102 > size || pos + length + 8 > size || length > ((UInt64)1 << 62)) return S_FALSE; CItem item; item.Attrib = Get32(p + 8); // item.SecurityId = Get32(p + 0xC); UInt64 subdirOffset = Get64(p + 0x10); GetFileTimeFromMem(p + 0x28, &item.CTime); GetFileTimeFromMem(p + 0x30, &item.ATime); GetFileTimeFromMem(p + 0x38, &item.MTime); memcpy(item.Hash, p + 0x40, kHashSize); // UInt16 shortNameLen = Get16(p + 98); UInt16 fileNameLen = Get16(p + 100); size_t tempPos = pos + 102; if (tempPos + fileNameLen > size) return S_FALSE; wchar_t *sz = item.Name.GetBuffer(prefix.Length() + fileNameLen / 2 + 1); MyStringCopy(sz, (const wchar_t *)prefix); sz += prefix.Length(); for (UInt16 i = 0; i + 2 <= fileNameLen; i += 2) *sz++ = Get16(base + tempPos + i); *sz++ = '\0'; item.Name.ReleaseBuffer(); if (fileNameLen == 0 && item.isDir() && !item.HasStream()) { item.Attrib = 0x10; // some swm archives have system/hidden attributes for root item.Name.Delete(item.Name.Length() - 1); } items.Add(item); pos += (size_t)length; if (item.isDir() && (subdirOffset != 0)) { if (subdirOffset >= size) return S_FALSE; RINOK(ParseDirItem(base, (size_t)subdirOffset, size, item.Name + WCHAR_PATH_SEPARATOR, items)); } } }
static void GetStream(const Byte *p, CStreamInfo &s) { s.Resource.Parse(p); s.PartNumber = Get16(p + 24); s.RefCount = Get32(p + 26); memcpy(s.Hash, p + 30, kHashSize); }
bool CInArchive::ReadLocalItem(CItemEx &item) { const unsigned kPureHeaderSize = kLocalHeaderSize - 4; Byte p[kPureHeaderSize]; SafeReadBytes(p, kPureHeaderSize); { unsigned i; for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); if (i == kPureHeaderSize) return false; } item.ExtractVersion.Version = p[0]; item.ExtractVersion.HostOS = p[1]; item.Flags = Get16(p + 2); item.Method = Get16(p + 4); item.Time = Get32(p + 6); item.Crc = Get32(p + 10); item.PackSize = Get32(p + 14); item.Size = Get32(p + 18); unsigned nameSize = Get16(p + 22); unsigned extraSize = Get16(p + 24); ReadFileName(nameSize, item.Name); item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize; /* if (item.IsDir()) item.Size = 0; // check It */ if (extraSize > 0) { UInt64 localHeaderOffset = 0; UInt32 diskStartNumber = 0; if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, localHeaderOffset, diskStartNumber)) return false; } if (!CheckDosTime(item.Time)) { HeadersWarning = true; // return false; } if (item.Name.Len() != nameSize) return false; return item.LocalFullHeaderSize <= ((UInt32)1 << 16); }
HRESULT CHandler::Open2(IInStream *stream) { UInt64 archiveStartPos; RINOK(stream->Seek(0, STREAM_SEEK_SET, &archiveStartPos)); const UInt32 kHeaderSize = 0x1C; Byte buf[kHeaderSize]; RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)); UInt32 size = Get16(buf + 4); // UInt32 ver = Get16(buf + 6); // == 0 if (Get32(buf) != 0x78617221 || size != kHeaderSize) return S_FALSE; UInt64 packSize = Get64(buf + 8); UInt64 unpackSize = Get64(buf + 0x10); // UInt32 checkSumAlogo = Get32(buf + 0x18); if (unpackSize >= kXmlSizeMax) return S_FALSE; _dataStartPos = archiveStartPos + kHeaderSize + packSize; char *ss = _xml.GetBuffer((int)unpackSize + 1); NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec; CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> inStreamLim(inStreamLimSpec); inStreamLimSpec->SetStream(stream); inStreamLimSpec->Init(packSize); CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream; CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec); outStreamLimSpec->Init((Byte *)ss, (size_t)unpackSize); RINOK(zlibCoder->Code(inStreamLim, outStreamLim, NULL, NULL, NULL)); if (outStreamLimSpec->GetPos() != (size_t)unpackSize) return S_FALSE; ss[(size_t)unpackSize] = 0; _xml.ReleaseBuffer(); CXml xml; if (!xml.Parse(_xml)) return S_FALSE; if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1) return S_FALSE; const CXmlItem &toc = xml.Root.SubItems[0]; if (!toc.IsTagged("toc")) return S_FALSE; if (!AddItem(toc, _files, -1)) return S_FALSE; return S_OK; }
HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit) { m_CryptoMode = false; RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition)); m_Position = m_StreamStartPosition; UInt64 arcStartPos; RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize, searchHeaderSizeLimit, arcStartPos)); m_Position = arcStartPos + NHeader::kMarkerSize; RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1]; RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize)); AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize); UInt32 blockSize = Get16(buf + 5); _header.EncryptVersion = 0; _header.Flags = Get16(buf + 3); UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize; if (_header.IsThereEncryptVer()) { if (blockSize <= headerSize) return S_FALSE; RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1)); AddToSeekValue(1); _header.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize]; headerSize += 1; } if (blockSize < headerSize || buf[2] != NHeader::NBlockType::kArchiveHeader || (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF)) return S_FALSE; size_t commentSize = blockSize - headerSize; _comment.SetCapacity(commentSize); RINOK(ReadStream_FALSE(stream, _comment, commentSize)); AddToSeekValue(commentSize); m_Stream = stream; _header.StartPosition = arcStartPos; return S_OK; }
HRESULT CTag::Parse(const Byte *buf, size_t size) { if (size < 16) return S_FALSE; Byte sum = 0; int i; for (i = 0; i < 4; i++) sum = (Byte)(sum + buf[i]); for (i = 5; i < 16; i++) sum = (Byte)(sum + buf[i]); if (sum != buf[4] || buf[5] != 0) return S_FALSE; Id = Get16(buf); Version = Get16(buf + 2); // SerialNumber = Get16(buf + 6); UInt16 crc = Get16(buf + 8); UInt16 crcLen = Get16(buf + 10); // TagLocation = Get32(buf + 12); if (size >= 16 + (size_t)crcLen) if (crc == Crc16Calc(buf + 16, crcLen)) return S_OK; return S_FALSE; }
bool CReparseShortInfo::Parse(const Byte *p, size_t size) { const Byte *start = p; Offset= 0; Size = 0; if (size < 8) return false; UInt32 Tag = Get32(p); UInt32 len = Get16(p + 4); if (len + 8 > size) return false; /* if ((type & kReparseFlags_Alias) == 0 || (type & kReparseFlags_Microsoft) == 0 || (type & 0xFFFF) != 3) */ if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT && Tag != _my_IO_REPARSE_TAG_SYMLINK) // return true; return false; if (Get16(p + 6) != 0) // padding return false; p += 8; size -= 8; if (len != size) // do we need that check? return false; if (len < 8) return false; unsigned subOffs = Get16(p); unsigned subLen = Get16(p + 2); unsigned printOffs = Get16(p + 4); unsigned printLen = Get16(p + 6); len -= 8; p += 8; // UInt32 Flags = 0; if (Tag == _my_IO_REPARSE_TAG_SYMLINK) { if (len < 4) return false; // Flags = Get32(p); len -= 4; p += 4; } if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) return false; if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) return false; Offset = (unsigned)(p - start) + subOffs; Size = subLen; return true; }
//-------------------------------------------------------------------------- // Evaluate number, be it int, rational, or float from directory. //-------------------------------------------------------------------------- double CExifParse::ConvertAnyFormat(const void* const ValuePtr, int Format) { double Value; Value = 0; switch(Format) { case FMT_SBYTE: Value = *(const signed char*)ValuePtr; break; case FMT_BYTE: Value = *(const unsigned char*)ValuePtr; break; case FMT_USHORT: Value = Get16(ValuePtr, m_MotorolaOrder); break; case FMT_ULONG: Value = (unsigned)Get32(ValuePtr, m_MotorolaOrder); break; case FMT_URATIONAL: case FMT_SRATIONAL: { int Num,Den; Num = Get32(ValuePtr, m_MotorolaOrder); Den = Get32(4+(const char *)ValuePtr, m_MotorolaOrder); if (Den == 0) Value = 0; else Value = (double)Num/Den; } break; case FMT_SSHORT: Value = (signed short)Get16(ValuePtr, m_MotorolaOrder); break; case FMT_SLONG: Value = Get32(ValuePtr, m_MotorolaOrder); break; // Not sure if this is correct (never seen float used in Exif format) case FMT_SINGLE: Value = (double)*(const float*)ValuePtr; break; case FMT_DOUBLE: Value = *(const double*)ValuePtr; break; default: ErrNonfatal("Illegal format code %d",Format,0); } return Value; }
static bool ParseUtf16zString(const Byte *p, UInt32 size, UString &res) { if ((size & 1) != 0) return false; res.Empty(); UInt32 i; for (i = 0; i < size; i += 2) { wchar_t c = Get16(p + i); if (c == 0) break; res += c; } return (i == size - 2); }
bool CReparseAttr::Parse(const Byte *p, size_t size) { if (size < 8) return false; Tag = Get32(p); UInt32 len = Get16(p + 4); if (len + 8 > size) return false; /* if ((type & kReparseFlags_Alias) == 0 || (type & kReparseFlags_Microsoft) == 0 || (type & 0xFFFF) != 3) */ if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT && Tag != _my_IO_REPARSE_TAG_SYMLINK) // return true; return false; if (Get16(p + 6) != 0) // padding return false; p += 8; size -= 8; if (len != size) // do we need that check? return false; if (len < 8) return false; unsigned subOffs = Get16(p); unsigned subLen = Get16(p + 2); unsigned printOffs = Get16(p + 4); unsigned printLen = Get16(p + 6); len -= 8; p += 8; Flags = 0; if (Tag == _my_IO_REPARSE_TAG_SYMLINK) { if (len < 4) return false; Flags = Get32(p); len -= 4; p += 4; } if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) return false; if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) return false; GetString(p + subOffs, subLen >> 1, SubsName); GetString(p + printOffs, printLen >> 1, PrintName); return true; }
HRESULT CInArchive::ReadCdItem(CItemEx &item) { item.FromCentral = true; Byte p[kCentralHeaderSize - 4]; SafeReadBytes(p, kCentralHeaderSize - 4); item.MadeByVersion.Version = p[0]; item.MadeByVersion.HostOS = p[1]; item.ExtractVersion.Version = p[2]; item.ExtractVersion.HostOS = p[3]; item.Flags = Get16(p + 4); item.Method = Get16(p + 6); item.Time = Get32(p + 8); item.Crc = Get32(p + 12); item.PackSize = Get32(p + 16); item.Size = Get32(p + 20); unsigned nameSize = Get16(p + 24); UInt16 extraSize = Get16(p + 26); UInt16 commentSize = Get16(p + 28); UInt32 diskNumberStart = Get16(p + 30); item.InternalAttrib = Get16(p + 32); item.ExternalAttrib = Get32(p + 34); item.LocalHeaderPos = Get32(p + 38); ReadFileName(nameSize, item.Name); if (extraSize > 0) { ReadExtra(extraSize, item.CentralExtra, item.Size, item.PackSize, item.LocalHeaderPos, diskNumberStart); } if (diskNumberStart != 0) return E_NOTIMPL; // May be these strings must be deleted /* if (item.IsDir()) item.Size = 0; */ ReadBuffer(item.Comment, commentSize); return S_OK; }
void CInByte2::ReadString(UString &s) { const Byte *buf = _buffer + _pos; size_t rem = (_size - _pos) / 2 * 2; { size_t i; for (i = 0; i < rem; i += 2) if (buf[i] == 0 && buf[i + 1] == 0) break; if (i == rem) ThrowEndOfData(); rem = i; } int len = (int)(rem / 2); if (len < 0 || (size_t)len * 2 != rem) ThrowUnsupported(); wchar_t *p = s.GetBuffer(len); int i; for (i = 0; i < len; i++, buf += 2) p[i] = (wchar_t)Get16(buf); s.ReleaseBuffer(len); _pos += rem + 2; }
//-------------------------------------------------------------------------- // Process a EXIF marker // Describes all the drivel that most digital cameras include... //-------------------------------------------------------------------------- bool CExifParse::Process (const unsigned char* const ExifSection, const unsigned short length, ExifInfo_t *info) { m_ExifInfo = info; // EXIF signature: "Exif\0\0" // Check EXIF signatures const char ExifHeader[] = "Exif\0\0"; const char ExifAlignment0[] = "II"; const char ExifAlignment1[] = "MM"; const char ExifExtra = 0x2a; const char* pos = (const char*)(ExifSection + sizeof(short)); // position data pointer after length field if (memcmp(pos, ExifHeader,6)) { printf("ExifParse: incorrect Exif header"); return false; } pos += 6; if (memcmp(pos, ExifAlignment0, strlen(ExifAlignment0)) == 0) { m_MotorolaOrder = false; } else if (memcmp(pos, ExifAlignment1, strlen(ExifAlignment1)) == 0) { m_MotorolaOrder = true; } else { printf("ExifParse: invalid Exif alignment marker"); return false; } pos += strlen(ExifAlignment0); // Check the next value for correctness. if (Get16((const void*)(pos), m_MotorolaOrder) != ExifExtra) { printf("ExifParse: invalid Exif start (1)"); return false; } pos += sizeof(short); unsigned long FirstOffset = (unsigned)Get32((const void*)pos, m_MotorolaOrder); if (FirstOffset < 8 || FirstOffset > 16) { // Usually set to 8, but other values valid too. // CLog::Log(LOGERROR, "ExifParse: suspicious offset of first IFD value"); } // First directory starts 16 bytes in. All offset are relative to 8 bytes in. ProcessDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0); m_ExifInfo->ThumbnailAtEnd = m_ExifInfo->ThumbnailOffset >= m_LargestExifOffset; // Compute the CCD width, in millimeters. if (m_FocalPlaneXRes != 0) { // Note: With some cameras, its not possible to compute this correctly because // they don't adjust the indicated focal plane resolution units when using less // than maximum resolution, so the CCDWidth value comes out too small. Nothing // that Jhead can do about it - its a camera problem. m_ExifInfo->CCDWidth = (float)(m_ExifImageWidth * m_FocalPlaneUnits / m_FocalPlaneXRes); } if (m_ExifInfo->FocalLength) { if (m_ExifInfo->FocalLength35mmEquiv == 0) { // Compute 35 mm equivalent focal length based on sensor geometry if we haven't // already got it explicitly from a tag. if (m_ExifInfo->CCDWidth != 0.0) { m_ExifInfo->FocalLength35mmEquiv = (int)(m_ExifInfo->FocalLength/m_ExifInfo->CCDWidth*36 + 0.5); } } } return true; }
void CLogBlockAddr::Parse(const Byte *buf) { Pos = Get32(buf); PartitionRef = Get16(buf + 4); }
/* * Split a resource fork into its individual resources, and display them. */ int ReformatResourceFork::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcBuf = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); fUseRTF = false; long rFileVersion, rFileToMap, rFileMapSize; bool littleEndian; bool result; result = ReadHeader(srcBuf, srcLen, &rFileVersion, &rFileToMap, &rFileMapSize, &littleEndian); BufPrintf("Resource fork header (%s):\r\n", littleEndian ? "Apple IIgs little-endian" : "Macintosh big-endian"); BufPrintf(" rFileVersion = %d\r\n", rFileVersion); BufPrintf(" rFileToMap = 0x%08lx\r\n", rFileToMap); BufPrintf(" rFileMapSize = %ld\r\n", rFileMapSize); BufPrintf(" rFileMemo:\r\n"); BufHexDump(srcBuf+12, 128); BufPrintf("\r\n"); if (rFileVersion != 0) { BufPrintf("Not an Apple IIgs resource fork (probably Macintosh).\r\n"); goto done; } if (!result) { BufPrintf("Does not appear to be a valid resource fork.\r\n"); goto done; } /* move to start of resource map */ const uint8_t* mapPtr; long mapToIndex, mapIndexSize, mapIndexUsed; mapPtr = srcBuf + rFileToMap; mapToIndex = Get16(mapPtr + 0x0e, littleEndian); mapIndexSize = Get32(mapPtr + 0x14, littleEndian); mapIndexUsed = Get32(mapPtr + 0x18, littleEndian); BufPrintf("Resource map:\r\n"); BufPrintf(" mapToIndex = 0x%04x (file offset=0x%08lx)\n", mapToIndex, mapToIndex + rFileToMap); BufPrintf(" mapIndexSize = %ld\r\n", mapIndexSize); BufPrintf(" mapIndexUsed = %ld\r\n", mapIndexUsed); BufPrintf(" mapFreeListSize = %ld\r\n", Get16(mapPtr + 0x1c, littleEndian)); BufPrintf(" mapFreeListUsed = %ld\r\n", Get16(mapPtr + 0x1e, littleEndian)); /* dump contents of resource reference records */ const uint8_t* indexPtr; BufPrintf("\r\nResources:"); indexPtr = mapPtr + mapToIndex; int i; for (i = 0; i < mapIndexSize; i++) { uint16_t resType = Get16(indexPtr + 0x00, littleEndian); if (resType == 0) break; // should happen when i == mapIndexUsed const char* typeDescr; if (resType >= 0x8000 && resType < 0x8000 + NELEM(kRsrc8000)) typeDescr = kRsrc8000[resType - 0x8000]; else if (resType >= 0xc000 && resType < 0xc000 + NELEM(kRsrcC000)) typeDescr = kRsrcC000[resType - 0xc000]; else if (resType >= 0x0001 && resType <= 0x7fff) typeDescr = "(application-defined resource)"; else typeDescr = kUnknownSysRsrc; BufPrintf("\r\n Entry #%d:\r\n", i); BufPrintf(" resType = 0x%04x - %s\r\n", resType, typeDescr); BufPrintf(" resID = 0x%04x\r\n", Get32(indexPtr + 0x02, littleEndian)); BufPrintf(" resOffset = 0x%04x\r\n", Get32(indexPtr + 0x06, littleEndian)); BufPrintf(" resAttr = 0x%04x\r\n", Get16(indexPtr + 0x0a, littleEndian)); BufPrintf(" resSize = 0x%04x\r\n", Get32(indexPtr + 0x0c, littleEndian)); //BufPrintf(" resHandle = 0x%04x\r\n", // Get32(indexPtr + 0x10, littleEndian)); BufHexDump(srcBuf + Get32(indexPtr + 0x06, littleEndian), Get32(indexPtr + 0x0c, littleEndian)); indexPtr += kRsrcMapEntryLen; } done: SetResultBuffer(pOutput); return 0; }
UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeReadBytes(buf, 2); return Get16(buf); }
void CCdInfo::ParseEcd(const Byte *p) { NumEntries = Get16(p + 10); Size = Get32(p + 12); Offset = Get32(p + 16); }
//-------------------------------------------------------------------------- // Process one of the nested EXIF directories. //-------------------------------------------------------------------------- void CExifParse::ProcessDir(const unsigned char* const DirStart, const unsigned char* const OffsetBase, const unsigned ExifLength, int NestingLevel) { if (NestingLevel > 4) { ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0); return; } char IndentString[25]; memset(IndentString, ' ', 25); IndentString[NestingLevel * 4] = '\0'; int NumDirEntries = Get16((const void*)DirStart, m_MotorolaOrder); const unsigned char* const DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries); if (DirEnd+4 > (OffsetBase+ExifLength)) { if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength) { // Version 1.3 of jhead would truncate a bit too much. // This also caught later on as well. } else { ErrNonfatal("Illegally sized directory", 0,0); return; } } for (int de=0;de<NumDirEntries;de++) { int Tag, Format, Components; unsigned char* ValuePtr; int ByteCount; const unsigned char* const DirEntry = DIR_ENTRY_ADDR(DirStart, de); Tag = Get16(DirEntry, m_MotorolaOrder); Format = Get16(DirEntry+2, m_MotorolaOrder); Components = Get32(DirEntry+4, m_MotorolaOrder); if (Format <= 0 || Format > NUM_FORMATS) { ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag); continue; } if ((unsigned)Components > 0x10000) { ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag); continue; } ByteCount = Components * BytesPerFormat[Format - 1]; if (ByteCount > 4) { unsigned OffsetVal; OffsetVal = (unsigned)Get32(DirEntry+8, m_MotorolaOrder); // If its bigger than 4 bytes, the dir entry contains an offset. if (OffsetVal+ByteCount > ExifLength) { // Bogus pointer offset and / or bytecount value ErrNonfatal("Illegal value pointer for tag %04x", Tag,0); continue; } ValuePtr = (unsigned char*)(const_cast<unsigned char*>(OffsetBase)+OffsetVal); if (OffsetVal > m_LargestExifOffset) { m_LargestExifOffset = OffsetVal; } } else { // 4 bytes or less and value is in the dir entry itself ValuePtr = (unsigned char*)(const_cast<unsigned char*>(DirEntry)+8); } // Extract useful components of tag switch(Tag) { case TAG_DESCRIPTION: { int length = max(ByteCount, 0); length = min(length, MAX_COMMENT); strncpy(m_ExifInfo->Description, (char *)ValuePtr, length); m_ExifInfo->Description[length] = '\0'; break; } case TAG_MAKE: { int space = sizeof(m_ExifInfo->CameraMake); if (space > 0) { strncpy(m_ExifInfo->CameraMake, (char *)ValuePtr, space - 1); m_ExifInfo->CameraMake[space - 1] = '\0'; } break; } case TAG_MODEL: { int space = sizeof(m_ExifInfo->CameraModel); if (space > 0) { strncpy(m_ExifInfo->CameraModel, (char *)ValuePtr, space - 1); m_ExifInfo->CameraModel[space - 1] = '\0'; } break; } // case TAG_SOFTWARE: strncpy(m_ExifInfo->Software, ValuePtr, 5); break; case TAG_FOCALPLANEXRES: m_FocalPlaneXRes = ConvertAnyFormat(ValuePtr, Format); break; case TAG_THUMBNAIL_OFFSET: m_ExifInfo->ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); break; case TAG_THUMBNAIL_LENGTH: m_ExifInfo->ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); break; case TAG_MAKER_NOTE: continue; break; case TAG_DATETIME_ORIGINAL: { int space = sizeof(m_ExifInfo->DateTime); if (space > 0) { strncpy(m_ExifInfo->DateTime, (char *)ValuePtr, space - 1); m_ExifInfo->DateTime[space - 1] = '\0'; // If we get a DATETIME_ORIGINAL, we use that one. m_DateFound = true; } break; } case TAG_DATETIME_DIGITIZED: case TAG_DATETIME: { if (!m_DateFound) { // If we don't already have a DATETIME_ORIGINAL, use whatever // time fields we may have. int space = sizeof(m_ExifInfo->DateTime); if (space > 0) { strncpy(m_ExifInfo->DateTime, (char *)ValuePtr, space - 1); m_ExifInfo->DateTime[space - 1] = '\0'; } } break; } case TAG_USERCOMMENT: { // The UserComment allows comments without the charset limitations of ImageDescription. // Therefore the UserComment field is prefixed by a CharacterCode field (8 Byte): // - ASCII: 'ASCII\0\0\0' // - Unicode: 'UNICODE\0' // - JIS X208-1990: 'JIS\0\0\0\0\0' // - Unknown: '\0\0\0\0\0\0\0\0' (application specific) m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_UNKNOWN; const int EXIF_COMMENT_CHARSET_LENGTH = 8; if (ByteCount >= EXIF_COMMENT_CHARSET_LENGTH) { // As some implementations use spaces instead of \0 for the padding, // we're not so strict and check only the prefix. if (memcmp(ValuePtr, "ASCII", 5) == 0) m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_ASCII; else if (memcmp(ValuePtr, "UNICODE", 7) == 0) m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_UNICODE; else if (memcmp(ValuePtr, "JIS", 3) == 0) m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_JIS; int length = ByteCount - EXIF_COMMENT_CHARSET_LENGTH; length = min(length, MAX_COMMENT); memcpy(m_ExifInfo->Comments, ValuePtr + EXIF_COMMENT_CHARSET_LENGTH, length); m_ExifInfo->Comments[length] = '\0'; // FixComment(comment); // Ensure comment is printable } } break; case TAG_XP_COMMENT: { // The XP user comment field is always unicode (UCS-2) encoded m_ExifInfo->XPCommentsCharset = EXIF_COMMENT_CHARSET_UNICODE; size_t length = min(ByteCount, MAX_COMMENT); memcpy(m_ExifInfo->XPComment, ValuePtr, length); m_ExifInfo->XPComment[length] = '\0'; } break; case TAG_FNUMBER: // Simplest way of expressing aperture, so I trust it the most. // (overwrite previously computd value if there is one) m_ExifInfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_APERTURE: case TAG_MAXAPERTURE: // More relevant info always comes earlier, so only use this field if we don't // have appropriate aperture information yet. if (m_ExifInfo->ApertureFNumber == 0) { m_ExifInfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5); } break; case TAG_FOCALLENGTH: // Nice digital cameras actually save the focal length as a function // of how far they are zoomed in. m_ExifInfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_SUBJECT_DISTANCE: // Inidcates the distacne the autofocus camera is focused to. // Tends to be less accurate as distance increases. { float distance = (float)ConvertAnyFormat(ValuePtr, Format); m_ExifInfo->Distance = distance; } break; case TAG_EXPOSURETIME: { // Simplest way of expressing exposure time, so I trust it most. // (overwrite previously computd value if there is one) float expTime = (float)ConvertAnyFormat(ValuePtr, Format); if (expTime) m_ExifInfo->ExposureTime = expTime; } break; case TAG_SHUTTERSPEED: // More complicated way of expressing exposure time, so only use // this value if we don't already have it from somewhere else. if (m_ExifInfo->ExposureTime == 0) { m_ExifInfo->ExposureTime = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0))); } break; case TAG_FLASH: m_ExifInfo->FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_ORIENTATION: m_ExifInfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format); if (m_ExifInfo->Orientation < 0 || m_ExifInfo->Orientation > 8) { ErrNonfatal("Undefined rotation value %d", m_ExifInfo->Orientation, 0); m_ExifInfo->Orientation = 0; } break; case TAG_EXIF_IMAGELENGTH: case TAG_EXIF_IMAGEWIDTH: // Use largest of height and width to deal with images that have been // rotated to portrait format. { int a = (int)ConvertAnyFormat(ValuePtr, Format); if (m_ExifImageWidth < a) m_ExifImageWidth = a; } break; case TAG_FOCALPLANEUNITS: switch((int)ConvertAnyFormat(ValuePtr, Format)) { // According to the information I was using, 2 means meters. // But looking at the Cannon powershot's files, inches is the only // sensible value. case 1: m_FocalPlaneUnits = 25.4; break; // inch case 2: m_FocalPlaneUnits = 25.4; break; case 3: m_FocalPlaneUnits = 10; break; // centimeter case 4: m_FocalPlaneUnits = 1; break; // millimeter case 5: m_FocalPlaneUnits = .001; break; // micrometer } break; case TAG_EXPOSURE_BIAS: m_ExifInfo->ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_WHITEBALANCE: m_ExifInfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_LIGHT_SOURCE: //Quercus: 17-1-2004 Added LightSource, some cams return this, whitebalance or both m_ExifInfo->LightSource = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_METERING_MODE: m_ExifInfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_EXPOSURE_PROGRAM: m_ExifInfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_EXPOSURE_INDEX: if (m_ExifInfo->ISOequivalent == 0) { // Exposure index and ISO equivalent are often used interchangeably, // so we will do the same. // http://photography.about.com/library/glossary/bldef_ei.htm m_ExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); } break; case TAG_ISO_EQUIVALENT: m_ExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); if (m_ExifInfo->ISOequivalent < 50) m_ExifInfo->ISOequivalent *= 200; // Fixes strange encoding on some older digicams. break; case TAG_EXPOSURE_MODE: m_ExifInfo->ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_DIGITALZOOMRATIO: m_ExifInfo->DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_EXIF_OFFSET: case TAG_INTEROP_OFFSET: { const unsigned char* const SubdirStart = OffsetBase + (unsigned)Get32(ValuePtr, m_MotorolaOrder); if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) { ErrNonfatal("Illegal exif or interop ofset directory link",0,0); } else { ProcessDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); } continue; } break; case TAG_GPSINFO: { const unsigned char* const SubdirStart = OffsetBase + (unsigned)Get32(ValuePtr, m_MotorolaOrder); if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) { ErrNonfatal("Illegal GPS directory link",0,0); } else { ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength); } continue; } break; case TAG_FOCALLENGTH_35MM: // The focal length equivalent 35 mm is a 2.2 tag (defined as of April 2002) // if its present, use it to compute equivalent focal length instead of // computing it from sensor geometry and actual focal length. m_ExifInfo->FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format); break; } } // In addition to linking to subdirectories via exif tags, // there's also a potential link to another directory at the end of each // directory. this has got to be the result of a committee! unsigned Offset; if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength) { Offset = (unsigned)Get32(DirStart+2+12*NumDirEntries, m_MotorolaOrder); if (Offset) { const unsigned char* const SubdirStart = OffsetBase + Offset; if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase) { if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20) { // Jhead 1.3 or earlier would crop the whole directory! // As Jhead produces this form of format incorrectness, // I'll just let it pass silently } else { ErrNonfatal("Illegal subdirectory link",0,0); } } else { if (SubdirStart <= OffsetBase+ExifLength) { ProcessDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); } } if (Offset > m_LargestExifOffset) { m_LargestExifOffset = Offset; } } } else { // The exif header ends before the last next directory pointer. } if (m_ExifInfo->ThumbnailOffset) { m_ExifInfo->ThumbnailAtEnd = false; if (m_ExifInfo->ThumbnailOffset <= ExifLength) { if (m_ExifInfo->ThumbnailSize > ExifLength - m_ExifInfo->ThumbnailOffset) { // If thumbnail extends past exif header, only save the part that // actually exists. Canon's EOS viewer utility will do this - the // thumbnail extracts ok with this hack. m_ExifInfo->ThumbnailSize = ExifLength - m_ExifInfo->ThumbnailOffset; } } } }
API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) { if (size < 8) return k_IsArc_Res_NEED_MORE; if (p[0] != 'P') return k_IsArc_Res_NO; UInt32 value = Get32(p); if (value == NSignature::kNoSpan) { p += 4; size -= 4; } value = Get32(p); if (value == NSignature::kEcd) { if (size < kEcdSize) return k_IsArc_Res_NEED_MORE; CEcd ecd; ecd.Parse(p + 4); // if (ecd.cdSize != 0) if (!ecd.IsEmptyArc()) return k_IsArc_Res_NO; return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; } if (value != NSignature::kLocalFileHeader) return k_IsArc_Res_NO; if (size < kLocalHeaderSize) return k_IsArc_Res_NEED_MORE; p += 4; { const unsigned kPureHeaderSize = kLocalHeaderSize - 4; unsigned i; for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); if (i == kPureHeaderSize) return k_IsArc_Res_NEED_MORE; } /* if (p[0] >= 128) // ExtractVersion.Version; return k_IsArc_Res_NO; */ // ExtractVersion.Version = p[0]; // ExtractVersion.HostOS = p[1]; // Flags = Get16(p + 2); // Method = Get16(p + 4); /* // 9.33: some zip archives contain incorrect value in timestamp. So we don't check it now UInt32 dosTime = Get32(p + 6); if (!CheckDosTime(dosTime)) return k_IsArc_Res_NO; */ // Crc = Get32(p + 10); // PackSize = Get32(p + 14); // Size = Get32(p + 18); unsigned nameSize = Get16(p + 22); unsigned extraSize = Get16(p + 24); UInt32 extraOffset = kLocalHeaderSize + (UInt32)nameSize; if (extraOffset + extraSize > (1 << 16)) return k_IsArc_Res_NO; p -= 4; { size_t rem = size - kLocalHeaderSize; if (rem > nameSize) rem = nameSize; const Byte *p2 = p + kLocalHeaderSize; for (size_t i = 0; i < rem; i++) if (p2[i] == 0) return k_IsArc_Res_NO; } if (size < extraOffset) return k_IsArc_Res_NEED_MORE; if (extraSize > 0) { p += extraOffset; size -= extraOffset; while (extraSize != 0) { if (extraSize < 4) { // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers. // so we return k_IsArc_Res_YES to support such archives. // return k_IsArc_Res_NO; // do we need to support such extra ? return k_IsArc_Res_YES; } if (size < 4) return k_IsArc_Res_NEED_MORE; unsigned dataSize = Get16(p + 2); size -= 4; extraSize -= 4; p += 4; if (dataSize > extraSize) return k_IsArc_Res_NO; if (dataSize > size) return k_IsArc_Res_NEED_MORE; size -= dataSize; extraSize -= dataSize; p += dataSize; } } return k_IsArc_Res_YES; }
//-------------------------------------------------------------------------- // Process GPS info directory //-------------------------------------------------------------------------- void CExifParse::ProcessGpsInfo( const unsigned char* const DirStart, int ByteCountUnused, const unsigned char* const OffsetBase, unsigned ExifLength) { int NumDirEntries = Get16(DirStart, m_MotorolaOrder); for (int de=0;de<NumDirEntries;de++) { const unsigned char* DirEntry = DIR_ENTRY_ADDR(DirStart, de); unsigned Tag = Get16(DirEntry, m_MotorolaOrder); unsigned Format = Get16(DirEntry+2, m_MotorolaOrder); unsigned Components = (unsigned)Get32(DirEntry+4, m_MotorolaOrder); if (Format == 0 || Format > NUM_FORMATS) { ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag); continue; } unsigned ComponentSize = BytesPerFormat[Format - 1]; unsigned ByteCount = Components * ComponentSize; const unsigned char* ValuePtr; if (ByteCount > 4) { unsigned OffsetVal = (unsigned)Get32(DirEntry+8, m_MotorolaOrder); // If its bigger than 4 bytes, the dir entry contains an offset. if (OffsetVal+ByteCount > ExifLength) { // Bogus pointer offset and / or bytecount value ErrNonfatal("Illegal value pointer for tag %04x", Tag,0); continue; } ValuePtr = OffsetBase+OffsetVal; } else { // 4 bytes or less and value is in the dir entry itself ValuePtr = DirEntry+8; } switch(Tag) { case TAG_GPS_LAT_REF: m_ExifInfo->GpsLat[0] = ValuePtr[0]; m_ExifInfo->GpsLat[1] = 0; break; case TAG_GPS_LONG_REF: m_ExifInfo->GpsLong[0] = ValuePtr[0]; m_ExifInfo->GpsLong[1] = 0; break; case TAG_GPS_LAT: GetLatLong(Format, ValuePtr, ComponentSize, m_ExifInfo->GpsLat); break; case TAG_GPS_LONG: GetLatLong(Format, ValuePtr, ComponentSize, m_ExifInfo->GpsLong); break; case TAG_GPS_ALT_REF: if (ValuePtr[0] != 0) m_ExifInfo->GpsAlt[0] = '-'; m_ExifInfo->GpsAlt[1] = 0; break; case TAG_GPS_ALT: { char temp[18]; sprintf(temp,"%dm", Get32(ValuePtr, m_MotorolaOrder)); strcat(m_ExifInfo->GpsAlt, temp); } break; } } }
int8 KismetExecuteEvent(int16 _DeviceID,int8 _EventID) { int8 a;//variable for the kismet blocks to use int8 read8; int16 read16; int16 eventaddr; int16 methodaddr; int16 BlockAddr; int16 timeout; if(!OperationEnabled)return 1;//return if no operating is allowed //ToSendDataBuffer[2]=((int8*)&_DeviceID)[0]; //ToSendDataBuffer[3]=((int8*)&_DeviceID)[1]; //ToSendDataBuffer[4]=_EventID; MemoryBeginRead(EEPROMHEADERSIZE); for(timeout=0;timeout<1024;timeout++) { read16=MemoryReadInt16(); eventaddr =MemoryReadInt16(); if(read16==_DeviceID)break; if(read16==0xffff) { MemoryEndRead(); return 2; } } MemoryEndRead(); MemoryBeginRead(eventaddr); for(timeout=0;timeout<1024;timeout++) { read8=MemoryReadInt8(); methodaddr=MemoryReadInt16(); if(read8==_EventID)break; if(read8==0xff) { MemoryEndRead(); return 3; } } MemoryEndRead(); //ToSendDataBuffer[12]=((int8*)&eventaddr)[0]; //ToSendDataBuffer[13]=((int8*)&eventaddr)[1]; //ToSendDataBuffer[14]=((int8*)&methodaddr)[0]; //ToSendDataBuffer[15]=((int8*)&methodaddr)[1]; BlockAddr=methodaddr; MemoryBeginRead(BlockAddr); while(1) { int8 blocktype=MemoryReadInt8(); //#=EEPROM DATA $=REGISTER DATA switch(blocktype) { case 0x00://end of code default://or we dont understand it { MemoryEndRead(); return 0; } case 0x01://load literal int16 { int8 reg =MemoryReadInt8(); int16 value =MemoryReadInt16(); Set16(reg,value); }break; case 0x02://load literal int8 { int8 reg =MemoryReadInt8(); int8 value =MemoryReadInt8(); Set8(reg,value); }break; case 0x0B://equal { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,(Get16(reg1)==Get16(reg2))?0xffff:0); }break; case 0x0C://differ { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,(Get16(reg1)!=Get16(reg2))?0xffff:0); }break; case 0x0D://and { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,Get16(reg1)&Get16(reg2)); }break; case 0x0E://or { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,Get16(reg1)|Get16(reg2)); }break; case 0x0F://xor { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,Get16(reg1)^Get16(reg2)); }break; case 0x20://add { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,Get16(reg1)+Get16(reg2)); }break; case 0x21://sub { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,Get16(reg1)-Get16(reg2)); }break; case 0x22://mul { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,Get16(reg1)*Get16(reg2)); }break; case 0x23://div { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 reg3 =MemoryReadInt8(); Set16(reg3,Get16(reg1)/Get16(reg2)); }break; case 0x30://hours { int8 reg1 =MemoryReadInt8(); Set16(reg1,(int16)RTCHour); }break; case 0x31://minutes { int8 reg1 =MemoryReadInt8(); Set16(reg1,(int16)RTCMinute); }break; case 0x32://seconds { int8 reg1 =MemoryReadInt8(); Set16(reg1,(int16)RTCSecond); }break; case 0x33://days { int8 reg1 =MemoryReadInt8(); Set16(reg1,(int16)RTCDay); }break; case 0x0A://Set LED { int8 reg =MemoryReadInt8(); //Set16(reg,1); SetLED(Get16(reg)); }break; case 0x80:// $if goto $here? { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); if(Get16(reg1)==0) { BlockAddr=methodaddr+(int16)reg2; MemoryEndRead();MemoryBeginRead(BlockAddr); } }break; case 0x70://mov { int8 reg1 =MemoryReadInt8(); int8 reg2 =MemoryReadInt8(); int8 amnt =MemoryReadInt8(); for(a=0;a<amnt;a++) Set8(reg2+a,Get8(reg1+a)); }break; case 0x71://EPSend { int16 dev =MemoryReadInt16(); EPBufferSize=MemoryReadInt8(); //try three times if(EPSend(dev))break; if(EPSend(dev))break; if(EPSend(dev))break; }break; case 0x90://Set Delay { int8 timer =MemoryReadInt8(); int8 event =MemoryReadInt8(); int8 reg =MemoryReadInt8(); int16 time=Get16(reg); SetTimer(timer,event,time); }break; } } return 4; }