Пример #1
0
/*static*/ off_t
AVFormatWriter::_Seek(void* cookie, off_t offset, int whence)
{
	TRACE_IO("AVFormatWriter::_Seek(%p, %lld, %d)\n",
		cookie, offset, whence);

	AVFormatWriter* writer = reinterpret_cast<AVFormatWriter*>(cookie);

	BPositionIO* positionIO = dynamic_cast<BPositionIO*>(writer->fTarget);
	if (positionIO == NULL)
		return -1;

	// Support for special file size retrieval API without seeking anywhere:
	if (whence == AVSEEK_SIZE) {
		off_t size;
		if (positionIO->GetSize(&size) == B_OK)
			return size;
		return -1;
	}

	off_t position = positionIO->Seek(offset, whence);
	TRACE_IO("  position: %lld\n", position);
	if (position < 0)
		return -1;

	return position;
}
Пример #2
0
/*static*/ status_t
FSUtils::CompareFileContent(BPositionIO& content1, BPositionIO& content2,
                            bool& _equal)
{
    // get and compare content size
    off_t size1;
    status_t error = content1.GetSize(&size1);
    if (error != B_OK)
        return error;

    off_t size2;
    error = content2.GetSize(&size2);
    if (error != B_OK)
        return error;

    if (size1 != size2) {
        _equal = false;
        return B_OK;
    }

    if (size1 == 0) {
        _equal = true;
        return B_OK;
    }

    // allocate a data buffer
    uint8* buffer1 = new(std::nothrow) uint8[2 * kCompareDataBufferSize];
    if (buffer1 == NULL)
        return B_NO_MEMORY;
    ArrayDeleter<uint8> bufferDeleter(buffer1);
    uint8* buffer2 = buffer1 + kCompareDataBufferSize;

    // compare the data
    off_t offset = 0;
    while (offset < size1) {
        size_t toCompare = std::min(size_t(size1 - offset),
                                    kCompareDataBufferSize);
        ssize_t bytesRead = content1.ReadAt(offset, buffer1, toCompare);
        if (bytesRead < 0)
            return bytesRead;
        if ((size_t)bytesRead != toCompare)
            return B_ERROR;

        bytesRead = content2.ReadAt(offset, buffer2, toCompare);
        if (bytesRead < 0)
            return bytesRead;
        if ((size_t)bytesRead != toCompare)
            return B_ERROR;

        if (memcmp(buffer1, buffer2, toCompare) != 0) {
            _equal = false;
            return B_OK;
        }

        offset += bytesRead;
    }

    _equal = true;
    return B_OK;
}
/* static */ int
WebPTranslator::_EncodedWriter(const uint8_t* data, size_t dataSize,
	const WebPPicture* const picture)
{
	BPositionIO* target = (BPositionIO*)picture->custom_ptr;
	return dataSize ? (target->Write(data, dataSize) == (ssize_t)dataSize) : 1;
}
Пример #4
0
void
TiffUintField::LoadByte(IFDEntry &entry, BPositionIO &io, swap_action swp)
{
	// Make certain there is enough memory
	// before trying to do anything else
	fpByte = new uint8[entry.count];
	if (!fpByte) {
		finitStatus = B_NO_MEMORY;
		return;
	}
	
	if (entry.count <= 4) {
		// If all of the byte values can fit into the
		// IFD entry value bytes
		memcpy(fpByte, entry.bytevals, entry.count);
		finitStatus = B_OK;		
	} else {
	
		// entry.count > 4, use longval to find offset for byte data
		if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
			finitStatus = B_ERROR;
		else {
			ssize_t read;
			read = io.ReadAt(entry.longval, fpByte, entry.count);
			if (read != static_cast<ssize_t>(entry.count))
				finitStatus = B_IO_ERROR;
			else
				finitStatus = B_OK;
		}
		
	}
}
Пример #5
0
SharedBitmap::SharedBitmap(BPositionIO& data)
	:
	BReferenceable(),
	fResourceID(-1),
	fBuffer(NULL),
	fSize(0),
	fMimeType()
{
	status_t status = data.GetSize(&fSize);
	const off_t kMaxSize = 1024 * 1024;
	if (status == B_OK && fSize > 0 && fSize <= kMaxSize) {
		fBuffer = new(std::nothrow) uint8[fSize];
		if (fBuffer != NULL) {
			data.Seek(0, SEEK_SET);
			
			off_t bytesRead = 0;
			size_t chunkSize = std::min((off_t)4096, fSize);
			while (bytesRead < fSize) {
				ssize_t read = data.Read(fBuffer + bytesRead, chunkSize);
				if (read > 0)
					bytesRead += read;
				else
					break;
			}
	
			if (bytesRead != fSize) {
				delete[] fBuffer;
				fBuffer = NULL;
				fSize = 0;
			}
		} else
			fSize = 0;
	} else {
		fprintf(stderr, "SharedBitmap(): Stream too large: %" B_PRIi64
			", max: %" B_PRIi64 "\n", fSize, kMaxSize);
	}

	fBitmap[0] = NULL;
	fBitmap[1] = NULL;
	fBitmap[2] = NULL;
}
Пример #6
0
status_t 
MusePackReader::Sniff(int32 *_streamCount)
{
	BPositionIO *file = dynamic_cast<BPositionIO *>(Source());
	if (file == NULL)
		// we cannot handle non seekable files for now
		return B_ERROR;

	file->Seek(0, SEEK_SET);
	int error = fInfo.ReadStreamInfo(file);
	if (error > B_OK) {
		// error came from engine
		TRACE("MusePackReader: ReadStreamInfo() engine error %d\n", error);
		return B_ERROR;
	} else if (error < B_OK)
		return error;

	TRACE("MusePackReader: recognized MPC file\n");
	*_streamCount = 1;
	return B_OK;
}
Пример #7
0
// read_exactly
static
void
read_exactly(BPositionIO& file, off_t position, void* buffer, size_t size,
			 const char* errorMessage = NULL)
{
	ssize_t read = file.ReadAt(position, buffer, size);
	if (read < 0)
		throw Exception(read, errorMessage);
	else if ((size_t)read != size) {
		if (errorMessage) {
			throw Exception("%s Read to few bytes (%ld/%lu).", errorMessage,
							read, size);
		} else
			throw Exception("Read to few bytes (%ld/%lu).", read, size);
	}
}
Пример #8
0
static BPositionIO *
get_seekable(BDataIO * data)
{
	// try to cast to BPositionIO then perform a series of
	// sanity checks to ensure that seeking is reliable
	BPositionIO * seekable = dynamic_cast<BPositionIO *>(data);
	if (seekable == 0) {
		return 0;
	}
	// first try to get our current location
	off_t current = seekable->Seek(0, SEEK_CUR);
	if (current < 0) {
		return 0;
	}
	// check it against position
	if (current != seekable->Position()) {
		return 0;
	}
	// next try to seek to our current location (absolutely)
	if (seekable->Seek(current, SEEK_SET) < 0) {
		return 0;
	}
	// next try to seek to the start of the stream (absolutely)
	if (seekable->Seek(0, SEEK_SET) < 0) {
		return 0;
	}
	// then seek back to where we started
	if (seekable->Seek(current, SEEK_SET) < 0) {
		// really screwed
		return 0;
	}
	// next try to seek to the end of the stream (absolutely)
	if (seekable->Seek(0, SEEK_END) < 0) {
		return 0;
	}
	// then seek back to where we started
	if (seekable->Seek(current, SEEK_SET) < 0) {
		// really screwed
		return 0;
	}
	return seekable;
}
Пример #9
0
void
TiffUintField::LoadShort(IFDEntry &entry, BPositionIO &io, swap_action swp)
{
	// Make certain there is enough memory
	// before trying to do anything else
	fpShort = new uint16[entry.count];
	if (!fpShort) {
		finitStatus = B_NO_MEMORY;
		return;
	}
	
	if (entry.count <= 2) {
		// If all of the byte values can fit into the
		// IFD entry value bytes
		memcpy(fpShort, entry.shortvals, entry.count * 2);
		finitStatus = B_OK;		
	} else {
	
		// entry.count > 2, use longval to find offset for short data
		if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
			finitStatus = B_ERROR;
		else {
			ssize_t read;
			read = io.ReadAt(entry.longval, fpShort, entry.count * 2);
			if (read != static_cast<ssize_t>(entry.count) * 2)
				finitStatus = B_IO_ERROR;
			else
				finitStatus = B_OK;
		}
		
	}
	
	// If short values were successfully read in, swap them to
	// the correct byte order
	if (finitStatus == B_OK &&
		swap_data(B_UINT16_TYPE, fpShort, entry.count * 2, swp) != B_OK)
		finitStatus = B_ERROR;
}
Пример #10
0
void
TiffUintField::LoadLong(IFDEntry &entry, BPositionIO &io, swap_action swp)
{
	// Make certain there is enough memory
	// before trying to do anything else
	fpLong = new uint32[entry.count];
	if (!fpLong) {
		finitStatus = B_NO_MEMORY;
		return;
	}
	
	if (entry.count == 1) {
		fpLong[0] = entry.longval;
		finitStatus = B_OK;		
	} else {
	
		// entry.count > 1, use longval to find offset for long data
		if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
			finitStatus = B_ERROR;
		else {
			ssize_t read;
			read = io.ReadAt(entry.longval, fpLong, entry.count * 4);
			if (read != static_cast<ssize_t>(entry.count) * 4)
				finitStatus = B_IO_ERROR;
			else
				finitStatus = B_OK;
		}
		
	}
	
	// If long values were successfully read in, swap them to
	// the correct byte order
	if (finitStatus == B_OK &&
		swap_data(B_UINT32_TYPE, fpLong, entry.count * 4, swp) != B_OK)
		finitStatus = B_ERROR;
}
Пример #11
0
_EXPORT ssize_t readfoldedline(BPositionIO &in, char **buffer, size_t *buflen)
{
	ssize_t len = buflen && *buflen ? *buflen : 0;
	char * buf = buffer && *buffer ? *buffer : NULL;
	ssize_t cnt = 0; // Number of characters currently in the buffer.
	char c;
	status_t errorCode;

	while (true)
	{
		// Make sure there is space in the buffer for two more characters (one
		// for the next character, and one for the end of string NUL byte).
		if (buf == NULL || cnt + 2 >= len)
		{
			char *temp = (char *)realloc(buf, len + 64);
			if (temp == NULL) {
				// Out of memory, however existing buffer remains allocated.
				cnt = ENOMEM;
				break;
			}
			len += 64;
			buf = temp;
		}

		errorCode = in.Read (&c,1); // A really slow way of reading - unbuffered.
		if (errorCode != 1) {
			if (errorCode < 0) {
				cnt = errorCode; // IO error encountered, just return the code.
			} else {
				// Really is end of file.  Also make it end of line if there is
				// some text already read in.  If the first thing read was EOF,
				// just return an empty string.
				if (cnt > 0) {
					buf[cnt++] = '\n';
					if (buf[cnt-2] == '\r') {
						buf[cnt-2] = '\n';
						--cnt;
					}
				}
			}
			break;
		}

		buf[cnt++] = c;

		if (c == '\n') {
			// Convert CRLF end of line to just a LF.  Do it before folding, in
			// case we don't need to fold.
			if (cnt >= 2 && buf[cnt-2] == '\r') {
				buf[cnt-2] = '\n';
				--cnt;
			}
			// If the current line is empty then return it (so that empty lines
			// don't disappear if the next line starts with a space).
			if (cnt <= 1)
				break;
			// if first character on the next line is whitespace, fold lines
			errorCode = in.Read(&c,1);
			if (errorCode == 1) {
				if (c == ' ' || c == '\t')
					buf[cnt-1] = c; // Replace \n with the white space character.
				else {
					// Not folding, we finished reading a whole line.
					in.Seek(-1,SEEK_CUR); // Undo the look-ahead character read.
					break;
				}
			} else if (errorCode < 0) {
				cnt = errorCode;
				break;
			} else // No next line; at the end of the file.  Return the line.
				break;
		}
	}

	if (buf != NULL && cnt >= 0)
		buf[cnt] = '\0';

	if (buffer)
		*buffer = buf;
	else if (buf)
		free(buf);

	if (buflen)
		*buflen = len;

	return cnt;
}
Пример #12
0
status_t
StreamBase::Seek(uint32 flags, int64* frame, bigtime_t* time)
{
	BAutolock _(fStreamLock);

	if (fContext == NULL || fStream == NULL)
		return B_NO_INIT;

	TRACE_SEEK("StreamBase::Seek(%ld,%s%s%s%s, %lld, "
		"%lld)\n", VirtualIndex(),
		(flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
		(flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
		(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD)
			? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
		(flags & B_MEDIA_SEEK_CLOSEST_FORWARD)
			? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
		*frame, *time);

	double frameRate = FrameRate();
	if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
		// Seeking is always based on time, initialize it when client seeks
		// based on frame.
		*time = (bigtime_t)(*frame * 1000000.0 / frameRate + 0.5);
	}

	int64_t timeStamp = *time;

	int searchFlags = AVSEEK_FLAG_BACKWARD;
	if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0)
		searchFlags = 0;

	if (fSeekByBytes) {
		searchFlags |= AVSEEK_FLAG_BYTE;

		BAutolock _(fSourceLock);
		int64_t fileSize;
		if (fSource->GetSize(&fileSize) != B_OK)
			return B_NOT_SUPPORTED;
		int64_t duration = Duration();
		if (duration == 0)
			return B_NOT_SUPPORTED;

		timeStamp = int64_t(fileSize * ((double)timeStamp / duration));
		if ((flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) != 0) {
			timeStamp -= 65536;
			if (timeStamp < 0)
				timeStamp = 0;
		}

		bool seekAgain = true;
		bool seekForward = true;
		bigtime_t lastFoundTime = -1;
		int64_t closestTimeStampBackwards = -1;
		while (seekAgain) {
			if (avformat_seek_file(fContext, -1, INT64_MIN, timeStamp,
				INT64_MAX, searchFlags) < 0) {
				TRACE("  avformat_seek_file() (by bytes) failed.\n");
				return B_ERROR;
			}
			seekAgain = false;

			// Our last packet is toast in any case. Read the next one so we
			// know where we really seeked.
			fReusePacket = false;
			if (_NextPacket(true) == B_OK) {
				while (fPacket.pts == kNoPTSValue) {
					fReusePacket = false;
					if (_NextPacket(true) != B_OK)
						return B_ERROR;
				}
				if (fPacket.pos >= 0)
					timeStamp = fPacket.pos;
				bigtime_t foundTime
					= _ConvertFromStreamTimeBase(fPacket.pts);
				if (foundTime != lastFoundTime) {
					lastFoundTime = foundTime;
					if (foundTime > *time) {
						if (closestTimeStampBackwards >= 0) {
							timeStamp = closestTimeStampBackwards;
							seekAgain = true;
							seekForward = false;
							continue;
						}
						int64_t diff = int64_t(fileSize
							* ((double)(foundTime - *time) / (2 * duration)));
						if (diff < 8192)
							break;
						timeStamp -= diff;
						TRACE_SEEK("  need to seek back (%lld) (time: %.2f "
							"-> %.2f)\n", timeStamp, *time / 1000000.0,
							foundTime / 1000000.0);
						if (timeStamp < 0)
							foundTime = 0;
						else {
							seekAgain = true;
							continue;
						}
					} else if (seekForward && foundTime < *time - 100000) {
						closestTimeStampBackwards = timeStamp;
						int64_t diff = int64_t(fileSize
							* ((double)(*time - foundTime) / (2 * duration)));
						if (diff < 8192)
							break;
						timeStamp += diff;
						TRACE_SEEK("  need to seek forward (%lld) (time: "
							"%.2f -> %.2f)\n", timeStamp, *time / 1000000.0,
							foundTime / 1000000.0);
						if (timeStamp > duration)
							foundTime = duration;
						else {
							seekAgain = true;
							continue;
						}
					}
				}
				TRACE_SEEK("  found time: %lld -> %lld (%.2f)\n", *time,
					foundTime, foundTime / 1000000.0);
				*time = foundTime;
				*frame = (uint64)(*time * frameRate / 1000000LL + 0.5);
				TRACE_SEEK("  seeked frame: %lld\n", *frame);
			} else {
				TRACE_SEEK("  _NextPacket() failed!\n");
				return B_ERROR;
			}
		}
	} else {
		// We may not get a PTS from the next packet after seeking, so
		// we try to get an expected time from the index.
		int64_t streamTimeStamp = _ConvertToStreamTimeBase(*time);
		int index = av_index_search_timestamp(fStream, streamTimeStamp,
			searchFlags);
		if (index < 0) {
			TRACE("  av_index_search_timestamp() failed\n");
		} else {
			if (index > 0) {
				const AVIndexEntry& entry = fStream->index_entries[index];
				streamTimeStamp = entry.timestamp;
			} else {
				// Some demuxers use the first index entry to store some
				// other information, like the total playing time for example.
				// Assume the timeStamp of the first entry is alays 0.
				// TODO: Handle start-time offset?
				streamTimeStamp = 0;
			}
			bigtime_t foundTime = _ConvertFromStreamTimeBase(streamTimeStamp);
			bigtime_t timeDiff = foundTime > *time
				? foundTime - *time : *time - foundTime;

			if (timeDiff > 1000000
				&& (fStreamBuildsIndexWhileReading
					|| index == fStream->nb_index_entries - 1)) {
				// If the stream is building the index on the fly while parsing
				// it, we only have entries in the index for positions already
				// decoded, i.e. we cannot seek into the future. In that case,
				// just assume that we can seek where we want and leave
				// time/frame unmodified. Since successfully seeking one time
				// will generate index entries for the seeked to position, we
				// need to remember this in fStreamBuildsIndexWhileReading,
				// since when seeking back there will be later index entries,
				// but we still want to ignore the found entry.
				fStreamBuildsIndexWhileReading = true;
				TRACE_SEEK("  Not trusting generic index entry. "
					"(Current count: %d)\n", fStream->nb_index_entries);
			} else {
				// If we found a reasonably time, write it into *time.
				// After seeking, we will try to read the sought time from
				// the next packet. If the packet has no PTS value, we may
				// still have a more accurate time from the index lookup.
				*time = foundTime;
			}
		}

		if (avformat_seek_file(fContext, -1, INT64_MIN, timeStamp, INT64_MAX,
				searchFlags) < 0) {
			TRACE("  avformat_seek_file() failed.\n");
			// Try to fall back to av_seek_frame()
			timeStamp = _ConvertToStreamTimeBase(timeStamp);
			if (av_seek_frame(fContext, fStream->index, timeStamp,
				searchFlags) < 0) {
				TRACE("  avformat_seek_frame() failed as well.\n");
				// Fall back to seeking to the beginning by bytes
				timeStamp = 0;
				if (av_seek_frame(fContext, fStream->index, timeStamp,
						AVSEEK_FLAG_BYTE) < 0) {
					TRACE("  avformat_seek_frame() by bytes failed as "
						"well.\n");
					// Do not propagate error in any case. We fail if we can't
					// read another packet.
				} else
					*time = 0;
			}
		}

		// Our last packet is toast in any case. Read the next one so
		// we know where we really sought.
		bigtime_t foundTime = *time;

		fReusePacket = false;
		if (_NextPacket(true) == B_OK) {
			if (fPacket.pts != kNoPTSValue)
				foundTime = _ConvertFromStreamTimeBase(fPacket.pts);
			else
				TRACE_SEEK("  no PTS in packet after seeking\n");
		} else
			TRACE_SEEK("  _NextPacket() failed!\n");

		*time = foundTime;
		TRACE_SEEK("  sought time: %.2fs\n", *time / 1000000.0);
		*frame = (uint64)(*time * frameRate / 1000000.0 + 0.5);
		TRACE_SEEK("  sought frame: %lld\n", *frame);
	}

	return B_OK;
}
Пример #13
0
void
BHttpRequest::_SendPostData()
{
	if (fRequestMethod == B_HTTP_POST && fOptPostFields != NULL) {
		if (fOptPostFields->GetFormType() != B_HTTP_FORM_MULTIPART) {
			BString outputBuffer = fOptPostFields->RawData();
			_EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT,
				"%s", outputBuffer.String());
			fSocket->Write(outputBuffer.String(), outputBuffer.Length());
		} else {
			for (BHttpForm::Iterator it = fOptPostFields->GetIterator();
				const BHttpFormData* currentField = it.Next();
				) {
				_EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT,
					it.MultipartHeader().String());
				fSocket->Write(it.MultipartHeader().String(),
					it.MultipartHeader().Length());

				switch (currentField->Type()) {
					default:
					case B_HTTPFORM_UNKNOWN:
						ASSERT(0);
						break;

					case B_HTTPFORM_STRING:
						fSocket->Write(currentField->String().String(),
							currentField->String().Length());
						break;

					case B_HTTPFORM_FILE:
						{
							BFile upFile(currentField->File().Path(),
								B_READ_ONLY);
							char readBuffer[kHttpBufferSize];
							ssize_t readSize;

							readSize = upFile.Read(readBuffer,
								sizeof(readBuffer));
							while (readSize > 0) {
								fSocket->Write(readBuffer, readSize);
								readSize = upFile.Read(readBuffer,
									sizeof(readBuffer));
							}

							break;
						}
					case B_HTTPFORM_BUFFER:
						fSocket->Write(currentField->Buffer(),
							currentField->BufferSize());
						break;
				}

				fSocket->Write("\r\n", 2);
			}

			BString footer = fOptPostFields->GetMultipartFooter();
			fSocket->Write(footer.String(), footer.Length());
		}
	} else if ((fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT)
		&& fOptInputData != NULL) {

		// If the input data is seekable, we rewind it for each new request.
		BPositionIO* seekableData
			= dynamic_cast<BPositionIO*>(fOptInputData);
		if (seekableData)
			seekableData->Seek(0, SEEK_SET);

		for (;;) {
			char outputTempBuffer[kHttpBufferSize];
			ssize_t read = fOptInputData->Read(outputTempBuffer,
				sizeof(outputTempBuffer));

			if (read <= 0)
				break;

			if (fOptInputDataSize < 0) {
				// Chunked transfer
				char hexSize[16];
				size_t hexLength = sprintf(hexSize, "%ld", read);

				fSocket->Write(hexSize, hexLength);
				fSocket->Write("\r\n", 2);
				fSocket->Write(outputTempBuffer, read);
				fSocket->Write("\r\n", 2);
			} else {
				fSocket->Write(outputTempBuffer, read);
			}
		}

		if (fOptInputDataSize < 0) {
			// Chunked transfer terminating sequence
			fSocket->Write("0\r\n\r\n", 5);
		}
	}

}
Пример #14
0
static status_t
convert_data_to_bits(pcx_header &header, StreamBuffer &source,
	BPositionIO &target)
{
	uint16 bitsPerPixel = header.bitsPerPixel;
	uint16 bytesPerLine = header.bytesPerLine;
	uint32 width = header.xMax - header.xMin + 1;
	uint32 height = header.yMax - header.yMin + 1;
	uint16 numPlanes = header.numPlanes;
	uint32 scanLineLength = numPlanes * bytesPerLine;

	// allocate buffers
	TempAllocator scanLineAllocator;
	TempAllocator paletteAllocator;
	uint8 *scanLineData[height];
	uint8 *palette = (uint8 *)paletteAllocator.Allocate(3 * 256);
	status_t status = B_OK;

	for (uint32 row = 0; row < height; row++) {
		TRACE("scanline %ld\n", row);
		scanLineData[row] = (uint8 *)scanLineAllocator.Allocate(scanLineLength);
		if (scanLineData[row] == NULL)
			return B_NO_MEMORY;
		uint8 *line = scanLineData[row];
		uint32 index = 0;
		uint8 x;
		do {
			if (source.Read(&x, 1) != 1) {
				status = B_IO_ERROR;
				break;
			}
			if ((x & 0xc0) == 0xc0) {
				uint32 count = x & 0x3f;
				if (index + count - 1 > scanLineLength) {
					status = B_BAD_DATA;
					break;
				}
				if (source.Read(&x, 1) != 1) {
					status = B_IO_ERROR;
					break;
				}
				for (uint32 i = 0; i < count; i++)
					line[index++] = x;
			} else {
				line[index++] = x;
			}
		} while (index < scanLineLength);

		if (status != B_OK) {
			// If we've already read more than a third of the file, display
			// what we have, ie. ignore the error.
			if (row < height / 3)
				return status;

			memset(scanLineData + row, 0, sizeof(uint8*) * (height - row));
			break;
		}
	}

	if (bitsPerPixel == 8 && numPlanes == 1) {
		TRACE("palette reading %p 8\n", palette);
		uint8 x;
		if (status != B_OK || source.Read(&x, 1) != 1 || x != 12) {
			// Try again by repositioning the file stream
			if (source.Seek(-3 * 256 - 1, SEEK_END) < 0)
				return B_BAD_DATA;
			if (source.Read(&x, 1) != 1)
				return B_IO_ERROR;
			if (x != 12)
				return B_BAD_DATA;
		}
		if (source.Read(palette, 256 * 3) != 256 * 3)
			return B_IO_ERROR;
	} else {
		TRACE("palette reading %p palette\n", palette);
		memcpy(palette, &header.paletteInfo, 48);
	}

	uint8 alpha = 255;
	if (bitsPerPixel == 1 && numPlanes == 1) {
		TRACE("target writing 1\n");
		palette[0] = palette[1] = palette[2] = 0;
		palette[3] = palette[4] = palette[5] = 0xff;
		for (uint32 row = 0; row < height; row++) {
			uint8 *line = scanLineData[row];
			if (line == NULL)
				break;
			uint8 mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
			for (uint32 i = 0; i < width; i++) {
				bool isBit = ((line[i >> 3] & mask[i & 7]) != 0) ? true : false;
				target.Write(&palette[!isBit ? 2 : 5], 1);
				target.Write(&palette[!isBit ? 1 : 4], 1);
				target.Write(&palette[!isBit ? 0 : 3], 1);
				target.Write(&alpha, 1);
			}
		}
	} else if (bitsPerPixel == 4 && numPlanes == 1) {
Пример #15
0
void CCellView::Read(BPositionIO& stream)
{
	CSwapStream str(stream);

	scChunk chunk;
	long offset;
	int *funcList, *styleList, *fontList, *formatList;
	int funcCount, styleCount, fontCount, formatCount, borderFont = fBorderFontID;
	bool warnForIncorrectFormula = true;
	scCell cl;

	styleCount = 0;
	styleList = (int *)MALLOC(0);
	fontCount = 0;
	fontList = (int *)MALLOC(0);
	formatCount = 0;
	formatList = (int *)MALLOC(0);
	funcList = NULL;
	
	scCSElement *colStyles = NULL;
	int colStyleCount = 0;

	offset = 0;

	StProgress progress(this, 1, pColorYellow, false);
	StWriteLock lock(fContainer);

	try
	{
		stream.Seek(offset, SEEK_SET);
		
		str >> chunk;

		if (chunk.type == kscVersion)
		{
			scVersion vers;
			str >> vers;
			if (vers.major != 3)
				THROW((errTooNewFileFormat));
		}
		else
			THROW((errUnknownFileFormat, ((CCellWindow *)Window())->EntryRef()->name));

		do
		{
			if (stream.Seek(offset, SEEK_SET) < offset)
			{
				MStopAlert("File is too short").Go();
				break;
			}
			
			str >> chunk;
			offset += 4 + chunk.size;
			
			switch (chunk.type)
			{
				case kscVersion:
					break;
				case kscHeader:
				{
					scHeader head;
					str >> head;
					
					funcList = (int *)CALLOC(head.functionCount, sizeof(int));
					FailNil(funcList);
					funcCount = head.functionCount;
					progress.NewMax(head.cellCount);
					break;
				}
				case kscView:
				{
					scView view;
					str >> view;
					
					if (view.windowRect.left > 0 && view.windowRect.top > 0)
					{
						BRect r;
						{
							r = BScreen().Frame();
						}

						r.InsetBy(4, 4);
						r = r & view.windowRect;
						
						if (r.IsValid() && r.Width() >= 300 && r.Height() >= 100)
						{
							Window()->MoveTo(r.left, r.top);
							Window()->ResizeTo(r.Width(), r.Height());
						}
					}
					if (view.position.h > 0 && view.position.v > 0)
						fPosition = view.position;
					fFrozen = view.frozen;
					if (view.selection.IsValid())
						fSelection = view.selection;
					if (fSelection.Contains(view.curCell))
						fCurCell = view.curCell;
					borderFont = view.headingFont;
					fShowGrid = (view.flags & kscShowGrid) != 0;
					fShowBorders = (view.flags & kscShowHeadings) != 0;
					if (!fShowBorders)
					{
						fCellBounds.left -= fBorderWidth;
						fCellBounds.top -= fBorderHeight;
					}

					Window()->Show();
					Window()->UpdateIfNeeded();
					break;
				}
				case kscPrint:
					break;
				case kscWidths:
				case kscHeights:
				{
					int count = chunk.size/(sizeof(short)*2);
					scWidthElement *elems = (scWidthElement *)MALLOC(chunk.size);
					FailNil(elems);
					
					int k = count * sizeof(scWidthElement);
					stream.Read(elems, k);
					
					if (chunk.type == kscWidths)
						fCellWidths.Read(count, elems);
					else
						fCellHeights.Read(count, elems);

					FREE(elems);
					break;
				}
				case kscColStyles:
				{
					colStyleCount = chunk.size/(sizeof(short)*2);
					colStyles = (scCSElement *)MALLOC(chunk.size);
					FailNil(colStyles);
					
					for (int i = 0; i < colStyleCount; i++)
						str >> colStyles[i];
					break;
				}
				case kscName:
				{
					char buf[50];
					scName *name = (scName *)buf;
					int l = std::min((int)chunk.size, 50);
					
					stream.Read(name, l);

					range r;
					
					memcpy(&r, name->reference+1, sizeof(cell));
					if (name->reference[0] == valRange)
						memcpy(&r.bottom, name->reference+5, sizeof(cell));
					else
						r.BotRight() = r.TopLeft();
					
					swap_order(r);
					
					if (fNames->count(name->name) == 0)
						(*fNames)[CName(name->name)] = r;
					break;
				}
				case kscFunc:
				{
					scFunc func;
					str >> func;
					
					if (!funcList) THROW((errCorruptedFile));
					if (func.funcNr >= funcCount)
						THROW((errCorruptedFile));
					
					funcList[func.funcNr] = GetFunctionNr(func.name);
					if (funcList[func.funcNr] == -1)
						WarnForMissingFunction(func.name);
					break;
				}
				case kscFont:
				{
					scFont font;
					str >> font;
					font_family fam;
					font_style sty;
					
					ReadCString(stream, sizeof(font_style), sty);
					ReadCString(stream, sizeof(font_family), fam);
				
					int *t = (int *)REALLOC(fontList, (fontCount+1)*sizeof(int));
					FailNil(t);
					fontList = t;
					fontList[fontCount] = gFontSizeTable.GetFontID(
						fam, sty, font.size, font.color);
					fontCount++;
					break;
				}
				case kscFormat:
				{
					scFormat format;
					str >> format;
					
					int *t = (int *)REALLOC(formatList, (formatCount+1)*sizeof(int));
					FailNil(t);
					formatList = t;
					
					if (format.nr < eFirstNewFormat)
						formatList[formatCount] = format.nr;
					else
					{
						char fs[256];
						ReadCString(stream, 255, fs);
						formatList[formatCount] = gFormatTable.GetFormatID(fs);
					}
						
					formatCount++;
					break;
				}
				case kscStyle:
				{
					scStyle style;
					str >> style;
					
					int *t = (int *)REALLOC(styleList, (styleCount+1)*sizeof(int));
					FailNil(t);
					styleList = t;
					
					CellStyle cs;

					if (style.font >= fontCount)
						THROW((errCorruptedFile));
					cs.fFont = fontList[style.font];

					if (style.format >= formatCount)
						THROW((errCorruptedFile));
					cs.fFormat = formatList[style.format];

					cs.fAlignment = style.align;
					cs.fLowColor = style.lowColor;
					cs.fLocked = (style.flags & kscLocked) != 0;
					cs.fHidden = (style.flags & kscHidden) != 0;
					
					styleList[styleCount] = gStyleTable.GetStyleID(cs);
					
					styleCount++;
					break;
				}
				case kscCellEmpty:
				case kscCellBool:
				case kscCellNumber:
				case kscCellDateTime:
				case kscCellText:
				{
					str >> cl;
					
					Value val;
					
					switch (chunk.type)
					{
						case kscCellBool:
						{
							bool b;
							str >> b;
							val = b;
							break;
						}
						case kscCellNumber:
						{
							double d;
							str >> d;
							val = d;
							break;
						}
						case kscCellDateTime:
						{
							time_t t;
							str >> t;
							val = t;
							break;
						}
						case kscCellText:
						{
							// do nothing yet...
						}
					}
	
					fContainer->NewCell(cl.loc, val, NULL);
					if (cl.style >= styleCount)
						/*THROW((errCorruptedFile))*/;
					else
						fContainer->SetCellStyleNr(cl.loc, styleList[cl.style]);
					
					progress.Step();
					break;
				}
				case kscString:
				{
					char s[256];
					Value val;
					stream.Read(s, std::min((int)chunk.size, 255));
					s[std::min((int)chunk.size, 255)] = 0;
					val = s;
					
					fContainer->SetValue(cl.loc, val);
					break;
				}
				case kscFormula:
				{
					CFormula form;
					try
					{
						if (!funcList) THROW((errCorruptedFile));
						form.Read(stream, funcList);
						Value v;
						form.Calculate(cl.loc, v, fContainer);
						fContainer->SetCellFormula(cl.loc, form.CopyString());
					}
					catch (CErr& e)
					{
						CATCHED;
						char s[32];
						cl.loc.GetName(s);
#if DEBUG
						printf("%s in formula of cell %s\n", (char *)e, s);
#endif
						if (warnForIncorrectFormula)
						{
							char m[256];
							sprintf(m, GetMessage(msgIncorrectFormula), s);
							MAlert *a = new MWarningAlert(m, GetMessage(msgOK),
								GetMessage(msgNoMoreWarnings));
							if (a->Go() == 2)
								warnForIncorrectFormula = false;
						}
					}
					form.Clear();
					break;
				}
				case kscChart:
					ReadChart(stream, chunk.size);
				case kscEnd:
					break;
				default:
					MStopAlert("File contains errors").Go();
					chunk.type = kscEnd;
					break;
			}
		}
		while (chunk.type != kscEnd);

// adjust the fields that couldn't be adjusted before
		if (fontCount && borderFont < fontCount)
			fBorderFontID = fontList[borderFont];
		
		if (colStyles && styleList)
		{
			for (int i = 0; i < colStyleCount; i++)
			{
				if (colStyles[i].style >= 0 && colStyles[i].style < styleCount)	
					colStyles[i].style = styleList[colStyles[i].style];
			}
			fContainer->GetColumnStyles().Read(colStyleCount, colStyles);
		}
	}
Пример #16
0
status_t
AGMSBayesianSpamFilter::ProcessMailMessage (
	BPositionIO** io_message,
	BEntry* io_entry,
	BMessage* io_headers,
	BPath* io_folder,
	const char* io_uid)
{
	ssize_t		 amountRead;
	attr_info	 attributeInfo;
	const char	*classificationString;
	off_t		 dataSize;
	BPositionIO	*dataStreamPntr = *io_message;
	status_t	 errorCode = B_OK;
	int32        headerLength;
	BString      headerString;
	BString		 newSubjectString;
	BNode        nodeForOutputFile;
	bool		 nodeForOutputFileInitialised = false;
	const char	*oldSubjectStringPntr;
	char         percentageString [30];
	BMessage	 replyMessage;
	BMessage	 scriptingMessage;
	team_id		 serverTeam;
	float		 spamRatio;
	char		*stringBuffer = NULL;
	char         tempChar;
	status_t     tempErrorCode;
	const char  *tokenizeModeStringPntr;

	// Set up a BNode to the final output file so that we can write custom
	// attributes to it.  Non-custom attributes are stored separately in
	// io_headers.

	if (io_entry != NULL && B_OK == nodeForOutputFile.SetTo (io_entry))
		nodeForOutputFileInitialised = true;

	// Get a connection to the spam database server.  Launch if needed, should
	// only need it once, unless another e-mail thread shuts down the server
	// inbetween messages.  This code used to be in InitCheck, but apparently
	// that isn't called.

	printf("Checking for Spam Server.\n");
	if (fLaunchAttemptCount == 0 || !fMessengerToServer.IsValid ()) {
		if (fLaunchAttemptCount > 3)
			goto ErrorExit; // Don't try to start the server too many times.
		fLaunchAttemptCount++;

		// Make sure the server is running.
		if (!be_roster->IsRunning (kServerSignature)) {
			errorCode = be_roster->Launch (kServerSignature);
			if (errorCode != B_OK) {
				BPath path;
				entry_ref ref;
				directory_which places[] = {B_COMMON_BIN_DIRECTORY,B_BEOS_BIN_DIRECTORY};
				for (int32 i = 0; i < 2; i++) {
					find_directory(places[i],&path);
					path.Append("spamdbm");
					if (!BEntry(path.Path()).Exists())
						continue;
					get_ref_for_path(path.Path(),&ref);
					if ((errorCode =  be_roster->Launch (&ref)) == B_OK)
						break;
				}
				if (errorCode != B_OK)
					goto ErrorExit;
			}
		}

		// Set up the messenger to the database server.
		serverTeam = be_roster->TeamFor (kServerSignature);
		if (serverTeam < 0)
			goto ErrorExit;
		fMessengerToServer =
			BMessenger (kServerSignature, serverTeam, &errorCode);
		if (!fMessengerToServer.IsValid ())
			goto ErrorExit;

		// Check if the server is running in headers only mode.  If so, we only
		// need to download the header rather than the entire message.
		scriptingMessage.MakeEmpty ();
		scriptingMessage.what = B_GET_PROPERTY;
		scriptingMessage.AddSpecifier ("TokenizeMode");
		replyMessage.MakeEmpty ();
		if ((errorCode = fMessengerToServer.SendMessage (&scriptingMessage,
			&replyMessage)) != B_OK)
			goto ErrorExit;
		if ((errorCode = replyMessage.FindInt32 ("error", &tempErrorCode))
			!= B_OK)
			goto ErrorExit;
		if ((errorCode = tempErrorCode) != B_OK)
			goto ErrorExit;
		if ((errorCode = replyMessage.FindString ("result",
			&tokenizeModeStringPntr)) != B_OK)
			goto ErrorExit;
		fHeaderOnly = (tokenizeModeStringPntr != NULL
			&& strcmp (tokenizeModeStringPntr, "JustHeader") == 0);
	}

	// See if the message has already been classified.  Happens for messages
	// which are partially downloaded when you have auto-training on.  Could
	// untrain the partial part before training on the complete message, but we
	// don't know how big it was, so instead just ignore the message.

	if (nodeForOutputFileInitialised) {
		if (nodeForOutputFile.GetAttrInfo ("MAIL:classification",
			&attributeInfo) == B_OK)
			return B_OK;
	}

	// Copy the message to a string so that we can pass it to the spam database
	// (the even messier alternative is a temporary file).  Do it in a fashion
	// which allows NUL bytes in the string.  This method of course limits the
	// message size to a few hundred megabytes.  If we're using header mode,
	// only read the header rather than the full message.

	if (fHeaderOnly) {
		// Read just the header, it ends with an empty CRLF line.
		dataStreamPntr->Seek (0, SEEK_SET);
		while ((errorCode = dataStreamPntr->Read (&tempChar, 1)) == 1) {
			headerString.Append (tempChar, 1);
			headerLength = headerString.Length();
			if (headerLength >= 4 && strcmp (headerString.String() +
				headerLength - 4, "\r\n\r\n") == 0)
				break;
		}
		if (errorCode < 0)
			goto ErrorExit;

		dataSize = headerString.Length();
		stringBuffer = new char [dataSize + 1];
		memcpy (stringBuffer, headerString.String(), dataSize);
		stringBuffer[dataSize] = 0;
	} else {
		// Read the whole file.  The seek to the end may take a while since
		// that triggers downloading of the entire message (and caching in a
		// slave file - see the MessageIO class).
		dataSize = dataStreamPntr->Seek (0, SEEK_END);
		if (dataSize <= 0)
			goto ErrorExit;

		try {
			stringBuffer = new char [dataSize + 1];
		} catch (...) {
			errorCode = ENOMEM;
			goto ErrorExit;
		}

		dataStreamPntr->Seek (0, SEEK_SET);
		amountRead = dataStreamPntr->Read (stringBuffer, dataSize);
		if (amountRead != dataSize)
			goto ErrorExit;
		stringBuffer[dataSize] = 0; // Add an end of string NUL, just in case.
	}

	// Send off a scripting command to the database server, asking it to
	// evaluate the string for spaminess.  Note that it can return ENOMSG
	// when there are no words (a good indicator of spam which is pure HTML
	// if you are using plain text only tokenization), so we could use that
	// as a spam marker too.  Code copied for the reevaluate stuff below.

	scriptingMessage.MakeEmpty ();
	scriptingMessage.what = B_SET_PROPERTY;
	scriptingMessage.AddSpecifier ("EvaluateString");
	errorCode = scriptingMessage.AddData ("data", B_STRING_TYPE,
		stringBuffer, dataSize + 1, false /* fixed size */);
	if (errorCode != B_OK)
		goto ErrorExit;
	replyMessage.MakeEmpty ();
	errorCode = fMessengerToServer.SendMessage (&scriptingMessage,
		&replyMessage);
	if (errorCode != B_OK
		|| replyMessage.FindInt32 ("error", &errorCode) != B_OK)
		goto ErrorExit; // Unable to read the return code.
	if (errorCode == ENOMSG && fNoWordsMeansSpam)
		spamRatio = fSpamCutoffRatio; // Yes, no words and that means spam.
	else if (errorCode != B_OK
		|| replyMessage.FindFloat ("result", &spamRatio) != B_OK)
		goto ErrorExit; // Classification failed in one of many ways.

	// If we are auto-training, feed back the message to the server as a
	// training example (don't train if it is uncertain).  Also redo the
	// evaluation after training.

	if (fAutoTraining) {
		if (spamRatio >= fSpamCutoffRatio || spamRatio < fGenuineCutoffRatio) {
			scriptingMessage.MakeEmpty ();
			scriptingMessage.what = B_SET_PROPERTY;
			scriptingMessage.AddSpecifier ((spamRatio >= fSpamCutoffRatio)
				? "SpamString" : "GenuineString");
			errorCode = scriptingMessage.AddData ("data", B_STRING_TYPE,
				stringBuffer, dataSize + 1, false /* fixed size */);
			if (errorCode != B_OK)
				goto ErrorExit;
			replyMessage.MakeEmpty ();
			errorCode = fMessengerToServer.SendMessage (&scriptingMessage,
				&replyMessage);
			if (errorCode != B_OK
				|| replyMessage.FindInt32 ("error", &errorCode) != B_OK)
				goto ErrorExit; // Unable to read the return code.
			if (errorCode != B_OK)
				goto ErrorExit; // Failed to set a good example.
		}

		// Note the kind of example made so that the user doesn't reclassify
		// the message twice (the spam server looks for this attribute).

		classificationString =
			(spamRatio >= fSpamCutoffRatio)
			? "Spam"
			: ((spamRatio < fGenuineCutoffRatio) ? "Genuine" : "Uncertain");
		if (nodeForOutputFileInitialised)
			nodeForOutputFile.WriteAttr ("MAIL:classification", B_STRING_TYPE,
				0 /* offset */, classificationString,
				strlen (classificationString) + 1);

		// Now that the database has changed due to training, recompute the
		// spam ratio.  Hopefully it will have become more extreme in the
		// correct direction (not switched from being spam to being genuine).
		// Code copied from above.

		scriptingMessage.MakeEmpty ();
		scriptingMessage.what = B_SET_PROPERTY;
		scriptingMessage.AddSpecifier ("EvaluateString");
		errorCode = scriptingMessage.AddData ("data", B_STRING_TYPE,
			stringBuffer, dataSize + 1, false /* fixed size */);
		if (errorCode != B_OK)
			goto ErrorExit;
		replyMessage.MakeEmpty ();
		errorCode = fMessengerToServer.SendMessage (&scriptingMessage,
			&replyMessage);
		if (errorCode != B_OK
			|| replyMessage.FindInt32 ("error", &errorCode) != B_OK)
			goto ErrorExit; // Unable to read the return code.
		if (errorCode == ENOMSG && fNoWordsMeansSpam)
			spamRatio = fSpamCutoffRatio; // Yes, no words and that means spam.
		else if (errorCode != B_OK
			|| replyMessage.FindFloat ("result", &spamRatio) != B_OK)
			goto ErrorExit; // Classification failed in one of many ways.
	}

	// Store the spam ratio in an attribute called MAIL:ratio_spam,
	// attached to the eventual output file.

	if (nodeForOutputFileInitialised)
		nodeForOutputFile.WriteAttr ("MAIL:ratio_spam",
			B_FLOAT_TYPE, 0 /* offset */, &spamRatio, sizeof (spamRatio));

	// Also add it to the subject, if requested.

	if (fAddSpamToSubject
		&& spamRatio >= fSpamCutoffRatio
		&& io_headers->FindString ("Subject", &oldSubjectStringPntr) == B_OK) {
		newSubjectString.SetTo ("[Spam ");
		sprintf (percentageString, "%05.2f", spamRatio * 100.0);
		newSubjectString << percentageString << "%] ";
		newSubjectString << oldSubjectStringPntr;
		io_headers->ReplaceString ("Subject", newSubjectString);
	}

	// Beep using different sounds for spam and genuine, as Jeremy Friesner
	// nudged me to get around to implementing.  And add uncertain to that, as
	// "BiPolar" suggested.  If the user doesn't want to hear the sound, they
	// can turn it off in the system sound preferences.

	if (spamRatio >= fSpamCutoffRatio) {
		system_beep (kAGMSBayesBeepSpamName);
	} else if (spamRatio < fGenuineCutoffRatio) {
		system_beep (kAGMSBayesBeepGenuineName);
	} else {
		system_beep (kAGMSBayesBeepUncertainName);
	}

	return B_OK;

ErrorExit:
	fprintf (stderr, "Error exit from "
		"SpamFilter::ProcessMailMessage, code maybe %ld (%s).\n",
		errorCode, strerror (errorCode));
	delete [] stringBuffer;
	return B_OK; // Not MD_ERROR so the message doesn't get left on server.
}