Beispiel #1
0
void DNS::add_record(const Resource &resource, const sections_type &sections) {
    // We need to check that the data provided is correct. Otherwise, the sections
    // will end up being inconsistent.
    IPv4Address v4_addr;
    IPv6Address v6_addr;
    std::string buffer = encode_domain_name(resource.dname()), encoded_data;
    // By default the data size is the length of the data field.
    uint32_t data_size = resource.data().size();
    if(resource.type() == A) {
        v4_addr = resource.data();
        data_size = 4;
    }
    else if(resource.type() == AAAA) {
        v6_addr = resource.data();
        data_size = IPv6Address::address_size;
    }
    else if(contains_dname(resource.type())) { 
        encoded_data = encode_domain_name(resource.data());
        data_size = encoded_data.size();
    }
    uint32_t offset = buffer.size() + sizeof(uint16_t) * 3 + sizeof(uint32_t) + data_size, 
            threshold = sections.empty() ? records_data.size() : *sections.front().first;
    // Skip the preference field
    if(resource.type() == MX) {
        offset += sizeof(uint16_t);
    }
    for(size_t i = 0; i < sections.size(); ++i) {
        update_records(*sections[i].first, sections[i].second, threshold, offset);
    }
    
    records_data.insert(
        records_data.begin() + threshold,
        offset,
        0
    );
    uint8_t *ptr = std::copy(
        buffer.begin(),
        buffer.end(),
        &records_data[threshold]
    );

    uint16_t uint16_t_buffer;
    uint32_t uint32_t_buffer;

    uint16_t_buffer = Endian::host_to_be(resource.type());
    std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
    ptr += sizeof(uint16_t);
    uint16_t_buffer = Endian::host_to_be(resource.query_class());
    std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
    ptr += sizeof(uint16_t);
    uint32_t_buffer = Endian::host_to_be(resource.ttl());
    std::memcpy(ptr, &uint32_t_buffer, sizeof(uint32_t));
    ptr += sizeof(uint32_t);
    uint16_t_buffer = Endian::host_to_be<uint16_t>(
        data_size + (resource.type() == MX ? 2 : 0)
    );
    std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
    ptr += sizeof(uint16_t);
    if(resource.type() == MX) {
        ptr += sizeof(uint16_t);
    }
    if(resource.type() == A) {
        uint32_t ip_int = v4_addr;
        std::memcpy(ptr, &ip_int, sizeof(ip_int));
    }
    else if(resource.type() == AAAA) {
        std::copy(v6_addr.begin(), v6_addr.end(), ptr);
    }
    else if(!encoded_data.empty()) {
        std::copy(encoded_data.begin(), encoded_data.end(), ptr);
    }
    else {
        std::copy(resource.data().begin(), resource.data().end(), ptr);
    }
}
Beispiel #2
0
int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
#ifndef ENABLE_SCI32
	// SCI32 support is not built in. Check if this is a SCI32 game
	// and if it is abort here.
	if (_volVersion >= kResVersionSci2)
		return SCI_ERROR_RESMAP_NOT_FOUND;
#endif

	uint32 offset = 0;
	const ResourceId mapResId(kResourceTypeMap, map->_mapNumber);
	Resource *mapRes = _resMap.getVal(mapResId, nullptr);

	if (!mapRes) {
		warning("Failed to open %s", mapResId.toString().c_str());
		return SCI_ERROR_RESMAP_NOT_FOUND;
	}

	// Here, we allocate audio maps ourselves instead of using findResource to
	// do this for us. This is in order to prevent the map resources from
	// getting into the LRU cache. These resources must be read and then
	// deallocated in games with multi-disc audio in order to read the audio
	// maps from every CD, and LRU eviction freaks out if an unallocated
	// resource ends up in the LRU list. It is also not necessary for these
	// resources to be cached in the LRU at all, since they are only used upon
	// game startup to populate _resMap.
	assert(mapRes->_status == kResStatusNoMalloc);
	loadResource(mapRes);

	if (!mapRes->data()) {
		warning("Failed to read data for %s", mapResId.toString().c_str());
		return SCI_ERROR_RESMAP_NOT_FOUND;
	}

	ResourceSource *src = findVolume(map, map->_volumeNumber);

	if (!src) {
		warning("Failed to find volume for %s", mapResId.toString().c_str());
		return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
	}

	Common::SeekableReadStream *fileStream = getVolumeFile(src);

	if (!fileStream) {
		warning("Failed to open file stream for %s", src->getLocationName().c_str());
		return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
	}

	const uint32 srcSize = fileStream->size();
	disposeVolumeFileStream(fileStream, src);

	SciSpan<const byte>::const_iterator ptr = mapRes->cbegin();

	uint32 entrySize = 0;
	if (_volVersion >= kResVersionSci2) {
		// The heuristic size detection is incompatible with at least Torin RU,
		// which is fine because it is not needed for SCI32
		entrySize = 11;
	} else {
		// Heuristic to detect entry size
		for (int i = mapRes->size() - 1; i >= 0; --i) {
			if (ptr[i] == 0xff)
				entrySize++;
			else
				break;
		}
	}

	if (map->_mapNumber == 65535) {
		while (ptr != mapRes->cend()) {
			uint16 n = ptr.getUint16LE();
			ptr += 2;

			if (n == 0xffff)
				break;

			if (entrySize == 6) {
				offset = ptr.getUint32LE();
				ptr += 4;
			} else {
				offset += ptr.getUint24LE();
				ptr += 3;
			}

			addResource(ResourceId(kResourceTypeAudio, n), src, offset, 0, map->getLocationName());
		}
	} else if (map->_mapNumber == 0 && entrySize == 10 && ptr[3] == 0) {
		// QFG3 demo format
		// ptr[3] would be 'seq' in the normal format and cannot possibly be 0
		while (ptr != mapRes->cend()) {
			uint16 n = ptr.getUint16BE();
			ptr += 2;

			if (n == 0xffff)
				break;

			offset = ptr.getUint32LE();
			ptr += 4;
			uint32 size = ptr.getUint32LE();
			ptr += 4;

			addResource(ResourceId(kResourceTypeAudio, n), src, offset, size, map->getLocationName());
		}
	} else if (map->_mapNumber == 0 && entrySize == 8 && (ptr + 2).getUint16LE() == 0xffff) {
		// LB2 Floppy/Mother Goose SCI1.1 format
		Common::SeekableReadStream *stream = getVolumeFile(src);

		while (ptr != mapRes->cend()) {
			uint16 n = ptr.getUint16LE();
			ptr += 4;

			if (n == 0xffff)
				break;

			const ResourceId audioResId(kResourceTypeAudio, n);

			offset = ptr.getUint32LE();
			ptr += 4;

			uint32 size;
			if (src->getAudioCompressionType() == 0) {
				// The size is not stored in the map and the entries have no order.
				// We need to dig into the audio resource in the volume to get the size.
				stream->seek(offset + 1);
				byte headerSize = stream->readByte();
				if (headerSize != 11 && headerSize != 12) {
					error("Unexpected header size in %s: should be 11 or 12, got %d", audioResId.toString().c_str(), headerSize);
				}

				stream->skip(7);
				size = stream->readUint32LE() + headerSize + 2;
			} else {
				size = 0;
			}
			addResource(audioResId, src, offset, size, map->getLocationName());
		}

		disposeVolumeFileStream(stream, src);
	} else {
		// EQ1CD & SQ4CD are "early" games; KQ6CD and all SCI32 are "late" games
		const bool isEarly = (entrySize != 11);

		if (!isEarly) {
			offset = ptr.getUint32LE();
			ptr += 4;
		}

		enum {
			kRaveFlag = 0x40,
			kSyncFlag = 0x80,
			kEndOfMapFlag = 0xFF
		};

		while (ptr != mapRes->cend()) {
			uint32 n = ptr.getUint32BE();
			uint32 syncSize = 0;
			ptr += 4;

			// Checking the entire tuple breaks Torin RU and is not how SSCI
			// works
			if ((n & kEndOfMapFlag) == kEndOfMapFlag) {
				const uint32 bytesLeft = mapRes->cend() - ptr;
				if (bytesLeft >= entrySize) {
					warning("End of %s reached, but %u entries remain", mapResId.toString().c_str(), bytesLeft / entrySize);
				}
				break;
			}

			// GK1CD has a message whose audio36 resource has the wrong tuple and never plays.
			//  The message tuple is 420 2 32 0 1 but the audio36 tuple is 420 2 32 3 1. bug #10819
			if (g_sci->getGameId() == GID_GK1 && g_sci->isCD() &&
				map->_mapNumber == 420 && n == 0x02200301) {
				n = 0x02200001;
			}

			// QFG4CD has a message whose audio36 resource has the wrong tuple and never plays.
			//  The message tuple is 510 23 1 0 1 but the audio36 tuple is 510 199 1 0 1. bug #10848
			if (g_sci->getGameId() == GID_QFG4 && g_sci->isCD() &&
				map->_mapNumber == 510 && n == 0xc7010001) {
				n = 0x17010001;
			}

			// QFG4CD has an orphaned audio36 resource that additionally has the wrong tuple.
			//  The audio36 tuple is 520 2 59 0 3. The message would be 520 2 59 0 2. bug #10849
			//  We restore the missing message in message.cpp.
			if (g_sci->getGameId() == GID_QFG4 && g_sci->isCD() &&
				map->_mapNumber == 520 && n == 0x023b0003) {
				n = 0x023b0002;
			}

			if (isEarly) {
				offset = ptr.getUint32LE();
				ptr += 4;
			} else {
				offset += ptr.getUint24LE();
				ptr += 3;
			}

			if (isEarly || (n & kSyncFlag)) {
				syncSize = ptr.getUint16LE();
				ptr += 2;

				// FIXME: The sync36 resource seems to be two bytes too big in KQ6CD
				// (bytes taken from the RAVE resource right after it)
				if (syncSize > 0) {
					// TODO: Add a mechanism to handle cases with missing resources like the ones below
					//
					// LB2CD is missing the sync resource for message 1885 1 6 30 2 but it's a duplicate
					//  of 1885 1 6 16 2 which does have a sync resource so use that for both. bug #9956
					if (g_sci->getGameId() == GID_LAURABOW2 && map->_mapNumber == 1885 && n == 0x01061002) {
						addResource(ResourceId(kResourceTypeSync36, map->_mapNumber, 0x01061e02), src, offset, syncSize, map->getLocationName());
					}

					addResource(ResourceId(kResourceTypeSync36, map->_mapNumber, n & 0xffffff3f), src, offset, syncSize, map->getLocationName());
				}
			}

			// Checking for this 0x40 flag breaks at least Laura Bow 2 CD 1.1
			// map 448
			if (g_sci->getGameId() == GID_KQ6 && (n & kRaveFlag)) {
				// This seems to define the size of raw lipsync data (at least
				// in KQ6 CD Windows).
				uint32 kq6HiresSyncSize = ptr.getUint16LE();
				ptr += 2;

				if (kq6HiresSyncSize > 0) {
					// Rave resources do not have separate entries in the audio
					// map (their data was just appended to sync resources), so
					// we have to use the sync resource offset first and then
					// adjust the offset & size later, otherwise offset
					// validation will fail for compressed volumes (since the
					// relocation table in a compressed volume only contains
					// offsets that existed in the original audio map)
					Resource *res = addResource(ResourceId(kResourceTypeRave, map->_mapNumber, n & 0xffffff3f), src, offset, syncSize + kq6HiresSyncSize, map->getLocationName());
					res->_fileOffset += syncSize;
					res->_size -= syncSize;
					syncSize += kq6HiresSyncSize;
				}
			}

			const ResourceId id(kResourceTypeAudio36, map->_mapNumber, n & 0xffffff3f);

			// Map 405 on CD 1 of the US release of PQ:SWAT 1.000 is broken
			// and points to garbage in the RESOURCE.AUD. The affected audio36
			// assets seem to be able to load successfully from one of the later
			// CDs, so just ignore the map on this disc
			if (g_sci->getGameId() == GID_PQSWAT &&
				g_sci->getLanguage() == Common::EN_ANY &&
				map->_volumeNumber == 1 &&
				map->_mapNumber == 405) {
				continue;
			}

			if (g_sci->getGameId() == GID_GK2) {
				// At least version 1.00 of the US release, and the German
				// release, of GK2 have multiple invalid audio36 map entries on
				// CD 6
				if (map->_volumeNumber == 6 && offset + syncSize >= srcSize) {
					bool skip;
					switch (g_sci->getLanguage()) {
					case Common::EN_ANY:
						skip = (map->_mapNumber == 22 || map->_mapNumber == 160);
						break;
					case Common::DE_DEU:
						skip = (map->_mapNumber == 22);
						break;
					default:
						skip = false;
					}

					if (skip) {
						continue;
					}
				}

				// Map 2020 on CD 1 of the German release of GK2 is invalid.
				// This content does not appear to ever be used by the game (it
				// does not even exist in the US release), and there is a
				// correct copy of it on CD 6, so just ignore the bad copy on
				// CD 1
				if (g_sci->getLanguage() == Common::DE_DEU &&
					map->_volumeNumber == 1 &&
					map->_mapNumber == 2020) {
					continue;
				}
			}

			// Map 800 and 4176 contain content that was cut from the game. The
			// French version of the game includes map files from the US
			// release, but the audio resources are French so the maps don't
			// match. Since the content was never used, just ignore these maps
			// everywhere
			if (g_sci->getGameId() == GID_PHANTASMAGORIA2 &&
				(map->_mapNumber == 800 || map->_mapNumber == 4176)) {
				continue;
			}

			addResource(id, src, offset + syncSize, 0, map->getLocationName());
		}
	}

	mapRes->unalloc();

	return 0;
}
Beispiel #3
0
void Screen::loadPalette(int fileNum, int subfile) {
	Resource *res = _vm->_files->loadFile(fileNum, subfile);
	byte *palette = res->data();
	Common::copy(palette, palette + (_numColors * 3), &_rawPalette[_startColor * 3]);
	delete res;
}